1
// Copyright 2013, 2014 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
11
"github.com/juju/loggo"
12
"launchpad.net/gnuflag"
14
"github.com/juju/juju/api"
15
"github.com/juju/juju/cmd/modelcmd"
18
// defaultLineCount is the default number of lines to
19
// display, from the end of the consolidated log.
20
const defaultLineCount = 10
22
var usageDebugLogSummary = `
23
Displays log messages for a model.`[1:]
25
var usageDebugLogDetails = `
27
This command provides access to all logged Juju activity on a per-model
28
basis. By default, the logs for the currently select model are shown.
30
Each log line is emitted in this format:
32
<entity> <timestamp> <log-level> <module>:<line-no> <message>
34
The "entity" is the source of the message: a machine or unit. The names for
35
machines and units can be seen in the output of `[1:] + "`juju status`" + `.
37
The '--include' and '--exclude' options filter by entity. A unit entity is
38
identified by prefixing 'unit-' to its corresponding unit name and replacing
39
the slash with a dash. A machine entity is identified by prefixing 'machine-'
40
to its corresponding machine id.
42
The '--include-module' and '--exclude-module' options filter by (dotted)
43
logging module name. The module name can be truncated such that all loggers
44
with the prefix will match.
46
The filtering options combine as follows:
47
* All --include options are logically ORed together.
48
* All --exclude options are logically ORed together.
49
* All --include-module options are logically ORed together.
50
* All --exclude-module options are logically ORed together.
51
* The combined --include, --exclude, --include-module and --exclude-module
52
selections are logically ANDed to form the complete filter.
56
Exclude all machine 0 messages; show a maximum of 100 lines; and continue to
57
append filtered messages:
59
juju debug-log --exclude machine-0 --lines 100
61
Include only unit mysql/0 messages; show a maximum of 50 lines; and then
64
juju debug-log -T --include unit-mysql-0 --lines 50
66
Show all messages from unit apache2/3 or machine 1 and then exit:
68
juju debug-log -T --replay --include unit-apache2-3 --include machine-1
70
Show all juju.worker.uniter logging module messages that are also unit
71
wordpress/0 messages, and then show any new log messages which match the
74
juju debug-log --replay
75
--include-module juju.worker.uniter \
76
--include unit-wordpress-0
78
Show all messages from the juju.worker.uniter module, except those sent from
79
machine-3 or machine-4, and then stop:
81
juju debug-log --replay --no-tail
82
--include-module juju.worker.uniter \
86
To see all WARNING and ERROR messages and then continue showing any
87
new WARNING and ERROR messages as they are logged:
89
juju debug-log --replay --level WARNING
95
func (c *debugLogCommand) Info() *cmd.Info {
98
Purpose: usageDebugLogSummary,
99
Doc: usageDebugLogDetails,
103
func newDebugLogCommand() cmd.Command {
104
return modelcmd.Wrap(&debugLogCommand{})
107
type debugLogCommand struct {
108
modelcmd.ModelCommandBase
111
params api.DebugLogParams
114
func (c *debugLogCommand) SetFlags(f *gnuflag.FlagSet) {
115
f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "i", "Only show log messages for these entities")
116
f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "include", "Only show log messages for these entities")
117
f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "x", "Do not show log messages for these entities")
118
f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "exclude", "Do not show log messages for these entities")
119
f.Var(cmd.NewAppendStringsValue(&c.params.IncludeModule), "include-module", "Only show log messages for these logging modules")
120
f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeModule), "exclude-module", "Do not show log messages for these logging modules")
122
f.StringVar(&c.level, "l", "", "Log level to show, one of [TRACE, DEBUG, INFO, WARNING, ERROR]")
123
f.StringVar(&c.level, "level", "", "")
125
f.UintVar(&c.params.Backlog, "n", defaultLineCount, "Show this many of the most recent (possibly filtered) lines, and continue to append")
126
f.UintVar(&c.params.Backlog, "lines", defaultLineCount, "")
127
f.UintVar(&c.params.Limit, "limit", 0, "Exit once this many of the most recent (possibly filtered) lines are shown")
128
f.BoolVar(&c.params.Replay, "replay", false, "Show the entire (possibly filtered) log and continue to append")
129
f.BoolVar(&c.params.NoTail, "T", false, "Stop after returning existing log messages")
130
f.BoolVar(&c.params.NoTail, "no-tail", false, "")
133
func (c *debugLogCommand) Init(args []string) error {
135
level, ok := loggo.ParseLevel(c.level)
136
if !ok || level < loggo.TRACE || level > loggo.ERROR {
137
return fmt.Errorf("level value %q is not one of %q, %q, %q, %q, %q",
138
c.level, loggo.TRACE, loggo.DEBUG, loggo.INFO, loggo.WARNING, loggo.ERROR)
140
c.params.Level = level
142
return cmd.CheckEmpty(args)
145
type DebugLogAPI interface {
146
WatchDebugLog(params api.DebugLogParams) (io.ReadCloser, error)
150
var getDebugLogAPI = func(c *debugLogCommand) (DebugLogAPI, error) {
151
return c.NewAPIClient()
154
// Run retrieves the debug log via the API.
155
func (c *debugLogCommand) Run(ctx *cmd.Context) (err error) {
156
client, err := getDebugLogAPI(c)
161
debugLog, err := client.WatchDebugLog(c.params)
165
defer debugLog.Close()
166
_, err = io.Copy(ctx.Stdout, debugLog)