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  }