~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/cmd/juju/commands/debuglog.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2013, 2014 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package commands
 
5
 
 
6
import (
 
7
        "fmt"
 
8
        "io"
 
9
 
 
10
        "github.com/juju/cmd"
 
11
        "github.com/juju/loggo"
 
12
        "launchpad.net/gnuflag"
 
13
 
 
14
        "github.com/juju/juju/api"
 
15
        "github.com/juju/juju/cmd/modelcmd"
 
16
)
 
17
 
 
18
// defaultLineCount is the default number of lines to
 
19
// display, from the end of the consolidated log.
 
20
const defaultLineCount = 10
 
21
 
 
22
var usageDebugLogSummary = `
 
23
Displays log messages for a model.`[1:]
 
24
 
 
25
var usageDebugLogDetails = `
 
26
 
 
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.
 
29
 
 
30
Each log line is emitted in this format:
 
31
 
 
32
  <entity> <timestamp> <log-level> <module>:<line-no> <message>
 
33
 
 
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`" + `.
 
36
 
 
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.
 
41
 
 
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.
 
45
 
 
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.
 
53
 
 
54
Examples:
 
55
 
 
56
Exclude all machine 0 messages; show a maximum of 100 lines; and continue to
 
57
append filtered messages:
 
58
 
 
59
    juju debug-log --exclude machine-0 --lines 100
 
60
 
 
61
Include only unit mysql/0 messages; show a maximum of 50 lines; and then
 
62
exit:
 
63
 
 
64
    juju debug-log -T --include unit-mysql-0 --lines 50
 
65
 
 
66
Show all messages from unit apache2/3 or machine 1 and then exit:
 
67
 
 
68
    juju debug-log -T --replay --include unit-apache2-3 --include machine-1
 
69
 
 
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
 
72
filter:
 
73
 
 
74
    juju debug-log --replay 
 
75
        --include-module juju.worker.uniter \
 
76
        --include unit-wordpress-0
 
77
 
 
78
Show all messages from the juju.worker.uniter module, except those sent from
 
79
machine-3 or machine-4, and then stop:
 
80
 
 
81
    juju debug-log --replay --no-tail
 
82
        --include-module juju.worker.uniter \
 
83
        --exclude machine-3 \
 
84
        --exclude machine-4 
 
85
 
 
86
To see all WARNING and ERROR messages and then continue showing any
 
87
new WARNING and ERROR messages as they are logged:
 
88
 
 
89
    juju debug-log --replay --level WARNING
 
90
 
 
91
See also: 
 
92
    status
 
93
    ssh`
 
94
 
 
95
func (c *debugLogCommand) Info() *cmd.Info {
 
96
        return &cmd.Info{
 
97
                Name:    "debug-log",
 
98
                Purpose: usageDebugLogSummary,
 
99
                Doc:     usageDebugLogDetails,
 
100
        }
 
101
}
 
102
 
 
103
func newDebugLogCommand() cmd.Command {
 
104
        return modelcmd.Wrap(&debugLogCommand{})
 
105
}
 
106
 
 
107
type debugLogCommand struct {
 
108
        modelcmd.ModelCommandBase
 
109
 
 
110
        level  string
 
111
        params api.DebugLogParams
 
112
}
 
113
 
 
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")
 
121
 
 
122
        f.StringVar(&c.level, "l", "", "Log level to show, one of [TRACE, DEBUG, INFO, WARNING, ERROR]")
 
123
        f.StringVar(&c.level, "level", "", "")
 
124
 
 
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, "")
 
131
}
 
132
 
 
133
func (c *debugLogCommand) Init(args []string) error {
 
134
        if c.level != "" {
 
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)
 
139
                }
 
140
                c.params.Level = level
 
141
        }
 
142
        return cmd.CheckEmpty(args)
 
143
}
 
144
 
 
145
type DebugLogAPI interface {
 
146
        WatchDebugLog(params api.DebugLogParams) (io.ReadCloser, error)
 
147
        Close() error
 
148
}
 
149
 
 
150
var getDebugLogAPI = func(c *debugLogCommand) (DebugLogAPI, error) {
 
151
        return c.NewAPIClient()
 
152
}
 
153
 
 
154
// Run retrieves the debug log via the API.
 
155
func (c *debugLogCommand) Run(ctx *cmd.Context) (err error) {
 
156
        client, err := getDebugLogAPI(c)
 
157
        if err != nil {
 
158
                return err
 
159
        }
 
160
        defer client.Close()
 
161
        debugLog, err := client.WatchDebugLog(c.params)
 
162
        if err != nil {
 
163
                return err
 
164
        }
 
165
        defer debugLog.Close()
 
166
        _, err = io.Copy(ctx.Stdout, debugLog)
 
167
        return err
 
168
}