github.com/cilium/cilium@v1.16.2/operator/metrics/metrics.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package metrics
     5  
     6  import (
     7  	"errors"
     8  	"net/http"
     9  	"regexp"
    10  
    11  	"github.com/cilium/hive/cell"
    12  	"github.com/prometheus/client_golang/prometheus"
    13  	"github.com/prometheus/client_golang/prometheus/collectors"
    14  	"github.com/prometheus/client_golang/prometheus/promhttp"
    15  	"github.com/sirupsen/logrus"
    16  	controllerRuntimeMetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
    17  
    18  	"github.com/cilium/cilium/pkg/hive"
    19  	"github.com/cilium/cilium/pkg/metrics"
    20  	"github.com/cilium/cilium/pkg/metrics/metric"
    21  )
    22  
    23  // goCustomCollectorsRX tracks enabled go runtime metrics.
    24  var goCustomCollectorsRX = regexp.MustCompile(`^/sched/latencies:seconds`)
    25  
    26  type params struct {
    27  	cell.In
    28  
    29  	Logger     logrus.FieldLogger
    30  	Lifecycle  cell.Lifecycle
    31  	Shutdowner hive.Shutdowner
    32  
    33  	Cfg       Config
    34  	SharedCfg SharedConfig
    35  
    36  	Metrics []metric.WithMetadata `group:"hive-metrics"`
    37  }
    38  
    39  type metricsManager struct {
    40  	logger     logrus.FieldLogger
    41  	shutdowner hive.Shutdowner
    42  
    43  	server http.Server
    44  
    45  	metrics []metric.WithMetadata
    46  }
    47  
    48  func (mm *metricsManager) Start(ctx cell.HookContext) error {
    49  	mux := http.NewServeMux()
    50  	mux.Handle("/metrics", promhttp.HandlerFor(Registry, promhttp.HandlerOpts{}))
    51  	mm.server.Handler = mux
    52  
    53  	go func() {
    54  		mm.logger.WithField("address", mm.server.Addr).Info("Starting metrics server")
    55  		if err := mm.server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
    56  			mm.logger.WithError(err).Error("Unable to start metrics server")
    57  			mm.shutdowner.Shutdown()
    58  		}
    59  	}()
    60  
    61  	return nil
    62  }
    63  
    64  func (mm *metricsManager) Stop(ctx cell.HookContext) error {
    65  	if err := mm.server.Shutdown(ctx); err != nil {
    66  		mm.logger.WithError(err).Error("Shutdown operator metrics server failed")
    67  		return err
    68  	}
    69  	return nil
    70  }
    71  
    72  func registerMetricsManager(p params) {
    73  	if !p.SharedCfg.EnableMetrics {
    74  		return
    75  	}
    76  
    77  	mm := &metricsManager{
    78  		logger:     p.Logger,
    79  		shutdowner: p.Shutdowner,
    80  		server:     http.Server{Addr: p.Cfg.OperatorPrometheusServeAddr},
    81  		metrics:    p.Metrics,
    82  	}
    83  
    84  	if p.SharedCfg.EnableGatewayAPI {
    85  		// Use the same Registry as controller-runtime, so that we don't need
    86  		// to expose multiple metrics endpoints or servers.
    87  		//
    88  		// Ideally, we should use our own Registry instance, but the metrics
    89  		// registration is done by init() functions, which are executed before
    90  		// this function is called.
    91  		Registry = controllerRuntimeMetrics.Registry
    92  	} else {
    93  		Registry = prometheus.NewPedanticRegistry()
    94  		Registry.MustRegister(collectors.NewGoCollector(
    95  			collectors.WithGoCollectorRuntimeMetrics(
    96  				collectors.GoRuntimeMetricsRule{Matcher: goCustomCollectorsRX},
    97  			)))
    98  	}
    99  
   100  	Registry.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{Namespace: metrics.CiliumOperatorNamespace}))
   101  
   102  	for _, metric := range mm.metrics {
   103  		Registry.MustRegister(metric.(prometheus.Collector))
   104  	}
   105  
   106  	metrics.InitOperatorMetrics()
   107  	Registry.MustRegister(metrics.ErrorsWarnings)
   108  	metrics.FlushLoggingMetrics()
   109  
   110  	p.Lifecycle.Append(mm)
   111  }