github.com/openshift/moby-moby@v1.13.2-0.20170601211448-f5ec1e2936dc/daemon/logs.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "io" 6 "strconv" 7 "time" 8 9 "golang.org/x/net/context" 10 11 "github.com/Sirupsen/logrus" 12 "github.com/docker/docker/api/types/backend" 13 containertypes "github.com/docker/docker/api/types/container" 14 timetypes "github.com/docker/docker/api/types/time" 15 "github.com/docker/docker/container" 16 "github.com/docker/docker/daemon/logger" 17 "github.com/docker/docker/pkg/ioutils" 18 "github.com/docker/docker/pkg/stdcopy" 19 ) 20 21 // ContainerLogs hooks up a container's stdout and stderr streams 22 // configured with the given struct. 23 func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, config *backend.ContainerLogsConfig, started chan struct{}) error { 24 container, err := daemon.GetContainer(containerName) 25 if err != nil { 26 return err 27 } 28 29 if !(config.ShowStdout || config.ShowStderr) { 30 return fmt.Errorf("You must choose at least one stream") 31 } 32 33 cLog, err := daemon.getLogger(container) 34 if err != nil { 35 return err 36 } 37 logReader, ok := cLog.(logger.LogReader) 38 if !ok { 39 return logger.ErrReadLogsNotSupported 40 } 41 42 follow := config.Follow && container.IsRunning() 43 tailLines, err := strconv.Atoi(config.Tail) 44 if err != nil { 45 tailLines = -1 46 } 47 48 logrus.Debug("logs: begin stream") 49 50 var since time.Time 51 if config.Since != "" { 52 s, n, err := timetypes.ParseTimestamps(config.Since, 0) 53 if err != nil { 54 return err 55 } 56 since = time.Unix(s, n) 57 } 58 readConfig := logger.ReadConfig{ 59 Since: since, 60 Tail: tailLines, 61 Follow: follow, 62 } 63 logs := logReader.ReadLogs(readConfig) 64 // Close logWatcher on exit 65 defer func() { 66 logs.Close() 67 if cLog != container.LogDriver { 68 // Since the logger isn't cached in the container, which 69 // occurs if it is running, it must get explicitly closed 70 // here to avoid leaking it and any file handles it has. 71 if err := cLog.Close(); err != nil { 72 logrus.Errorf("Error closing logger: %v", err) 73 } 74 } 75 }() 76 77 wf := ioutils.NewWriteFlusher(config.OutStream) 78 defer wf.Close() 79 close(started) 80 wf.Flush() 81 82 var outStream io.Writer 83 outStream = wf 84 errStream := outStream 85 if !container.Config.Tty { 86 errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr) 87 outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout) 88 } 89 90 for { 91 select { 92 case err := <-logs.Err: 93 logrus.Errorf("Error streaming logs: %v", err) 94 return nil 95 case <-ctx.Done(): 96 logrus.Debugf("logs: end stream, ctx is done: %v", ctx.Err()) 97 return nil 98 case msg, ok := <-logs.Msg: 99 if !ok { 100 logrus.Debug("logs: end stream") 101 return nil 102 } 103 logLine := msg.Line 104 if config.Details { 105 logLine = append([]byte(msg.Attrs.String()+" "), logLine...) 106 } 107 if config.Timestamps { 108 logLine = append([]byte(msg.Timestamp.Format(logger.TimeFormat)+" "), logLine...) 109 } 110 if msg.Source == "stdout" && config.ShowStdout { 111 outStream.Write(logLine) 112 } 113 if msg.Source == "stderr" && config.ShowStderr { 114 errStream.Write(logLine) 115 } 116 } 117 } 118 } 119 120 func (daemon *Daemon) getLogger(container *container.Container) (logger.Logger, error) { 121 if container.LogDriver != nil && container.IsRunning() { 122 return container.LogDriver, nil 123 } 124 return container.StartLogger(container.HostConfig.LogConfig) 125 } 126 127 // mergeLogConfig merges the daemon log config to the container's log config if the container's log driver is not specified. 128 func (daemon *Daemon) mergeAndVerifyLogConfig(cfg *containertypes.LogConfig) error { 129 if cfg.Type == "" { 130 cfg.Type = daemon.defaultLogConfig.Type 131 } 132 133 if cfg.Config == nil { 134 cfg.Config = make(map[string]string) 135 } 136 137 if cfg.Type == daemon.defaultLogConfig.Type { 138 for k, v := range daemon.defaultLogConfig.Config { 139 if _, ok := cfg.Config[k]; !ok { 140 cfg.Config[k] = v 141 } 142 } 143 } 144 145 return logger.ValidateLogOpts(cfg.Type, cfg.Config) 146 }