google.golang.org/grpc@v1.72.2/experimental/stats/metricregistry.go (about) 1 /* 2 * 3 * Copyright 2024 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package stats 20 21 import ( 22 "maps" 23 24 "google.golang.org/grpc/grpclog" 25 "google.golang.org/grpc/internal" 26 "google.golang.org/grpc/stats" 27 ) 28 29 func init() { 30 internal.SnapshotMetricRegistryForTesting = snapshotMetricsRegistryForTesting 31 } 32 33 var logger = grpclog.Component("metrics-registry") 34 35 // DefaultMetrics are the default metrics registered through global metrics 36 // registry. This is written to at initialization time only, and is read only 37 // after initialization. 38 var DefaultMetrics = stats.NewMetricSet() 39 40 // MetricDescriptor is the data for a registered metric. 41 type MetricDescriptor struct { 42 // The name of this metric. This name must be unique across the whole binary 43 // (including any per call metrics). See 44 // https://github.com/grpc/proposal/blob/master/A79-non-per-call-metrics-architecture.md#metric-instrument-naming-conventions 45 // for metric naming conventions. 46 Name string 47 // The description of this metric. 48 Description string 49 // The unit (e.g. entries, seconds) of this metric. 50 Unit string 51 // The required label keys for this metric. These are intended to 52 // metrics emitted from a stats handler. 53 Labels []string 54 // The optional label keys for this metric. These are intended to attached 55 // to metrics emitted from a stats handler if configured. 56 OptionalLabels []string 57 // Whether this metric is on by default. 58 Default bool 59 // The type of metric. This is set by the metric registry, and not intended 60 // to be set by a component registering a metric. 61 Type MetricType 62 // Bounds are the bounds of this metric. This only applies to histogram 63 // metrics. If unset or set with length 0, stats handlers will fall back to 64 // default bounds. 65 Bounds []float64 66 } 67 68 // MetricType is the type of metric. 69 type MetricType int 70 71 // Type of metric supported by this instrument registry. 72 const ( 73 MetricTypeIntCount MetricType = iota 74 MetricTypeFloatCount 75 MetricTypeIntHisto 76 MetricTypeFloatHisto 77 MetricTypeIntGauge 78 ) 79 80 // Int64CountHandle is a typed handle for a int count metric. This handle 81 // is passed at the recording point in order to know which metric to record 82 // on. 83 type Int64CountHandle MetricDescriptor 84 85 // Descriptor returns the int64 count handle typecast to a pointer to a 86 // MetricDescriptor. 87 func (h *Int64CountHandle) Descriptor() *MetricDescriptor { 88 return (*MetricDescriptor)(h) 89 } 90 91 // Record records the int64 count value on the metrics recorder provided. 92 func (h *Int64CountHandle) Record(recorder MetricsRecorder, incr int64, labels ...string) { 93 recorder.RecordInt64Count(h, incr, labels...) 94 } 95 96 // Float64CountHandle is a typed handle for a float count metric. This handle is 97 // passed at the recording point in order to know which metric to record on. 98 type Float64CountHandle MetricDescriptor 99 100 // Descriptor returns the float64 count handle typecast to a pointer to a 101 // MetricDescriptor. 102 func (h *Float64CountHandle) Descriptor() *MetricDescriptor { 103 return (*MetricDescriptor)(h) 104 } 105 106 // Record records the float64 count value on the metrics recorder provided. 107 func (h *Float64CountHandle) Record(recorder MetricsRecorder, incr float64, labels ...string) { 108 recorder.RecordFloat64Count(h, incr, labels...) 109 } 110 111 // Int64HistoHandle is a typed handle for an int histogram metric. This handle 112 // is passed at the recording point in order to know which metric to record on. 113 type Int64HistoHandle MetricDescriptor 114 115 // Descriptor returns the int64 histo handle typecast to a pointer to a 116 // MetricDescriptor. 117 func (h *Int64HistoHandle) Descriptor() *MetricDescriptor { 118 return (*MetricDescriptor)(h) 119 } 120 121 // Record records the int64 histo value on the metrics recorder provided. 122 func (h *Int64HistoHandle) Record(recorder MetricsRecorder, incr int64, labels ...string) { 123 recorder.RecordInt64Histo(h, incr, labels...) 124 } 125 126 // Float64HistoHandle is a typed handle for a float histogram metric. This 127 // handle is passed at the recording point in order to know which metric to 128 // record on. 129 type Float64HistoHandle MetricDescriptor 130 131 // Descriptor returns the float64 histo handle typecast to a pointer to a 132 // MetricDescriptor. 133 func (h *Float64HistoHandle) Descriptor() *MetricDescriptor { 134 return (*MetricDescriptor)(h) 135 } 136 137 // Record records the float64 histo value on the metrics recorder provided. 138 func (h *Float64HistoHandle) Record(recorder MetricsRecorder, incr float64, labels ...string) { 139 recorder.RecordFloat64Histo(h, incr, labels...) 140 } 141 142 // Int64GaugeHandle is a typed handle for an int gauge metric. This handle is 143 // passed at the recording point in order to know which metric to record on. 144 type Int64GaugeHandle MetricDescriptor 145 146 // Descriptor returns the int64 gauge handle typecast to a pointer to a 147 // MetricDescriptor. 148 func (h *Int64GaugeHandle) Descriptor() *MetricDescriptor { 149 return (*MetricDescriptor)(h) 150 } 151 152 // Record records the int64 histo value on the metrics recorder provided. 153 func (h *Int64GaugeHandle) Record(recorder MetricsRecorder, incr int64, labels ...string) { 154 recorder.RecordInt64Gauge(h, incr, labels...) 155 } 156 157 // registeredMetrics are the registered metric descriptor names. 158 var registeredMetrics = make(map[string]bool) 159 160 // metricsRegistry contains all of the registered metrics. 161 // 162 // This is written to only at init time, and read only after that. 163 var metricsRegistry = make(map[string]*MetricDescriptor) 164 165 // DescriptorForMetric returns the MetricDescriptor from the global registry. 166 // 167 // Returns nil if MetricDescriptor not present. 168 func DescriptorForMetric(metricName string) *MetricDescriptor { 169 return metricsRegistry[metricName] 170 } 171 172 func registerMetric(metricName string, def bool) { 173 if registeredMetrics[metricName] { 174 logger.Fatalf("metric %v already registered", metricName) 175 } 176 registeredMetrics[metricName] = true 177 if def { 178 DefaultMetrics = DefaultMetrics.Add(metricName) 179 } 180 } 181 182 // RegisterInt64Count registers the metric description onto the global registry. 183 // It returns a typed handle to use to recording data. 184 // 185 // NOTE: this function must only be called during initialization time (i.e. in 186 // an init() function), and is not thread-safe. If multiple metrics are 187 // registered with the same name, this function will panic. 188 func RegisterInt64Count(descriptor MetricDescriptor) *Int64CountHandle { 189 registerMetric(descriptor.Name, descriptor.Default) 190 descriptor.Type = MetricTypeIntCount 191 descPtr := &descriptor 192 metricsRegistry[descriptor.Name] = descPtr 193 return (*Int64CountHandle)(descPtr) 194 } 195 196 // RegisterFloat64Count registers the metric description onto the global 197 // registry. It returns a typed handle to use to recording data. 198 // 199 // NOTE: this function must only be called during initialization time (i.e. in 200 // an init() function), and is not thread-safe. If multiple metrics are 201 // registered with the same name, this function will panic. 202 func RegisterFloat64Count(descriptor MetricDescriptor) *Float64CountHandle { 203 registerMetric(descriptor.Name, descriptor.Default) 204 descriptor.Type = MetricTypeFloatCount 205 descPtr := &descriptor 206 metricsRegistry[descriptor.Name] = descPtr 207 return (*Float64CountHandle)(descPtr) 208 } 209 210 // RegisterInt64Histo registers the metric description onto the global registry. 211 // It returns a typed handle to use to recording data. 212 // 213 // NOTE: this function must only be called during initialization time (i.e. in 214 // an init() function), and is not thread-safe. If multiple metrics are 215 // registered with the same name, this function will panic. 216 func RegisterInt64Histo(descriptor MetricDescriptor) *Int64HistoHandle { 217 registerMetric(descriptor.Name, descriptor.Default) 218 descriptor.Type = MetricTypeIntHisto 219 descPtr := &descriptor 220 metricsRegistry[descriptor.Name] = descPtr 221 return (*Int64HistoHandle)(descPtr) 222 } 223 224 // RegisterFloat64Histo registers the metric description onto the global 225 // registry. It returns a typed handle to use to recording data. 226 // 227 // NOTE: this function must only be called during initialization time (i.e. in 228 // an init() function), and is not thread-safe. If multiple metrics are 229 // registered with the same name, this function will panic. 230 func RegisterFloat64Histo(descriptor MetricDescriptor) *Float64HistoHandle { 231 registerMetric(descriptor.Name, descriptor.Default) 232 descriptor.Type = MetricTypeFloatHisto 233 descPtr := &descriptor 234 metricsRegistry[descriptor.Name] = descPtr 235 return (*Float64HistoHandle)(descPtr) 236 } 237 238 // RegisterInt64Gauge registers the metric description onto the global registry. 239 // It returns a typed handle to use to recording data. 240 // 241 // NOTE: this function must only be called during initialization time (i.e. in 242 // an init() function), and is not thread-safe. If multiple metrics are 243 // registered with the same name, this function will panic. 244 func RegisterInt64Gauge(descriptor MetricDescriptor) *Int64GaugeHandle { 245 registerMetric(descriptor.Name, descriptor.Default) 246 descriptor.Type = MetricTypeIntGauge 247 descPtr := &descriptor 248 metricsRegistry[descriptor.Name] = descPtr 249 return (*Int64GaugeHandle)(descPtr) 250 } 251 252 // snapshotMetricsRegistryForTesting snapshots the global data of the metrics 253 // registry. Returns a cleanup function that sets the metrics registry to its 254 // original state. 255 func snapshotMetricsRegistryForTesting() func() { 256 oldDefaultMetrics := DefaultMetrics 257 oldRegisteredMetrics := registeredMetrics 258 oldMetricsRegistry := metricsRegistry 259 260 registeredMetrics = make(map[string]bool) 261 metricsRegistry = make(map[string]*MetricDescriptor) 262 maps.Copy(registeredMetrics, registeredMetrics) 263 maps.Copy(metricsRegistry, metricsRegistry) 264 265 return func() { 266 DefaultMetrics = oldDefaultMetrics 267 registeredMetrics = oldRegisteredMetrics 268 metricsRegistry = oldMetricsRegistry 269 } 270 }