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 }