github.com/vmware/govmomi@v0.37.2/govc/metric/ls.go (about)

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