github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/pkg/metrics/metrics.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     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 metrics contains utilities for working with metrics in prow.
    18  package metrics
    19  
    20  import (
    21  	"net/http"
    22  	"strconv"
    23  	"time"
    24  
    25  	"github.com/prometheus/client_golang/prometheus"
    26  	"github.com/prometheus/client_golang/prometheus/promhttp"
    27  	"github.com/sirupsen/logrus"
    28  	ctrlruntimemetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
    29  
    30  	"sigs.k8s.io/prow/pkg/config"
    31  	"sigs.k8s.io/prow/pkg/interrupts"
    32  )
    33  
    34  type CreateServer func(http.Handler) interrupts.ListenAndServer
    35  
    36  // ExposeMetricsWithRegistry chooses whether to serve or push metrics for the service with the registry
    37  func ExposeMetricsWithRegistry(component string, pushGateway config.PushGateway, port int, reg prometheus.Gatherer, createServer CreateServer) {
    38  	if pushGateway.Endpoint != "" {
    39  		pushMetrics(component, pushGateway.Endpoint, pushGateway.Interval.Duration)
    40  		if !pushGateway.ServeMetrics {
    41  			return
    42  		}
    43  	}
    44  
    45  	// These get registered in controller-runtimes registry via an init in the internal/controller/metrics package. if
    46  	// we dont unregister them, metrics break if that package is somehow imported.
    47  	// Setting the default prometheus registry in controller-runtime is unfortunately not an option, because that would
    48  	// result in all metrics that got registered in controller-runtime via an init to vanish, as inits of dependencies
    49  	// always get executed before our own init.
    50  	// Exempted from linting, it uses a deprecated Prometheus function but must match what controller-runtime does so
    51  	// we can not change it.
    52  
    53  	//nolint:staticcheck
    54  	ctrlruntimemetrics.Registry.Unregister(prometheus.NewGoCollector())
    55  	//nolint:staticcheck
    56  	ctrlruntimemetrics.Registry.Unregister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
    57  
    58  	if reg == nil {
    59  		reg = prometheus.DefaultGatherer
    60  	}
    61  	handler := promhttp.HandlerFor(
    62  		prometheus.Gatherers{reg, ctrlruntimemetrics.Registry},
    63  		promhttp.HandlerOpts{},
    64  	)
    65  	metricsMux := http.NewServeMux()
    66  	metricsMux.Handle("/metrics", handler)
    67  	var server interrupts.ListenAndServer
    68  	if createServer == nil {
    69  		server = &http.Server{Addr: ":" + strconv.Itoa(port), Handler: metricsMux}
    70  	} else {
    71  		server = createServer(handler)
    72  	}
    73  	interrupts.ListenAndServe(server, 5*time.Second)
    74  }
    75  
    76  // ExposeMetrics chooses whether to serve or push metrics for the service
    77  func ExposeMetrics(component string, pushGateway config.PushGateway, port int) {
    78  	ExposeMetricsWithRegistry(component, pushGateway, port, nil, nil)
    79  }
    80  
    81  // pushMetrics is meant to run in a goroutine and continuously push
    82  // metrics to the provided endpoint.
    83  func pushMetrics(component, endpoint string, interval time.Duration) {
    84  	interrupts.TickLiteral(func() {
    85  		if err := fromGatherer(component, hostnameGroupingKey(), endpoint, prometheus.DefaultGatherer); err != nil {
    86  			logrus.WithField("component", component).WithError(err).Error("Failed to push metrics.")
    87  		}
    88  	}, interval)
    89  }