forked from hyperhq/hyperd
/
logs.go
137 lines (120 loc) · 2.63 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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package daemon
import (
"fmt"
"strconv"
"time"
"github.com/docker/docker/daemon/logger"
"github.com/golang/glog"
"github.com/hyperhq/hyper/engine"
"github.com/hyperhq/runv/hypervisor/types"
)
type logsCmdConfig struct {
container string
follow bool
timestamps bool
tail string
since time.Time
stdout bool
stderr bool
}
func readLogsConfig(args []string) (*logsCmdConfig, error) {
if len(args) < 1 {
return nil, fmt.Errorf("container id or name must be provided")
}
cfg := &logsCmdConfig{
container: args[0],
}
if len(args) > 1 {
cfg.tail = args[1]
}
if len(args) > 2 {
s, err := strconv.ParseInt(args[2], 10, 64)
if err == nil {
cfg.since = time.Unix(s, 0)
}
}
for _, s := range args[3:] {
switch s {
case "follow":
cfg.follow = true
case "timestamp":
cfg.timestamps = true
case "stdout":
cfg.stdout = true
case "stderr":
cfg.stderr = true
}
}
return cfg, nil
}
func (daemon *Daemon) CmdLogs(job *engine.Job) (err error) {
var (
config *logsCmdConfig
pod *Pod
cidx int
tailLines int
)
config, err = readLogsConfig(job.Args)
if err != nil {
glog.Warningf("log args parsing error: %v", err)
return
}
if !(config.stdout || config.stderr) {
return fmt.Errorf("You must choose at least one stream")
}
outStream := job.Stdout
errStream := outStream
pod, cidx, err = daemon.GetPodByContainerIdOrName(config.container)
if err != nil {
return err
}
err = pod.getLogger(daemon)
if err != nil {
return err
}
logReader, ok := pod.status.Containers[cidx].Logs.Driver.(logger.LogReader)
if !ok {
return fmt.Errorf("logger not suppert read")
}
follow := config.follow && (pod.status.Status == types.S_POD_RUNNING)
tailLines, err = strconv.Atoi(config.tail)
if err != nil {
tailLines = -1
}
readConfig := logger.ReadConfig{
Since: config.since,
Tail: tailLines,
Follow: follow,
}
logs := logReader.ReadLogs(readConfig)
for {
select {
case e := <-logs.Err:
glog.Errorf("Error streaming logs: %v", e)
return nil
case msg, ok := <-logs.Msg:
if !ok {
glog.V(1).Info("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.stdout {
glog.V(2).Info("print stdout log: ", logLine)
_, err := outStream.Write(logLine)
if err != nil {
return nil
}
}
if msg.Source == "stderr" && config.stderr {
glog.V(2).Info("print stderr log: ", logLine)
_, err := errStream.Write(logLine)
if err != nil {
return nil
}
}
}
}
}