zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/extensions/monitoring/extension.go (about) 1 //go:build metrics 2 // +build metrics 3 4 package monitoring 5 6 import ( 7 "path" 8 "time" 9 10 "github.com/prometheus/client_golang/prometheus" 11 "github.com/prometheus/client_golang/prometheus/promauto" 12 13 "zotregistry.io/zot/errors" 14 "zotregistry.io/zot/pkg/log" 15 ) 16 17 const metricsNamespace = "zot" 18 19 var ( 20 httpConnRequests = promauto.NewCounterVec( //nolint: gochecknoglobals 21 prometheus.CounterOpts{ 22 Namespace: metricsNamespace, 23 Name: "http_requests_total", 24 Help: "Total number of http request in zot", 25 }, 26 []string{"method", "code"}, 27 ) 28 httpRepoLatency = promauto.NewSummaryVec( //nolint: gochecknoglobals 29 prometheus.SummaryOpts{ 30 Namespace: metricsNamespace, 31 Name: "http_repo_latency_seconds", 32 Help: "Latency of serving HTTP requests", 33 }, 34 []string{"repo"}, 35 ) 36 httpMethodLatency = promauto.NewHistogramVec( //nolint: gochecknoglobals 37 prometheus.HistogramOpts{ 38 Namespace: metricsNamespace, 39 Name: "http_method_latency_seconds", 40 Help: "Latency of serving HTTP requests", 41 Buckets: GetDefaultBuckets(), 42 }, 43 []string{"method"}, 44 ) 45 repoStorageBytes = promauto.NewGaugeVec( //nolint: gochecknoglobals 46 prometheus.GaugeOpts{ 47 Namespace: metricsNamespace, 48 Name: "repo_storage_bytes", 49 Help: "Storage used per zot repo", 50 }, 51 []string{"repo"}, 52 ) 53 uploadCounter = promauto.NewCounterVec( //nolint: gochecknoglobals 54 prometheus.CounterOpts{ 55 Namespace: metricsNamespace, 56 Name: "repo_uploads_total", 57 Help: "Total number times an image was uploaded", 58 }, 59 []string{"repo"}, 60 ) 61 downloadCounter = promauto.NewCounterVec( //nolint: gochecknoglobals 62 prometheus.CounterOpts{ 63 Namespace: metricsNamespace, 64 Name: "repo_downloads_total", 65 Help: "Total number times an image was downloaded", 66 }, 67 []string{"repo"}, 68 ) 69 serverInfo = promauto.NewGaugeVec( //nolint: gochecknoglobals 70 prometheus.GaugeOpts{ 71 Namespace: metricsNamespace, 72 Name: "info", 73 Help: "Server general information", 74 }, 75 []string{"commit", "binaryType", "goVersion", "version"}, 76 ) 77 storageLockLatency = promauto.NewHistogramVec( //nolint: gochecknoglobals 78 prometheus.HistogramOpts{ 79 Namespace: metricsNamespace, 80 Name: "storage_lock_latency_seconds", 81 Help: "Latency of serving HTTP requests", 82 Buckets: GetStorageLatencyBuckets(), 83 }, 84 []string{"storageName", "lockType"}, 85 ) 86 ) 87 88 type metricServer struct { 89 enabled bool 90 log log.Logger 91 } 92 93 func GetDefaultBuckets() []float64 { 94 return []float64{.05, .5, 1, 5, 30, 60, 600} 95 } 96 97 func GetStorageLatencyBuckets() []float64 { 98 return []float64{.001, .01, 0.1, 1, 5, 10, 15, 30, 60} 99 } 100 101 func NewMetricsServer(enabled bool, log log.Logger) MetricServer { 102 return &metricServer{ 103 enabled: enabled, 104 log: log, 105 } 106 } 107 108 // implementing the MetricServer interface. 109 func (ms *metricServer) SendMetric(mfunc interface{}) { 110 if ms.enabled { 111 mfn, ok := mfunc.(func()) 112 if !ok { 113 ms.log.Error().Err(errors.ErrInvalidMetric).Msg("type conversion") 114 115 return 116 } 117 118 mfn() 119 } 120 } 121 122 func (ms *metricServer) ForceSendMetric(mfunc interface{}) { 123 mfn, ok := mfunc.(func()) 124 if !ok { 125 ms.log.Error().Err(errors.ErrInvalidMetric).Msg("type conversion") 126 127 return 128 } 129 130 mfn() 131 } 132 133 func (ms *metricServer) ReceiveMetrics() interface{} { 134 return nil 135 } 136 137 func (ms *metricServer) IsEnabled() bool { 138 return ms.enabled 139 } 140 141 func IncHTTPConnRequests(ms MetricServer, lvalues ...string) { 142 ms.SendMetric(func() { 143 httpConnRequests.WithLabelValues(lvalues...).Inc() 144 }) 145 } 146 147 func ObserveHTTPRepoLatency(ms MetricServer, path string, latency time.Duration) { 148 ms.SendMetric(func() { 149 match := re.FindStringSubmatch(path) 150 151 if len(match) > 1 { 152 httpRepoLatency.WithLabelValues(match[1]).Observe(latency.Seconds()) 153 } else { 154 httpRepoLatency.WithLabelValues("N/A").Observe(latency.Seconds()) 155 } 156 }) 157 } 158 159 func ObserveHTTPMethodLatency(ms MetricServer, method string, latency time.Duration) { 160 ms.SendMetric(func() { 161 httpMethodLatency.WithLabelValues(method).Observe(latency.Seconds()) 162 }) 163 } 164 165 func IncDownloadCounter(ms MetricServer, repo string) { 166 ms.SendMetric(func() { 167 downloadCounter.WithLabelValues(repo).Inc() 168 }) 169 } 170 171 func SetStorageUsage(ms MetricServer, rootDir, repo string) { 172 ms.SendMetric(func() { 173 dir := path.Join(rootDir, repo) 174 repoSize, err := GetDirSize(dir) 175 176 if err == nil { 177 repoStorageBytes.WithLabelValues(repo).Set(float64(repoSize)) 178 } 179 }) 180 } 181 182 func IncUploadCounter(ms MetricServer, repo string) { 183 ms.SendMetric(func() { 184 uploadCounter.WithLabelValues(repo).Inc() 185 }) 186 } 187 188 func SetServerInfo(ms MetricServer, lvalues ...string) { 189 ms.ForceSendMetric(func() { 190 serverInfo.WithLabelValues(lvalues...).Set(0) 191 }) 192 } 193 194 func ObserveStorageLockLatency(ms MetricServer, latency time.Duration, storageName, lockType string) { 195 ms.SendMetric(func() { 196 storageLockLatency.WithLabelValues(storageName, lockType).Observe(latency.Seconds()) 197 }) 198 }