func (instance *Instance) readFromTail(t *tail.Tail, pub *zmqpubsub.Publisher, name string, stopCh chan bool, filename string, tracker storage.Tracker) { var err error FORLOOP: for { select { case line, ok := <-t.Lines: if !ok { err = t.Wait() break FORLOOP } currentOffset, err := t.Tell() if err != nil { log.Error(err.Error()) } tracker.Update(instance.getShortDockerId(), filename, currentOffset) instance.publishLine(pub, name, line) case <-stopCh: err = t.Stop() break FORLOOP } } if err != nil { log.Warn(err) instance.SendTimelineEvent("WARN -- Error tailing file (%s); %s", name, err) } log.Infof("Completed tailing %v log for %v", name, instance.Identifier()) }
// Tail begins tailing the files for this instance. func (instance *Instance) Tail(tracker storage.Tracker) { log.Infof("Tailing %v logs for %v -- %+v", instance.Type, instance.Identifier(), instance) stopCh := make(chan bool) instance.pubch = pubchannel.New("event.timeline", stopCh) logfiles := instance.getLogFiles() log.Infof("Determined log files: %+v", logfiles) shortDockerId := instance.getShortDockerId() tracker.RegisterInstance(shortDockerId) for name, filename := range logfiles { // call tailStream for standard docker logs and tailFile for user custom logs if instance.DockerStreams && (name == STDOUT || name == STDERR) { go instance.tailStream(name, filename, stopCh, tracker) } else { go instance.tailFile(name, filename, stopCh, tracker) } } go func() { docker.DockerListener.BlockUntilContainerStops(instance.DockerId) log.Infof("Container for %v exited", instance.Identifier()) close(stopCh) tracker.Remove(shortDockerId) }() }
func (l *dockerListener) TrackerCleanUp(tracker storage.Tracker) { all_containers := docker_events.GetLiveDockerContainers(RETRY) if len(all_containers) > 0 { tracker.CleanUp(all_containers) } }
func (instance *Instance) tailFile(name, filename string, stopCh chan bool, tracker storage.Tracker) { var err error var location *tail.SeekInfo var limit int64 var shouldInitialize bool pub := logyard.Broker.NewPublisherMust() defer pub.Stop() if tracker.IsChildNodeInitialized(instance.getShortDockerId(), filename) { offset := tracker.GetFileCachedOffset(instance.getShortDockerId(), filename) location = &tail.SeekInfo{offset, os.SEEK_SET} } else { limit, err = instance.getReadLimit(pub, name, filename) location = &tail.SeekInfo{-limit, os.SEEK_END} shouldInitialize = true } if err != nil { log.Warn(err) instance.SendTimelineEvent("WARN -- %v", err) return } rateLimiter := GetConfig().GetLeakyBucket() t, err := tail.TailFile(filename, tail.Config{ MaxLineSize: GetConfig().MaxRecordSize, MustExist: true, Follow: true, Location: location, ReOpen: false, Poll: false, RateLimiter: rateLimiter}) // IMPORTANT: this registration happens everytime app restarts if shouldInitialize { tracker.InitializeChildNode(instance.getShortDockerId(), filename, INITIAL_OFFSET) } if err != nil { log.Warnf("Cannot tail file (%s); %s", filename, err) instance.SendTimelineEvent("ERROR -- Cannot tail file (%s); %s", name, err) return } instance.readFromTail(t, pub, name, stopCh, filename, tracker) }