github.com/clintkitson/docker@v1.9.1/daemon/logs.go (about) 1 package daemon 2 3 import ( 4 "io" 5 "strconv" 6 "time" 7 8 "github.com/Sirupsen/logrus" 9 "github.com/docker/docker/daemon/logger" 10 derr "github.com/docker/docker/errors" 11 "github.com/docker/docker/pkg/stdcopy" 12 ) 13 14 // ContainerLogsConfig holds configs for logging operations. Exists 15 // for users of the daemon to to pass it a logging configuration. 16 type ContainerLogsConfig struct { 17 // if true stream log output 18 Follow bool 19 // if true include timestamps for each line of log output 20 Timestamps bool 21 // return that many lines of log output from the end 22 Tail string 23 // filter logs by returning on those entries after this time 24 Since time.Time 25 // whether or not to show stdout and stderr as well as log entries. 26 UseStdout, UseStderr bool 27 OutStream io.Writer 28 Stop <-chan bool 29 } 30 31 // ContainerLogs hooks up a container's stdout and stderr streams 32 // configured with the given struct. 33 func (daemon *Daemon) ContainerLogs(containerName string, config *ContainerLogsConfig) error { 34 container, err := daemon.Get(containerName) 35 if err != nil { 36 return derr.ErrorCodeNoSuchContainer.WithArgs(containerName) 37 } 38 39 if !(config.UseStdout || config.UseStderr) { 40 return derr.ErrorCodeNeedStream 41 } 42 43 outStream := config.OutStream 44 errStream := outStream 45 if !container.Config.Tty { 46 errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) 47 outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) 48 } 49 config.OutStream = outStream 50 51 cLog, err := container.getLogger() 52 if err != nil { 53 return err 54 } 55 logReader, ok := cLog.(logger.LogReader) 56 if !ok { 57 return logger.ErrReadLogsNotSupported 58 } 59 60 follow := config.Follow && container.IsRunning() 61 tailLines, err := strconv.Atoi(config.Tail) 62 if err != nil { 63 tailLines = -1 64 } 65 66 logrus.Debug("logs: begin stream") 67 readConfig := logger.ReadConfig{ 68 Since: config.Since, 69 Tail: tailLines, 70 Follow: follow, 71 } 72 logs := logReader.ReadLogs(readConfig) 73 74 for { 75 select { 76 case err := <-logs.Err: 77 logrus.Errorf("Error streaming logs: %v", err) 78 return nil 79 case <-config.Stop: 80 logs.Close() 81 return nil 82 case msg, ok := <-logs.Msg: 83 if !ok { 84 logrus.Debugf("logs: end stream") 85 return nil 86 } 87 logLine := msg.Line 88 if config.Timestamps { 89 logLine = append([]byte(msg.Timestamp.Format(logger.TimeFormat)+" "), logLine...) 90 } 91 if msg.Source == "stdout" && config.UseStdout { 92 outStream.Write(logLine) 93 } 94 if msg.Source == "stderr" && config.UseStderr { 95 errStream.Write(logLine) 96 } 97 } 98 } 99 }