github.com/vmware/govmomi@v0.51.0/cli/metric/ls.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  	"text/tabwriter"
    14  
    15  	"github.com/vmware/govmomi/cli"
    16  	"github.com/vmware/govmomi/performance"
    17  	"github.com/vmware/govmomi/vim25/types"
    18  )
    19  
    20  type ls struct {
    21  	*PerformanceFlag
    22  
    23  	group    string
    24  	long     bool
    25  	longlong bool
    26  }
    27  
    28  func init() {
    29  	cli.Register("metric.ls", &ls{})
    30  }
    31  
    32  func (cmd *ls) Register(ctx context.Context, f *flag.FlagSet) {
    33  	cmd.PerformanceFlag, ctx = NewPerformanceFlag(ctx)
    34  	cmd.PerformanceFlag.Register(ctx, f)
    35  
    36  	f.StringVar(&cmd.group, "g", "", "List a specific Group")
    37  	f.BoolVar(&cmd.long, "l", false, "Long listing format")
    38  	f.BoolVar(&cmd.longlong, "L", false, "Longer listing format")
    39  }
    40  
    41  func (cmd *ls) Usage() string {
    42  	return "PATH"
    43  }
    44  
    45  func (cmd *ls) Description() string {
    46  	return `List available metrics for PATH.
    47  
    48  The default output format is the metric name.
    49  The '-l' flag includes the metric description.
    50  The '-L' flag includes the metric units, instance count (if any) and description.
    51  The instance count is prefixed with a single '@'.
    52  If no aggregate is provided for the metric, instance count is prefixed with two '@@'.
    53  
    54  Examples:
    55    govc metric.ls /dc1/host/cluster1
    56    govc metric.ls datastore/*
    57    govc metric.ls -L -g CPU /dc1/host/cluster1/host1
    58    govc metric.ls vm/* | grep mem. | xargs govc metric.sample vm/*`
    59  }
    60  
    61  func (cmd *ls) Process(ctx context.Context) error {
    62  	if err := cmd.PerformanceFlag.Process(ctx); err != nil {
    63  		return err
    64  	}
    65  	return nil
    66  }
    67  
    68  type lsResult struct {
    69  	cmd      *ls
    70  	counters map[int32]*types.PerfCounterInfo
    71  	performance.MetricList
    72  }
    73  
    74  func (r *lsResult) Write(w io.Writer) error {
    75  	tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
    76  
    77  	type count struct {
    78  		aggregate bool
    79  		instances int
    80  	}
    81  	seen := make(map[int32]*count)
    82  	var res []types.PerfMetricId
    83  
    84  	for _, id := range r.MetricList {
    85  		if r.cmd.group != "" {
    86  			info, ok := r.counters[id.CounterId]
    87  			if !ok || info.GroupInfo.GetElementDescription().Label != r.cmd.group {
    88  				continue
    89  			}
    90  		}
    91  
    92  		c := seen[id.CounterId]
    93  		if c == nil {
    94  			c = new(count)
    95  			seen[id.CounterId] = c
    96  			res = append(res, id)
    97  		}
    98  
    99  		if id.Instance == "" {
   100  			c.aggregate = true
   101  		} else {
   102  			c.instances++
   103  		}
   104  	}
   105  
   106  	for _, id := range res {
   107  		info, ok := r.counters[id.CounterId]
   108  		if !ok {
   109  			continue
   110  		}
   111  
   112  		switch {
   113  		case r.cmd.long:
   114  			fmt.Fprintf(tw, "%s\t%s\n", info.Name(),
   115  				info.NameInfo.GetElementDescription().Label)
   116  		case r.cmd.longlong:
   117  			i := ""
   118  			c := seen[id.CounterId]
   119  			if !c.aggregate {
   120  				i = "@"
   121  			}
   122  			if c.instances > 0 {
   123  				i += fmt.Sprintf("@%d", c.instances)
   124  			}
   125  			fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", info.Name(),
   126  				i,
   127  				info.UnitInfo.GetElementDescription().Label,
   128  				info.NameInfo.GetElementDescription().Label)
   129  		default:
   130  			fmt.Fprintln(w, info.Name())
   131  		}
   132  	}
   133  
   134  	return tw.Flush()
   135  }
   136  
   137  func (r *lsResult) MarshalJSON() ([]byte, error) {
   138  	m := make(map[string]*types.PerfCounterInfo)
   139  
   140  	for _, id := range r.MetricList {
   141  		if info, ok := r.counters[id.CounterId]; ok {
   142  			m[info.Name()] = info
   143  		}
   144  	}
   145  
   146  	return json.Marshal(m)
   147  }
   148  
   149  func (cmd *ls) Run(ctx context.Context, f *flag.FlagSet) error {
   150  	if f.NArg() != 1 {
   151  		return flag.ErrHelp
   152  	}
   153  
   154  	objs, err := cmd.ManagedObjects(ctx, f.Args())
   155  	if err != nil {
   156  		return err
   157  	}
   158  
   159  	m, err := cmd.Manager(ctx)
   160  	if err != nil {
   161  		return err
   162  	}
   163  
   164  	s, err := m.ProviderSummary(ctx, objs[0])
   165  	if err != nil {
   166  		return err
   167  	}
   168  
   169  	mids, err := m.AvailableMetric(ctx, objs[0], cmd.Interval(s.RefreshRate))
   170  	if err != nil {
   171  		return err
   172  	}
   173  
   174  	counters, err := m.CounterInfoByKey(ctx)
   175  	if err != nil {
   176  		return err
   177  	}
   178  
   179  	return cmd.WriteResult(&lsResult{cmd, counters, mids})
   180  }