github.com/cilium/cilium@v1.16.2/pkg/hubble/metrics/api/api.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Hubble
     3  
     4  package api
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"strings"
    11  
    12  	"github.com/prometheus/client_golang/prometheus"
    13  	"github.com/sirupsen/logrus"
    14  
    15  	pb "github.com/cilium/cilium/api/v1/flow"
    16  	"github.com/cilium/cilium/pkg/k8s/types"
    17  	"github.com/cilium/cilium/pkg/logging"
    18  	"github.com/cilium/cilium/pkg/logging/logfields"
    19  )
    20  
    21  const (
    22  	// DefaultPrometheusNamespace is the default namespace (prefix) used
    23  	// for all Hubble related Prometheus metrics
    24  	DefaultPrometheusNamespace = "hubble"
    25  )
    26  
    27  // Map is a set of metrics with their corresponding options
    28  type Map map[string]Options
    29  
    30  // ParseMetricList parses a slice of metric options and returns a map of
    31  // enabled metrics
    32  func ParseMetricList(enabledMetrics []string) (m Map) {
    33  	m = Map{}
    34  	for _, metric := range enabledMetrics {
    35  		s := strings.SplitN(metric, ":", 2)
    36  		if len(s) == 2 {
    37  			m[s[0]] = ParseOptions(s[1])
    38  		} else {
    39  			m[s[0]] = Options{}
    40  		}
    41  	}
    42  	return
    43  }
    44  
    45  // Handlers contains all the metrics handlers.
    46  type Handlers struct {
    47  	handlers       []Handler
    48  	flowProcessors []FlowProcessor
    49  }
    50  
    51  // Plugin is a metric plugin. A metric plugin is associated a name and is
    52  // responsible to spawn metric handlers of a certain type.
    53  type Plugin interface {
    54  	// NewHandler returns a new metric handler of the respective plugin
    55  	NewHandler() Handler
    56  
    57  	// HelpText returns a human readable help text including a description
    58  	// of the options
    59  	HelpText() string
    60  }
    61  
    62  // PluginConflicts is an optional interface that plugins can implement to
    63  // declare other plugins they conflict with.
    64  type PluginConflicts interface {
    65  	// ConflictingPlugin returns a list of other plugin names that this plugin
    66  	// conflicts with.
    67  	ConflictingPlugins() []string
    68  }
    69  
    70  // Handler is a basic metric handler.
    71  type Handler interface {
    72  	// Init must initialize the metric handler by validating and parsing
    73  	// the options and then registering all required metrics with the
    74  	// specifies Prometheus registry
    75  	Init(registry *prometheus.Registry, options Options) error
    76  
    77  	// ListMetricVec returns an array of MetricVec used by a handler
    78  	ListMetricVec() []*prometheus.MetricVec
    79  
    80  	// Context used by this metrics handler
    81  	Context() *ContextOptions
    82  
    83  	// Status returns the configuration status of the metric handler
    84  	Status() string
    85  }
    86  
    87  // FlowProcessor is a metric handler which requires flows to perform metrics
    88  // accounting.
    89  // It is called upon receival of raw event data and is responsible
    90  // to perform metrics accounting according to the scope of the metrics plugin.
    91  type FlowProcessor interface {
    92  	// ProcessFlow must processes a flow event and perform metrics
    93  	// accounting
    94  	ProcessFlow(ctx context.Context, flow *pb.Flow) error
    95  }
    96  
    97  func NewHandlers(log logrus.FieldLogger, registry *prometheus.Registry, in []NamedHandler) (*Handlers, error) {
    98  	var handlers Handlers
    99  	for _, item := range in {
   100  		handlers.handlers = append(handlers.handlers, item.Handler)
   101  		if fp, ok := item.Handler.(FlowProcessor); ok {
   102  			handlers.flowProcessors = append(handlers.flowProcessors, fp)
   103  		}
   104  
   105  		if err := item.Handler.Init(registry, item.Options); err != nil {
   106  			return nil, fmt.Errorf("unable to initialize metric '%s': %w", item.Name, err)
   107  		}
   108  
   109  		log.WithFields(logrus.Fields{
   110  			"name":   item.Name,
   111  			"status": item.Handler.Status(),
   112  		}).Info("Configured metrics plugin")
   113  	}
   114  	return &handlers, nil
   115  }
   116  
   117  // ProcessFlow processes a flow by calling ProcessFlow it on to all enabled
   118  // metric handlers
   119  func (h Handlers) ProcessFlow(ctx context.Context, flow *pb.Flow) error {
   120  	var errs error
   121  	for _, fp := range h.flowProcessors {
   122  		// Continue running the remaining metrics handlers, since one failing
   123  		// shouldn't impact the other metrics handlers.
   124  		errs = errors.Join(errs, fp.ProcessFlow(ctx, flow))
   125  	}
   126  	return errs
   127  }
   128  
   129  // ProcessCiliumEndpointDeletion queries all handlers for a list of MetricVec and removes
   130  // metrics directly associated to pod of the deleted cilium endpoint.
   131  func (h Handlers) ProcessCiliumEndpointDeletion(endpoint *types.CiliumEndpoint) {
   132  	for _, h := range h.handlers {
   133  		for _, mv := range h.ListMetricVec() {
   134  			if ctx := h.Context(); ctx != nil {
   135  				ctx.DeleteMetricsAssociatedWithPod(endpoint.GetName(), endpoint.GetNamespace(), mv)
   136  			}
   137  		}
   138  	}
   139  }
   140  
   141  var registry = NewRegistry(
   142  	logging.DefaultLogger.WithField(logfields.LogSubsys, "hubble"),
   143  )
   144  
   145  // DefaultRegistry returns the default registry of all available metric plugins
   146  func DefaultRegistry() *Registry {
   147  	return registry
   148  }