github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/commands/debuglog.go (about) 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 This command accesses all logged Juju activity on a per-model basis. By 27 default, the model is the current model. 28 A log line is written in this format: 29 <entity> <timestamp> <log-level> <module>:<line-no> <message> 30 The "entity" is the source of the message: a machine or unit. Both are 31 obtained in the output to `[1:] + "`juju status`" + `. 32 The '--include' and '--exclude' options filter by entity. A unit entity is 33 identified by prefixing 'unit-' to its corresponding unit name and 34 replacing the slash with a dash. A machine entity is identified by 35 prefixing 'machine-' to its corresponding machine id. 36 The '--include-module' and '--exclude-module' options filter by (dotted) 37 logging module name, which can be truncated. 38 A combination of machine and unit filtering uses a logical OR whereas a 39 combination of module and machine/unit filtering uses a logical AND. 40 Log levels are cumulative; each lower level (more verbose) contains the 41 preceding higher level (less verbose). 42 43 Examples: 44 Exclude all machine 0 messages; show a maximum of 100 lines; and continue 45 to append filtered messages: 46 47 juju debug-log --exclude machine-0 --lines 100 48 49 Include only unit mysql/0 messages; show a maximum of 50 lines; and then 50 exit: 51 52 juju debug-log -T --include unit-mysql-0 --lines 50 53 54 Show all messages from unit apache2/3 or machine 1 and then exit: 55 56 juju debug-log -T --replay --include unit-apache2-3 --include machine-1 57 58 Include all juju.worker.uniter logging module messages that are also unit 59 wordpress/0 messages and continue to append filtered messages: 60 61 juju debug-log --replay --include-module juju.worker.uniter --include \ 62 unit-wordpress-0 63 64 To see all WARNING and ERROR messages: 65 66 juju debug-log --replay --level WARNING 67 68 See also: 69 status` 70 71 func (c *debugLogCommand) Info() *cmd.Info { 72 return &cmd.Info{ 73 Name: "debug-log", 74 Purpose: usageDebugLogSummary, 75 Doc: usageDebugLogDetails, 76 } 77 } 78 79 func newDebugLogCommand() cmd.Command { 80 return modelcmd.Wrap(&debugLogCommand{}) 81 } 82 83 type debugLogCommand struct { 84 modelcmd.ModelCommandBase 85 86 level string 87 params api.DebugLogParams 88 } 89 90 func (c *debugLogCommand) SetFlags(f *gnuflag.FlagSet) { 91 f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "i", "Only show log messages for these entities") 92 f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "include", "Only show log messages for these entities") 93 f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "x", "Do not show log messages for these entities") 94 f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "exclude", "Do not show log messages for these entities") 95 f.Var(cmd.NewAppendStringsValue(&c.params.IncludeModule), "include-module", "Only show log messages for these logging modules") 96 f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeModule), "exclude-module", "Do not show log messages for these logging modules") 97 98 f.StringVar(&c.level, "l", "", "Log level to show, one of [TRACE, DEBUG, INFO, WARNING, ERROR]") 99 f.StringVar(&c.level, "level", "", "") 100 101 f.UintVar(&c.params.Backlog, "n", defaultLineCount, "Show this many of the most recent (possibly filtered) lines, and continue to append") 102 f.UintVar(&c.params.Backlog, "lines", defaultLineCount, "") 103 f.UintVar(&c.params.Limit, "limit", 0, "Exit once this many of the most recent (possibly filtered) lines are shown") 104 f.BoolVar(&c.params.Replay, "replay", false, "Show the entire (possibly filtered) log and continue to append") 105 f.BoolVar(&c.params.NoTail, "T", false, "Stop after returning existing log messages") 106 f.BoolVar(&c.params.NoTail, "no-tail", false, "") 107 } 108 109 func (c *debugLogCommand) Init(args []string) error { 110 if c.level != "" { 111 level, ok := loggo.ParseLevel(c.level) 112 if !ok || level < loggo.TRACE || level > loggo.ERROR { 113 return fmt.Errorf("level value %q is not one of %q, %q, %q, %q, %q", 114 c.level, loggo.TRACE, loggo.DEBUG, loggo.INFO, loggo.WARNING, loggo.ERROR) 115 } 116 c.params.Level = level 117 } 118 return cmd.CheckEmpty(args) 119 } 120 121 type DebugLogAPI interface { 122 WatchDebugLog(params api.DebugLogParams) (io.ReadCloser, error) 123 Close() error 124 } 125 126 var getDebugLogAPI = func(c *debugLogCommand) (DebugLogAPI, error) { 127 return c.NewAPIClient() 128 } 129 130 // Run retrieves the debug log via the API. 131 func (c *debugLogCommand) Run(ctx *cmd.Context) (err error) { 132 client, err := getDebugLogAPI(c) 133 if err != nil { 134 return err 135 } 136 defer client.Close() 137 debugLog, err := client.WatchDebugLog(c.params) 138 if err != nil { 139 return err 140 } 141 defer debugLog.Close() 142 _, err = io.Copy(ctx.Stdout, debugLog) 143 return err 144 }