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