forked from ipfs/kubo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
log.go
140 lines (118 loc) · 3.33 KB
/
log.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
138
139
140
package commands
import (
"fmt"
"io"
"strings"
cmds "github.com/jbenet/go-ipfs/commands"
u "github.com/jbenet/go-ipfs/util"
tail "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/ActiveState/tail"
)
// Golang os.Args overrides * and replaces the character argument with
// an array which includes every file in the user's CWD. As a
// workaround, we use 'all' instead. The util library still uses * so
// we convert it at this step.
var logAllKeyword = "all"
var LogCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Interact with the daemon log output",
ShortDescription: `
'ipfs log' contains utility commands to affect or read the logging
output of a running daemon.
`,
},
Subcommands: map[string]*cmds.Command{
"level": logLevelCmd,
"tail": logTailCmd,
},
}
var logLevelCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Change the logging level",
ShortDescription: `
'ipfs log level' is a utility command used to change the logging
output of a running daemon.
`,
},
Arguments: []cmds.Argument{
// TODO use a different keyword for 'all' because all can theoretically
// clash with a subsystem name
cmds.StringArg("subsystem", true, false, fmt.Sprintf("the subsystem logging identifier. Use '%s' for all subsystems.", logAllKeyword)),
cmds.StringArg("level", true, false, "one of: debug, info, notice, warning, error, critical"),
},
Run: func(req cmds.Request, res cmds.Response) {
args := req.Arguments()
subsystem, level := args[0], args[1]
if subsystem == logAllKeyword {
subsystem = "*"
}
if err := u.SetLogLevel(subsystem, level); err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
s := fmt.Sprintf("Changed log level of '%s' to '%s'", subsystem, level)
log.Info(s)
res.SetOutput(&MessageOutput{s})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: MessageTextMarshaler,
},
Type: MessageOutput{},
}
var logTailCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Read the logs",
ShortDescription: `
'ipfs log tail' is a utility command used to read log output as it is written.
`,
},
Run: func(req cmds.Request, res cmds.Response) {
path := fmt.Sprintf("%s/logs/events.log", req.Context().ConfigRoot)
outChan := make(chan interface{})
go func() {
defer close(outChan)
t, err := tail.TailFile(path, tail.Config{
Location: &tail.SeekInfo{0, 2},
Follow: true,
MustExist: true,
Logger: tail.DiscardingLogger,
})
if err != nil {
fmt.Println(err.Error())
return
}
defer t.Stop()
done := req.Context().Context.Done()
for line := range t.Lines {
// return when context closes
select {
case <-done:
return
default:
}
if line.Err != nil {
fmt.Println(err.Error())
return
}
// TODO: unpack the line text into a struct and output that
outChan <- &MessageOutput{line.Text}
}
}()
res.SetOutput((<-chan interface{})(outChan))
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
outChan, ok := res.Output().(<-chan interface{})
if !ok {
return nil, u.ErrCast()
}
return &cmds.ChannelMarshaler{
Channel: outChan,
Marshaler: func(v interface{}) (io.Reader, error) {
output := v.(*MessageOutput)
return strings.NewReader(output.Message + "\n"), nil
},
}, nil
},
},
Type: MessageOutput{},
}