go.ligato.io/vpp-agent/v3@v3.5.0/examples/vpp_stats/main.go (about)

     1  //  Copyright (c) 2020 Cisco and/or its affiliates.
     2  //
     3  //  Licensed under the Apache License, Version 2.0 (the "License");
     4  //  you may not use this file except in compliance with the License.
     5  //  You may obtain a copy of the License at:
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //  Unless required by applicable law or agreed to in writing, software
    10  //  distributed under the License is distributed on an "AS IS" BASIS,
    11  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //  See the License for the specific language governing permissions and
    13  //  limitations under the License.
    14  
    15  // The VPP stats example shows how to use telemetry API to access
    16  // VPP stats via the GoVPP stats socket API and the telemetry vpp calls.
    17  
    18  package main
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  	"log"
    24  	"time"
    25  
    26  	"go.fd.io/govpp/api"
    27  	"go.ligato.io/cn-infra/v2/agent"
    28  	"go.ligato.io/cn-infra/v2/config"
    29  	"go.ligato.io/cn-infra/v2/logging"
    30  	"go.ligato.io/cn-infra/v2/logging/logrus"
    31  
    32  	"go.ligato.io/vpp-agent/v3/plugins/govppmux"
    33  	"go.ligato.io/vpp-agent/v3/plugins/telemetry"
    34  	"go.ligato.io/vpp-agent/v3/plugins/telemetry/vppcalls"
    35  )
    36  
    37  const PluginName = "stats-example"
    38  
    39  func main() {
    40  	ep := &StatsExamplePlugin{
    41  		Log:       logging.DefaultLogger,
    42  		Telemetry: &telemetry.DefaultPlugin,
    43  	}
    44  	stopExample := make(chan struct{})
    45  
    46  	a := agent.NewAgent(
    47  		agent.AllPlugins(ep),
    48  		agent.QuitOnClose(stopExample),
    49  	)
    50  	if err := a.Run(); err != nil {
    51  		log.Fatal(err)
    52  	}
    53  
    54  	go closeExample("Stats example finished", stopExample)
    55  }
    56  
    57  // StatsExamplePlugin displays VPP stats using telemetry plugin
    58  type StatsExamplePlugin struct {
    59  	handler vppcalls.TelemetryVppAPI
    60  
    61  	config.PluginConfig
    62  	Log       logging.Logger
    63  	Telemetry *telemetry.Plugin
    64  }
    65  
    66  func (p *StatsExamplePlugin) Init() error {
    67  	var err error
    68  	p.handler, err = vppcalls.NewHandler(&govppmux.DefaultPlugin)
    69  	if err != nil {
    70  		panic(err)
    71  	}
    72  
    73  	go p.processStats()
    74  	return nil
    75  }
    76  
    77  func (p *StatsExamplePlugin) Close() error {
    78  	p.Log.Info("Stats example closed")
    79  	return nil
    80  }
    81  
    82  func (p *StatsExamplePlugin) String() string {
    83  	return PluginName
    84  }
    85  
    86  func closeExample(message string, stopExample chan struct{}) {
    87  	time.Sleep(10 * time.Second)
    88  	logrus.DefaultLogger().Info(message)
    89  	close(stopExample)
    90  }
    91  
    92  func (p *StatsExamplePlugin) processStats() {
    93  	// give the Agent some time to initialize
    94  	// so the output is not mixed
    95  	time.Sleep(1 * time.Second)
    96  	p.Log.Infoln("Processing stats")
    97  
    98  	var errors []error
    99  
   100  	// collect stats
   101  	ifStats, err := p.handler.GetInterfaceStats(context.Background())
   102  	if err != nil {
   103  		errors = append(errors, fmt.Errorf("eroror retireving interface stats: %v", err))
   104  	}
   105  	nodeCounters, err := p.handler.GetNodeCounters(context.Background())
   106  	if err != nil {
   107  		errors = append(errors, fmt.Errorf("eroror retireving node counters: %v", err))
   108  	}
   109  
   110  	systemStats, err := p.handler.GetSystemStats(context.Background())
   111  	if err != nil {
   112  		errors = append(errors, fmt.Errorf("eroror retireving system stats: %v", err))
   113  	}
   114  
   115  	runtimeInfo, err := p.handler.GetRuntimeInfo(context.Background())
   116  	if err != nil {
   117  		errors = append(errors, fmt.Errorf("eroror retireving runtime info: %v", err))
   118  	}
   119  
   120  	bufferInfo, err := p.handler.GetBuffersInfo(context.Background())
   121  	if err != nil {
   122  		errors = append(errors, fmt.Errorf("eroror retireving buffers info: %v", err))
   123  	}
   124  
   125  	threadsInfo, err := p.handler.GetThreads(context.Background())
   126  	if err != nil {
   127  		errors = append(errors, fmt.Errorf("eroror retireving threads: %v", err))
   128  	}
   129  
   130  	memoryInfo, err := p.handler.GetMemory(context.Background())
   131  	fmt.Printf("mem %v, err %v", memoryInfo, err)
   132  	if err != nil {
   133  		errors = append(errors, fmt.Errorf("eroror retireving memory info: %v", err))
   134  	}
   135  
   136  	// print all errors and return if there is any
   137  	if len(errors) != 0 {
   138  		for _, err := range errors {
   139  			p.Log.Error(err)
   140  		}
   141  		return
   142  	}
   143  
   144  	// print collected stats
   145  	printIfStats(ifStats)
   146  	printNodeCounters(nodeCounters)
   147  	printSystemStats(systemStats)
   148  	printRuntimeInfo(runtimeInfo)
   149  	printBufferInfo(bufferInfo)
   150  	printThreadsInfo(threadsInfo)
   151  	printMemoryInfo(memoryInfo)
   152  }
   153  
   154  func printIfStats(ifStats *api.InterfaceStats) {
   155  	for _, ifStat := range ifStats.Interfaces {
   156  		fmt.Printf(`
   157  Interface name: %s (sw_if_idx %d)
   158  	Received: %d (rx errors %d)
   159  	Transmitted: %d (tx errors %d)
   160  	Drops: %d
   161  `, ifStat.InterfaceName, ifStat.InterfaceIndex, ifStat.Rx, ifStat.RxErrors,
   162  			ifStat.Tx, ifStat.TxErrors, ifStat.Drops)
   163  	}
   164  }
   165  
   166  func printNodeCounters(nodeCountersInfo *vppcalls.NodeCounterInfo) {
   167  	maxLen := 5
   168  	for i, nodeCounters := range nodeCountersInfo.GetCounters() {
   169  		if i >= maxLen {
   170  			// do not print everything, it is not necessary
   171  			break
   172  		}
   173  		fmt.Printf(`
   174  Node name: %s 
   175  Node: %s 
   176  
   177  `, nodeCounters.Name, nodeCounters.Node)
   178  	}
   179  	if len(nodeCountersInfo.GetCounters()) >= maxLen {
   180  		fmt.Printf("... and another %d nodes\n", len(nodeCountersInfo.GetCounters())-maxLen)
   181  	}
   182  }
   183  
   184  func printSystemStats(systemStats *api.SystemStats) {
   185  	fmt.Printf(`
   186  Last update: %d
   187  Last stats clear: %d
   188  Input rate: %d
   189  Num. Worker Threads: %d
   190  Vector rate: %d (per worker: %+v)
   191  Heartbeat: %d
   192  `, systemStats.LastUpdate, systemStats.LastStatsClear, systemStats.InputRate, systemStats.NumWorkerThreads,
   193  		systemStats.VectorRate, systemStats.VectorRatePerWorker, systemStats.Heartbeat)
   194  }
   195  
   196  func printRuntimeInfo(runtimeInfo *vppcalls.RuntimeInfo) {
   197  	for _, thread := range runtimeInfo.GetThreads() {
   198  		fmt.Printf("\nThread: %s (ID %d)", thread.Name, thread.ID)
   199  	}
   200  }
   201  
   202  func printBufferInfo(bufferInfo *vppcalls.BuffersInfo) {
   203  	for _, buffer := range bufferInfo.GetItems() {
   204  		fmt.Printf(`
   205  
   206  Buffer name: %s (index %d)
   207  	Alloc: %d (num %d)
   208  	Free: %d (num %d)
   209  	Size: %d
   210  	Thread ID: %d
   211  `, buffer.Name, buffer.Index, buffer.Alloc, buffer.NumAlloc, buffer.Free, buffer.NumFree, buffer.Size, buffer.ThreadID)
   212  	}
   213  }
   214  
   215  func printThreadsInfo(threadsInfo *vppcalls.ThreadsInfo) {
   216  	for _, thread := range threadsInfo.GetItems() {
   217  		fmt.Printf(`
   218  Thread name: %s (ID %d)
   219  	Type: %s
   220  	PID: %d 
   221  	Core: %d (CPU ID %d, CPU socket %d)
   222  `, thread.Name, thread.ID, thread.Type, thread.PID, thread.Core, thread.CPUID, thread.CPUSocket)
   223  	}
   224  }
   225  
   226  func printMemoryInfo(memoryInfo *vppcalls.MemoryInfo) {
   227  	for _, thread := range memoryInfo.GetThreads() {
   228  		fmt.Printf(`
   229  Thread %d %s
   230    size %d, %d pages, page size %d
   231    total: %d, used: %d, free: %d, trimmable: %d
   232      free chunks %d free fastbin blks %d
   233      max total allocated %d
   234  `, thread.ID, thread.Name, thread.Size, thread.Pages, thread.PageSize, thread.Total, thread.Used,
   235  			thread.Free, thread.Trimmable, thread.FreeChunks, thread.FreeFastbinBlks, thread.MaxTotalAlloc)
   236  	}
   237  }