@@ -3,120 +3,108 @@ package metrics
33import (
44 "fmt"
55 "io"
6- "strings "
6+ "log "
77 "sync"
88 "time"
99
10- "github.com/d-Rickyy-b/certstream-server-go/internal/certificatetransparency"
11- "github.com/d-Rickyy-b/certstream-server-go/internal/web"
12-
1310 "github.com/VictoriaMetrics/metrics"
1411)
1512
16- var (
17- ctLogMetricsInitialized = false
18- ctLogMetricsInitMutex = & sync.Mutex {}
19-
20- tempCertMetricsLastRefreshed = time.Time {}
21- tempCertMetrics = certificatetransparency.CTMetrics {}
22- tempCertMetricsMutex = & sync.RWMutex {}
13+ var Prometheus = NewPrometheusExporter ()
2314
15+ type PrometheusExporter struct {
2416 // Number of currently connected clients.
25- fullClientCount = metrics .NewGauge ("certstreamservergo_clients_total{type=\" full\" }" , func () float64 {
26- return float64 (web .ClientHandler .ClientFullCount ())
27- })
28- liteClientCount = metrics .NewGauge ("certstreamservergo_clients_total{type=\" lite\" }" , func () float64 {
29- return float64 (web .ClientHandler .ClientLiteCount ())
30- })
31- domainClientCount = metrics .NewGauge ("certstreamservergo_clients_total{type=\" domain\" }" , func () float64 {
32- return float64 (web .ClientHandler .ClientDomainsCount ())
33- })
17+ fullClientCount metrics.Gauge
18+ liteClientCount metrics.Gauge
19+ domainClientCount metrics.Gauge
20+
21+ tempCertMetricsLastRefreshed time.Time
22+ tempCertMetrics CTMetrics
23+ tempCertMetricsMutex sync.RWMutex
24+
25+ skippedCertsCallback func () map [string ]int64
26+ }
3427
35- // Number of certificates processed by the CT watcher.
36- processedCertificates = metrics .NewGauge ("certstreamservergo_certificates_total{type=\" regular\" }" , func () float64 {
37- return float64 (certificatetransparency .GetProcessedCerts ())
28+ // NewPrometheusExporter creates a new PrometheusExporter and registers the default metrics for the number of processed certificates.
29+ func NewPrometheusExporter () * PrometheusExporter {
30+ e := & PrometheusExporter {}
31+ // Register metrics for the total number of certificates processed by the CT watcher.
32+ metrics .GetOrCreateGauge ("certstreamservergo_certificates_total{type=\" regular\" }" , func () float64 {
33+ return float64 (GetProcessedCerts ())
3834 })
39- processedPreCertificates = metrics .NewGauge ("certstreamservergo_certificates_total{type=\" precert\" }" , func () float64 {
40- return float64 (certificatetransparency . GetProcessedPrecerts ())
35+ metrics .GetOrCreateGauge ("certstreamservergo_certificates_total{type=\" precert\" }" , func () float64 {
36+ return float64 (GetProcessedPrecerts ())
4137 })
42- )
43-
44- // WritePrometheus provides an easy way to write metrics to a writer.
45- func WritePrometheus (w io.Writer , exposeProcessMetrics bool ) {
46- ctLogMetricsInitMutex .Lock ()
47- if ! ctLogMetricsInitialized {
48- initCtLogMetrics ()
49- }
50- ctLogMetricsInitMutex .Unlock ()
38+ return e
39+ }
5140
52- getSkippedCertMetrics ()
41+ // Write is a callback function that is called by a webserver in order to write metrics data to the http response.
42+ func (pm * PrometheusExporter ) Write (w io.Writer , exposeProcessMetrics bool ) {
43+ // getSkippedCertMetrics()
5344
5445 metrics .WritePrometheus (w , exposeProcessMetrics )
5546}
5647
57- // For having metrics regarding each individual CT log, we need to register them manually.
58- // initCtLogMetrics fetches all the CT Logs and registers one metric per log.
59- func initCtLogMetrics () {
60- logs := certificatetransparency .GetLogOperators ()
61-
62- for operator , urls := range logs {
63- operator := operator // Copy variable to new scope
64-
65- for i := range urls {
66- url := urls [i ]
67- name := fmt .Sprintf ("certstreamservergo_certs_by_log_total{url=\" %s\" ,operator=\" %s\" }" , url , operator )
68- metrics .NewGauge (name , func () float64 {
69- return float64 (getCertCountForLog (operator , url ))
70- })
71- }
72- }
48+ // RegisterGaugeMetric is a helper function that registers a new gauge metric with a float64 callback function.
49+ func (pm * PrometheusExporter ) RegisterGaugeMetric (label string , callback func () float64 ) {
50+ metrics .GetOrCreateGauge (label , callback )
51+ }
7352
74- if len (logs ) > 0 {
75- ctLogMetricsInitialized = true
76- }
53+ // RegisterGaugeMetricInt is a helper function that registers a new gauge metric with an int64 callback function.
54+ func (pm * PrometheusExporter ) RegisterGaugeMetricInt (label string , callback func () int64 ) {
55+ metrics .GetOrCreateGauge (label , func () float64 { return float64 (callback ()) })
56+ }
57+
58+ // RegisterClient registers a new gauge metric for the client with the given name.
59+ func (pm * PrometheusExporter ) RegisterClient (name string , callback func () float64 ) {
60+ label := fmt .Sprintf ("certstreamservergo_skipped_certs{client=\" %s\" }" , name )
61+ metrics .GetOrCreateGauge (label , callback )
62+ }
63+
64+ // UnregisterClient unregisters the metric for the client with the given name.
65+ func (pm * PrometheusExporter ) UnregisterClient (name string ) {
66+ label := fmt .Sprintf ("certstreamservergo_skipped_certs{client=\" %s\" }" , name )
67+ metrics .UnregisterMetric (label )
68+ }
69+
70+ // RegisterLog registers a new gauge metric for the given CT log.
71+ // The metric will be named "certstreamservergo_certs_by_log_total{url=\"<url>\",operator=\"<operatorName>\"}" and
72+ // will call the given callback function to get the current value of the metric.
73+ func (pm * PrometheusExporter ) RegisterLog (operatorName , url string ) {
74+ label := fmt .Sprintf ("certstreamservergo_certs_by_log_total{url=\" %s\" ,operator=\" %s\" }" , url , operatorName )
75+ metrics .GetOrCreateGauge (label , func () float64 {
76+ return float64 (pm .getCertCountForLog (operatorName , url ))
77+ })
78+ }
79+
80+ // UnregisterMetric unregisters a metric with a given label.
81+ func (pm * PrometheusExporter ) UnregisterMetric (label string ) {
82+ metrics .UnregisterMetric (label )
7783}
7884
7985// getCertCountForLog returns the number of certificates processed from a specific CT log.
8086// It caches the result for 5 seconds. Subsequent calls to this method will return the cached result.
81- func getCertCountForLog (operatorName , logname string ) int64 {
82- tempCertMetricsMutex .Lock ()
83- defer tempCertMetricsMutex .Unlock ()
87+ func ( pm * PrometheusExporter ) getCertCountForLog (operatorName , logname string ) int64 {
88+ pm . tempCertMetricsMutex .Lock ()
89+ defer pm . tempCertMetricsMutex .Unlock ()
8490
8591 // Add some caching to avoid having to lock the mutex every time
86- if time .Since (tempCertMetricsLastRefreshed ) > time .Second * 5 {
87- tempCertMetricsLastRefreshed = time .Now ()
88- tempCertMetrics = certificatetransparency . GetCertMetrics ()
92+ if time .Since (pm . tempCertMetricsLastRefreshed ) > time .Second * 5 {
93+ pm . tempCertMetricsLastRefreshed = time .Now ()
94+ pm . tempCertMetrics = GetCertMetrics ()
8995 }
9096
91- return tempCertMetrics [operatorName ][logname ]
92- }
93-
94- // getSkippedCertMetrics gets the number of skipped certificates for each client and creates metrics for it.
95- // It also removes metrics for clients that are not connected anymore.
96- func getSkippedCertMetrics () {
97- skippedCerts := web .ClientHandler .GetSkippedCerts ()
98- for clientName := range skippedCerts {
99- // Get or register a new counter for each client
100- metricName := fmt .Sprintf ("certstreamservergo_skipped_certs{client=\" %s\" }" , clientName )
101- c := metrics .GetOrCreateCounter (metricName )
102- c .Set (skippedCerts [clientName ])
97+ operatorMetrics , ok := pm .tempCertMetrics [operatorName ]
98+ if ! ok {
99+ log .Printf ("No metrics for operator \" %s\" " , operatorName )
100+ return 0
103101 }
104102
105- // Remove all metrics that are not in the list of current client skipped cert metrics
106- // Get a list of current client skipped cert metrics
107- for _ , metricName := range metrics .ListMetricNames () {
108- if ! strings .HasPrefix (metricName , "certstreamservergo_skipped_certs" ) {
109- continue
110- }
111-
112- clientName := strings .TrimPrefix (metricName , "certstreamservergo_skipped_certs{client=\" " )
113- clientName = strings .TrimSuffix (clientName , "\" }" )
114-
115- // Check if the registered metric is in the list of current client skipped cert metrics
116- // If not, unregister the metric
117- _ , exists := skippedCerts [clientName ]
118- if ! exists {
119- metrics .UnregisterMetric (metricName )
120- }
103+ count , ok := operatorMetrics [logname ]
104+ if ! ok {
105+ log .Printf ("No metrics for log \" %s\" of operator \" %s\" " , logname , operatorName )
106+ return 0
121107 }
108+
109+ return count
122110}
0 commit comments