github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/cmd/juju/metricsdebug/metrics.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package metricsdebug 5 6 import ( 7 "fmt" 8 "io" 9 "time" 10 11 "github.com/gosuri/uitable" 12 "github.com/juju/cmd" 13 "github.com/juju/errors" 14 "github.com/juju/gnuflag" 15 "gopkg.in/juju/names.v2" 16 17 "github.com/juju/juju/api/metricsdebug" 18 "github.com/juju/juju/apiserver/params" 19 "github.com/juju/juju/cmd/modelcmd" 20 ) 21 22 const metricsDoc = ` 23 Display recently collected metrics. 24 ` 25 26 // MetricsCommand retrieves metrics stored in the juju controller. 27 type MetricsCommand struct { 28 modelcmd.ModelCommandBase 29 out cmd.Output 30 31 Tags []string 32 All bool 33 } 34 35 // New creates a new MetricsCommand. 36 func New() cmd.Command { 37 return modelcmd.Wrap(&MetricsCommand{}) 38 } 39 40 // Info implements Command.Info. 41 func (c *MetricsCommand) Info() *cmd.Info { 42 return &cmd.Info{ 43 Name: "metrics", 44 Args: "[tag1[...tagN]]", 45 Purpose: "Retrieve metrics collected by specified entities.", 46 Doc: metricsDoc, 47 } 48 } 49 50 // Init reads and verifies the cli arguments for the MetricsCommand 51 func (c *MetricsCommand) Init(args []string) error { 52 if !c.All && len(args) == 0 { 53 return errors.New("you need to specify at least one unit or application") 54 } else if c.All && len(args) > 0 { 55 return errors.New("cannot use --all with additional entities") 56 } 57 c.Tags = make([]string, len(args)) 58 for i, arg := range args { 59 if names.IsValidUnit(arg) { 60 c.Tags[i] = names.NewUnitTag(arg).String() 61 } else if names.IsValidApplication(arg) { 62 c.Tags[i] = names.NewApplicationTag(arg).String() 63 } else { 64 return errors.Errorf("%q is not a valid unit or application", args[0]) 65 } 66 } 67 return nil 68 } 69 70 // SetFlags implements cmd.Command.SetFlags. 71 func (c *MetricsCommand) SetFlags(f *gnuflag.FlagSet) { 72 c.ModelCommandBase.SetFlags(f) 73 c.out.AddFlags(f, "tabular", map[string]cmd.Formatter{ 74 "tabular": formatTabular, 75 "json": cmd.FormatJson, 76 "yaml": cmd.FormatYaml, 77 }) 78 f.BoolVar(&c.All, "all", false, "retrieve metrics collected by all units in the model") 79 } 80 81 type GetMetricsClient interface { 82 GetMetrics(tags ...string) ([]params.MetricResult, error) 83 Close() error 84 } 85 86 var newClient = func(env modelcmd.ModelCommandBase) (GetMetricsClient, error) { 87 state, err := env.NewAPIRoot() 88 if err != nil { 89 return nil, errors.Trace(err) 90 } 91 return metricsdebug.NewClient(state), nil 92 } 93 94 type metric struct { 95 Unit string `json:"unit" yaml:"unit"` 96 Timestamp time.Time `json:"timestamp" yaml:"timestamp"` 97 Metric string `json:"metric" yaml:"metric"` 98 Value string `json:"value" yaml:"value"` 99 } 100 101 // Run implements Command.Run. 102 func (c *MetricsCommand) Run(ctx *cmd.Context) error { 103 client, err := newClient(c.ModelCommandBase) 104 if err != nil { 105 return errors.Trace(err) 106 } 107 var metrics []params.MetricResult 108 if c.All { 109 metrics, err = client.GetMetrics() 110 } else { 111 metrics, err = client.GetMetrics(c.Tags...) 112 } 113 if err != nil { 114 return errors.Trace(err) 115 } 116 defer client.Close() 117 if len(metrics) == 0 { 118 return nil 119 } 120 results := make([]metric, len(metrics)) 121 for i, m := range metrics { 122 results[i] = metric{ 123 Unit: m.Unit, 124 Timestamp: m.Time, 125 Metric: m.Key, 126 Value: m.Value, 127 } 128 } 129 return errors.Trace(c.out.Write(ctx, results)) 130 } 131 132 // formatTabular returns a tabular view of collected metrics. 133 func formatTabular(writer io.Writer, value interface{}) error { 134 metrics, ok := value.([]metric) 135 if !ok { 136 return errors.Errorf("expected value of type %T, got %T", metrics, value) 137 } 138 table := uitable.New() 139 table.MaxColWidth = 50 140 table.Wrap = true 141 for _, col := range []int{1, 2, 3, 4} { 142 table.RightAlign(col) 143 } 144 table.AddRow("UNIT", "TIMESTAMP", "METRIC", "VALUE") 145 for _, m := range metrics { 146 table.AddRow(m.Unit, m.Timestamp.Format(time.RFC3339), m.Metric, m.Value) 147 } 148 _, err := fmt.Fprint(writer, table.String()) 149 return errors.Trace(err) 150 }