github.com/vmware/govmomi@v0.37.2/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  }