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