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 }