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  }