github.com/AbhinandanKurakure/podman/v3@v3.4.10/libpod/container_log.go (about) 1 package libpod 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "time" 8 9 "github.com/containers/podman/v3/libpod/define" 10 "github.com/containers/podman/v3/libpod/events" 11 "github.com/containers/podman/v3/libpod/logs" 12 "github.com/hpcloud/tail/watch" 13 "github.com/pkg/errors" 14 "github.com/sirupsen/logrus" 15 ) 16 17 // logDrivers stores the currently available log drivers, do not modify 18 var logDrivers []string 19 20 func init() { 21 logDrivers = append(logDrivers, define.KubernetesLogging, define.NoLogging) 22 } 23 24 // Log is a runtime function that can read one or more container logs. 25 func (r *Runtime) Log(ctx context.Context, containers []*Container, options *logs.LogOptions, logChannel chan *logs.LogLine) error { 26 for _, ctr := range containers { 27 if err := ctr.ReadLog(ctx, options, logChannel); err != nil { 28 return err 29 } 30 } 31 return nil 32 } 33 34 // ReadLog reads a containers log based on the input options and returns log lines over a channel. 35 func (c *Container) ReadLog(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine) error { 36 switch c.LogDriver() { 37 case define.NoLogging: 38 return errors.Wrapf(define.ErrNoLogs, "this container is using the 'none' log driver, cannot read logs") 39 case define.JournaldLogging: 40 return c.readFromJournal(ctx, options, logChannel) 41 case define.JSONLogging: 42 // TODO provide a separate implementation of this when Conmon 43 // has support. 44 fallthrough 45 case define.KubernetesLogging, "": 46 return c.readFromLogFile(ctx, options, logChannel) 47 default: 48 return errors.Wrapf(define.ErrInternal, "unrecognized log driver %q, cannot read logs", c.LogDriver()) 49 } 50 } 51 52 func (c *Container) readFromLogFile(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine) error { 53 t, tailLog, err := logs.GetLogFile(c.LogPath(), options) 54 if err != nil { 55 // If the log file does not exist, this is not fatal. 56 if os.IsNotExist(errors.Cause(err)) { 57 return nil 58 } 59 return errors.Wrapf(err, "unable to read log file %s for %s ", c.ID(), c.LogPath()) 60 } 61 options.WaitGroup.Add(1) 62 if len(tailLog) > 0 { 63 for _, nll := range tailLog { 64 nll.CID = c.ID() 65 nll.CName = c.Name() 66 if nll.Since(options.Since) && nll.Until(options.Until) { 67 logChannel <- nll 68 } 69 } 70 } 71 72 go func() { 73 defer options.WaitGroup.Done() 74 75 var partial string 76 for line := range t.Lines { 77 select { 78 case <-ctx.Done(): 79 // the consumer has cancelled 80 return 81 default: 82 // fallthrough 83 } 84 nll, err := logs.NewLogLine(line.Text) 85 if err != nil { 86 logrus.Errorf("Error getting new log line: %v", err) 87 continue 88 } 89 if nll.Partial() { 90 partial += nll.Msg 91 continue 92 } else if !nll.Partial() && len(partial) > 0 { 93 nll.Msg = partial + nll.Msg 94 partial = "" 95 } 96 nll.CID = c.ID() 97 nll.CName = c.Name() 98 if nll.Since(options.Since) && nll.Until(options.Until) { 99 logChannel <- nll 100 } 101 } 102 }() 103 // Check if container is still running or paused 104 if options.Follow { 105 // If the container isn't running or if we encountered an error 106 // getting its state, instruct the logger to read the file 107 // until EOF. 108 state, err := c.State() 109 if err != nil || state != define.ContainerStateRunning { 110 if err != nil && errors.Cause(err) != define.ErrNoSuchCtr { 111 logrus.Errorf("Error getting container state: %v", err) 112 } 113 go func() { 114 // Make sure to wait at least for the poll duration 115 // before stopping the file logger (see #10675). 116 time.Sleep(watch.POLL_DURATION) 117 tailError := t.StopAtEOF() 118 if tailError != nil && tailError.Error() != "tail: stop at eof" { 119 logrus.Errorf("Error stopping logger: %v", tailError) 120 } 121 }() 122 return nil 123 } 124 125 // The container is running, so we need to wait until the container exited 126 go func() { 127 eventChannel := make(chan *events.Event) 128 eventOptions := events.ReadOptions{ 129 EventChannel: eventChannel, 130 Filters: []string{"event=died", "container=" + c.ID()}, 131 Stream: true, 132 } 133 go func() { 134 if err := c.runtime.Events(ctx, eventOptions); err != nil { 135 logrus.Errorf("Error waiting for container to exit: %v", err) 136 } 137 }() 138 // Now wait for the died event and signal to finish 139 // reading the log until EOF. 140 <-eventChannel 141 // Make sure to wait at least for the poll duration 142 // before stopping the file logger (see #10675). 143 time.Sleep(watch.POLL_DURATION) 144 tailError := t.StopAtEOF() 145 if tailError != nil && fmt.Sprintf("%v", tailError) != "tail: stop at eof" { 146 logrus.Errorf("Error stopping logger: %v", tailError) 147 } 148 }() 149 } 150 return nil 151 }