github.com/rentongzhang/docker@v1.8.2-rc1/daemon/logs.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "io" 6 "strconv" 7 "time" 8 9 "github.com/Sirupsen/logrus" 10 "github.com/docker/docker/daemon/logger" 11 "github.com/docker/docker/pkg/stdcopy" 12 ) 13 14 type ContainerLogsConfig struct { 15 Follow, Timestamps bool 16 Tail string 17 Since time.Time 18 UseStdout, UseStderr bool 19 OutStream io.Writer 20 Stop <-chan bool 21 } 22 23 func (daemon *Daemon) ContainerLogs(container *Container, config *ContainerLogsConfig) error { 24 if !(config.UseStdout || config.UseStderr) { 25 return fmt.Errorf("You must choose at least one stream") 26 } 27 28 outStream := config.OutStream 29 errStream := outStream 30 if !container.Config.Tty { 31 errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) 32 outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) 33 } 34 35 cLog, err := container.getLogger() 36 if err != nil { 37 return err 38 } 39 logReader, ok := cLog.(logger.LogReader) 40 if !ok { 41 return logger.ErrReadLogsNotSupported 42 } 43 44 follow := config.Follow && container.IsRunning() 45 tailLines, err := strconv.Atoi(config.Tail) 46 if err != nil { 47 tailLines = -1 48 } 49 50 logrus.Debug("logs: begin stream") 51 readConfig := logger.ReadConfig{ 52 Since: config.Since, 53 Tail: tailLines, 54 Follow: follow, 55 } 56 logs := logReader.ReadLogs(readConfig) 57 58 for { 59 select { 60 case err := <-logs.Err: 61 logrus.Errorf("Error streaming logs: %v", err) 62 return nil 63 case <-config.Stop: 64 logs.Close() 65 return nil 66 case msg, ok := <-logs.Msg: 67 if !ok { 68 logrus.Debugf("logs: end stream") 69 return nil 70 } 71 logLine := msg.Line 72 if config.Timestamps { 73 logLine = append([]byte(msg.Timestamp.Format(logger.TimeFormat)+" "), logLine...) 74 } 75 if msg.Source == "stdout" && config.UseStdout { 76 outStream.Write(logLine) 77 } 78 if msg.Source == "stderr" && config.UseStderr { 79 errStream.Write(logLine) 80 } 81 } 82 } 83 }