blob: 2b57ba65a390770520c18b8a79c94fb7e3db4c4a [file] [log] [blame]
balaji.nagarajan8a2a7ee2026-06-19 22:31:13 +05301/*
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
19package stats
20
21import (
22 "maps"
23
24 "google.golang.org/grpc/grpclog"
25 "google.golang.org/grpc/internal"
26 "google.golang.org/grpc/stats"
27)
28
29func init() {
30 internal.SnapshotMetricRegistryForTesting = snapshotMetricsRegistryForTesting
31}
32
33var 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.
38var DefaultMetrics = stats.NewMetricSet()
39
40// MetricDescriptor is the data for a registered metric.
41type 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.
69type MetricType int
70
71// Type of metric supported by this instrument registry.
72const (
73 MetricTypeIntCount MetricType = iota
74 MetricTypeFloatCount
75 MetricTypeIntHisto
76 MetricTypeFloatHisto
77 MetricTypeIntGauge
78 MetricTypeIntUpDownCount
79)
80
81// Int64CountHandle is a typed handle for a int count metric. This handle
82// is passed at the recording point in order to know which metric to record
83// on.
84type Int64CountHandle MetricDescriptor
85
86// Descriptor returns the int64 count handle typecast to a pointer to a
87// MetricDescriptor.
88func (h *Int64CountHandle) Descriptor() *MetricDescriptor {
89 return (*MetricDescriptor)(h)
90}
91
92// Record records the int64 count value on the metrics recorder provided.
93func (h *Int64CountHandle) Record(recorder MetricsRecorder, incr int64, labels ...string) {
94 recorder.RecordInt64Count(h, incr, labels...)
95}
96
97// Int64UpDownCountHandle is a typed handle for an int up-down counter metric.
98// This handle is passed at the recording point in order to know which metric
99// to record on.
100type Int64UpDownCountHandle MetricDescriptor
101
102// Descriptor returns the int64 up-down counter handle typecast to a pointer to a
103// MetricDescriptor.
104func (h *Int64UpDownCountHandle) Descriptor() *MetricDescriptor {
105 return (*MetricDescriptor)(h)
106}
107
108// Record records the int64 up-down counter value on the metrics recorder provided.
109// The value 'v' can be positive to increment or negative to decrement.
110func (h *Int64UpDownCountHandle) Record(recorder MetricsRecorder, v int64, labels ...string) {
111 recorder.RecordInt64UpDownCount(h, v, labels...)
112}
113
114// Float64CountHandle is a typed handle for a float count metric. This handle is
115// passed at the recording point in order to know which metric to record on.
116type Float64CountHandle MetricDescriptor
117
118// Descriptor returns the float64 count handle typecast to a pointer to a
119// MetricDescriptor.
120func (h *Float64CountHandle) Descriptor() *MetricDescriptor {
121 return (*MetricDescriptor)(h)
122}
123
124// Record records the float64 count value on the metrics recorder provided.
125func (h *Float64CountHandle) Record(recorder MetricsRecorder, incr float64, labels ...string) {
126 recorder.RecordFloat64Count(h, incr, labels...)
127}
128
129// Int64HistoHandle is a typed handle for an int histogram metric. This handle
130// is passed at the recording point in order to know which metric to record on.
131type Int64HistoHandle MetricDescriptor
132
133// Descriptor returns the int64 histo handle typecast to a pointer to a
134// MetricDescriptor.
135func (h *Int64HistoHandle) Descriptor() *MetricDescriptor {
136 return (*MetricDescriptor)(h)
137}
138
139// Record records the int64 histo value on the metrics recorder provided.
140func (h *Int64HistoHandle) Record(recorder MetricsRecorder, incr int64, labels ...string) {
141 recorder.RecordInt64Histo(h, incr, labels...)
142}
143
144// Float64HistoHandle is a typed handle for a float histogram metric. This
145// handle is passed at the recording point in order to know which metric to
146// record on.
147type Float64HistoHandle MetricDescriptor
148
149// Descriptor returns the float64 histo handle typecast to a pointer to a
150// MetricDescriptor.
151func (h *Float64HistoHandle) Descriptor() *MetricDescriptor {
152 return (*MetricDescriptor)(h)
153}
154
155// Record records the float64 histo value on the metrics recorder provided.
156func (h *Float64HistoHandle) Record(recorder MetricsRecorder, incr float64, labels ...string) {
157 recorder.RecordFloat64Histo(h, incr, labels...)
158}
159
160// Int64GaugeHandle is a typed handle for an int gauge metric. This handle is
161// passed at the recording point in order to know which metric to record on.
162type Int64GaugeHandle MetricDescriptor
163
164// Descriptor returns the int64 gauge handle typecast to a pointer to a
165// MetricDescriptor.
166func (h *Int64GaugeHandle) Descriptor() *MetricDescriptor {
167 return (*MetricDescriptor)(h)
168}
169
170// Record records the int64 histo value on the metrics recorder provided.
171func (h *Int64GaugeHandle) Record(recorder MetricsRecorder, incr int64, labels ...string) {
172 recorder.RecordInt64Gauge(h, incr, labels...)
173}
174
175// registeredMetrics are the registered metric descriptor names.
176var registeredMetrics = make(map[string]bool)
177
178// metricsRegistry contains all of the registered metrics.
179//
180// This is written to only at init time, and read only after that.
181var metricsRegistry = make(map[string]*MetricDescriptor)
182
183// DescriptorForMetric returns the MetricDescriptor from the global registry.
184//
185// Returns nil if MetricDescriptor not present.
186func DescriptorForMetric(metricName string) *MetricDescriptor {
187 return metricsRegistry[metricName]
188}
189
190func registerMetric(metricName string, def bool) {
191 if registeredMetrics[metricName] {
192 logger.Fatalf("metric %v already registered", metricName)
193 }
194 registeredMetrics[metricName] = true
195 if def {
196 DefaultMetrics = DefaultMetrics.Add(metricName)
197 }
198}
199
200// RegisterInt64Count registers the metric description onto the global registry.
201// It returns a typed handle to use to recording data.
202//
203// NOTE: this function must only be called during initialization time (i.e. in
204// an init() function), and is not thread-safe. If multiple metrics are
205// registered with the same name, this function will panic.
206func RegisterInt64Count(descriptor MetricDescriptor) *Int64CountHandle {
207 registerMetric(descriptor.Name, descriptor.Default)
208 descriptor.Type = MetricTypeIntCount
209 descPtr := &descriptor
210 metricsRegistry[descriptor.Name] = descPtr
211 return (*Int64CountHandle)(descPtr)
212}
213
214// RegisterFloat64Count registers the metric description onto the global
215// registry. It returns a typed handle to use to recording data.
216//
217// NOTE: this function must only be called during initialization time (i.e. in
218// an init() function), and is not thread-safe. If multiple metrics are
219// registered with the same name, this function will panic.
220func RegisterFloat64Count(descriptor MetricDescriptor) *Float64CountHandle {
221 registerMetric(descriptor.Name, descriptor.Default)
222 descriptor.Type = MetricTypeFloatCount
223 descPtr := &descriptor
224 metricsRegistry[descriptor.Name] = descPtr
225 return (*Float64CountHandle)(descPtr)
226}
227
228// RegisterInt64Histo registers the metric description onto the global registry.
229// It returns a typed handle to use to recording data.
230//
231// NOTE: this function must only be called during initialization time (i.e. in
232// an init() function), and is not thread-safe. If multiple metrics are
233// registered with the same name, this function will panic.
234func RegisterInt64Histo(descriptor MetricDescriptor) *Int64HistoHandle {
235 registerMetric(descriptor.Name, descriptor.Default)
236 descriptor.Type = MetricTypeIntHisto
237 descPtr := &descriptor
238 metricsRegistry[descriptor.Name] = descPtr
239 return (*Int64HistoHandle)(descPtr)
240}
241
242// RegisterFloat64Histo registers the metric description onto the global
243// registry. It returns a typed handle to use to recording data.
244//
245// NOTE: this function must only be called during initialization time (i.e. in
246// an init() function), and is not thread-safe. If multiple metrics are
247// registered with the same name, this function will panic.
248func RegisterFloat64Histo(descriptor MetricDescriptor) *Float64HistoHandle {
249 registerMetric(descriptor.Name, descriptor.Default)
250 descriptor.Type = MetricTypeFloatHisto
251 descPtr := &descriptor
252 metricsRegistry[descriptor.Name] = descPtr
253 return (*Float64HistoHandle)(descPtr)
254}
255
256// RegisterInt64Gauge registers the metric description onto the global registry.
257// It returns a typed handle to use to recording data.
258//
259// NOTE: this function must only be called during initialization time (i.e. in
260// an init() function), and is not thread-safe. If multiple metrics are
261// registered with the same name, this function will panic.
262func RegisterInt64Gauge(descriptor MetricDescriptor) *Int64GaugeHandle {
263 registerMetric(descriptor.Name, descriptor.Default)
264 descriptor.Type = MetricTypeIntGauge
265 descPtr := &descriptor
266 metricsRegistry[descriptor.Name] = descPtr
267 return (*Int64GaugeHandle)(descPtr)
268}
269
270// RegisterInt64UpDownCount registers the metric description onto the global registry.
271// It returns a typed handle to use for recording data.
272//
273// NOTE: this function must only be called during initialization time (i.e. in
274// an init() function), and is not thread-safe. If multiple metrics are
275// registered with the same name, this function will panic.
276func RegisterInt64UpDownCount(descriptor MetricDescriptor) *Int64UpDownCountHandle {
277 registerMetric(descriptor.Name, descriptor.Default)
278 // Set the specific metric type for the up-down counter
279 descriptor.Type = MetricTypeIntUpDownCount
280 descPtr := &descriptor
281 metricsRegistry[descriptor.Name] = descPtr
282 return (*Int64UpDownCountHandle)(descPtr)
283}
284
285// snapshotMetricsRegistryForTesting snapshots the global data of the metrics
286// registry. Returns a cleanup function that sets the metrics registry to its
287// original state.
288func snapshotMetricsRegistryForTesting() func() {
289 oldDefaultMetrics := DefaultMetrics
290 oldRegisteredMetrics := registeredMetrics
291 oldMetricsRegistry := metricsRegistry
292
293 registeredMetrics = make(map[string]bool)
294 metricsRegistry = make(map[string]*MetricDescriptor)
295 maps.Copy(registeredMetrics, registeredMetrics)
296 maps.Copy(metricsRegistry, metricsRegistry)
297
298 return func() {
299 DefaultMetrics = oldDefaultMetrics
300 registeredMetrics = oldRegisteredMetrics
301 metricsRegistry = oldMetricsRegistry
302 }
303}