github.com/vmware/govmomi@v0.51.0/cli/metric/info.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package metric 6 7 import ( 8 "context" 9 "encoding/json" 10 "flag" 11 "fmt" 12 "io" 13 "strings" 14 "text/tabwriter" 15 16 "github.com/vmware/govmomi/cli" 17 "github.com/vmware/govmomi/vim25/types" 18 ) 19 20 type info struct { 21 *PerformanceFlag 22 group string 23 } 24 25 func init() { 26 cli.Register("metric.info", &info{}) 27 } 28 29 func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) { 30 cmd.PerformanceFlag, ctx = NewPerformanceFlag(ctx) 31 cmd.PerformanceFlag.Register(ctx, f) 32 33 f.StringVar(&cmd.group, "g", "", "Show info for a specific Group") 34 } 35 36 func (cmd *info) Usage() string { 37 return "PATH [NAME]..." 38 } 39 40 func (cmd *info) Description() string { 41 return `Metric info for NAME. 42 43 If PATH is a value other than '-', provider summary and instance list are included 44 for the given object type. 45 46 If NAME is not specified, all available metrics for the given INTERVAL are listed. 47 An object PATH must be provided in this case. 48 49 Examples: 50 govc metric.info vm/my-vm 51 govc metric.info -i 300 vm/my-vm 52 govc metric.info - cpu.usage.average 53 govc metric.info /dc1/host/cluster cpu.usage.average` 54 } 55 56 func (cmd *info) Process(ctx context.Context) error { 57 if err := cmd.PerformanceFlag.Process(ctx); err != nil { 58 return err 59 } 60 return nil 61 } 62 63 type EntityDetail struct { 64 Realtime bool `json:"realtime"` 65 Historical bool `json:"historical"` 66 Instance []string `json:"instance"` 67 } 68 69 type MetricInfo struct { 70 Counter *types.PerfCounterInfo `json:"counter"` 71 Enabled []string `json:"enabled"` 72 PerDeviceEnabled []string `json:"perDeviceEnabled"` 73 Detail *EntityDetail `json:"detail"` 74 } 75 76 type infoResult struct { 77 Info []*MetricInfo `json:"info"` 78 cmd *info 79 } 80 81 func (r *infoResult) Write(w io.Writer) error { 82 tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0) 83 84 for _, info := range r.Info { 85 counter := info.Counter 86 87 fmt.Fprintf(tw, "Name:\t%s\n", counter.Name()) 88 fmt.Fprintf(tw, " Label:\t%s\n", counter.NameInfo.GetElementDescription().Label) 89 fmt.Fprintf(tw, " Summary:\t%s\n", counter.NameInfo.GetElementDescription().Summary) 90 fmt.Fprintf(tw, " Group:\t%s\n", counter.GroupInfo.GetElementDescription().Label) 91 fmt.Fprintf(tw, " Unit:\t%s\n", counter.UnitInfo.GetElementDescription().Label) 92 fmt.Fprintf(tw, " Rollup type:\t%s\n", counter.RollupType) 93 fmt.Fprintf(tw, " Stats type:\t%s\n", counter.StatsType) 94 fmt.Fprintf(tw, " Level:\t%d\n", counter.Level) 95 fmt.Fprintf(tw, " Intervals:\t%s\n", strings.Join(info.Enabled, ",")) 96 fmt.Fprintf(tw, " Per-device level:\t%d\n", counter.PerDeviceLevel) 97 fmt.Fprintf(tw, " Intervals:\t%s\n", strings.Join(info.PerDeviceEnabled, ",")) 98 99 summary := info.Detail 100 if summary == nil { 101 continue 102 } 103 104 fmt.Fprintf(tw, " Realtime:\t%t\n", summary.Realtime) 105 fmt.Fprintf(tw, " Historical:\t%t\n", summary.Historical) 106 fmt.Fprintf(tw, " Instances:\t%s\n", strings.Join(summary.Instance, ",")) 107 } 108 109 return tw.Flush() 110 } 111 112 func (r *infoResult) MarshalJSON() ([]byte, error) { 113 m := make(map[string]*MetricInfo) 114 115 for _, info := range r.Info { 116 m[info.Counter.Name()] = info 117 } 118 119 return json.Marshal(m) 120 } 121 122 func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error { 123 if f.NArg() == 0 { 124 return flag.ErrHelp 125 } 126 127 names := f.Args()[1:] 128 129 m, err := cmd.Manager(ctx) 130 if err != nil { 131 return err 132 } 133 134 counters, err := m.CounterInfoByName(ctx) 135 if err != nil { 136 return err 137 } 138 139 intervals, err := m.HistoricalInterval(ctx) 140 if err != nil { 141 return err 142 } 143 enabled := intervals.Enabled() 144 145 var summary *types.PerfProviderSummary 146 var mids map[int32][]*types.PerfMetricId 147 148 if f.Arg(0) == "-" { 149 if len(names) == 0 { 150 return flag.ErrHelp 151 } 152 } else { 153 objs, err := cmd.ManagedObjects(ctx, f.Args()[:1]) 154 if err != nil { 155 return err 156 } 157 158 summary, err = m.ProviderSummary(ctx, objs[0]) 159 if err != nil { 160 return err 161 } 162 163 all, err := m.AvailableMetric(ctx, objs[0], cmd.Interval(summary.RefreshRate)) 164 if err != nil { 165 return err 166 } 167 168 mids = all.ByKey() 169 170 if len(names) == 0 { 171 nc, _ := m.CounterInfoByKey(ctx) 172 173 seen := make(map[int32]bool) 174 for i := range all { 175 id := &all[i] 176 info, ok := nc[id.CounterId] 177 if !ok || seen[id.CounterId] { 178 continue 179 } 180 seen[id.CounterId] = true 181 182 names = append(names, info.Name()) 183 } 184 } 185 } 186 187 var metrics []*MetricInfo 188 189 for _, name := range names { 190 counter, ok := counters[name] 191 if !ok { 192 return cmd.ErrNotFound(name) 193 } 194 195 if cmd.group != "" { 196 if counter.GroupInfo.GetElementDescription().Label != cmd.group { 197 continue 198 } 199 } 200 201 info := &MetricInfo{ 202 Counter: counter, 203 Enabled: enabled[counter.Level], 204 PerDeviceEnabled: enabled[counter.PerDeviceLevel], 205 } 206 207 metrics = append(metrics, info) 208 209 if summary == nil { 210 continue 211 } 212 213 var instances []string 214 215 for _, id := range mids[counter.Key] { 216 if id.Instance != "" { 217 instances = append(instances, id.Instance) 218 } 219 } 220 221 info.Detail = &EntityDetail{ 222 Realtime: summary.CurrentSupported, 223 Historical: summary.SummarySupported, 224 Instance: instances, 225 } 226 227 } 228 229 return cmd.WriteResult(&infoResult{metrics, cmd}) 230 }