Skip to content

Commit

Permalink
stats/opentelemetry: Cleanup OpenTelemetry API's before stabilization (
Browse files Browse the repository at this point in the history
…#7874)

Co-authored-by: Doug Fawley <[email protected]>
  • Loading branch information
zasweq and dfawley authored Dec 2, 2024
1 parent 4c07bca commit 3c0586a
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 142 deletions.
27 changes: 14 additions & 13 deletions experimental/stats/metricregistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/internal"
"google.golang.org/grpc/stats"
)

func init() {
Expand All @@ -34,15 +35,15 @@ var logger = grpclog.Component("metrics-registry")
// DefaultMetrics are the default metrics registered through global metrics
// registry. This is written to at initialization time only, and is read only
// after initialization.
var DefaultMetrics = NewMetrics()
var DefaultMetrics = stats.NewMetricSet()

// MetricDescriptor is the data for a registered metric.
type MetricDescriptor struct {
// The name of this metric. This name must be unique across the whole binary
// (including any per call metrics). See
// https://github.com/grpc/proposal/blob/master/A79-non-per-call-metrics-architecture.md#metric-instrument-naming-conventions
// for metric naming conventions.
Name Metric
Name string
// The description of this metric.
Description string
// The unit (e.g. entries, seconds) of this metric.
Expand Down Expand Up @@ -154,27 +155,27 @@ func (h *Int64GaugeHandle) Record(recorder MetricsRecorder, incr int64, labels .
}

// registeredMetrics are the registered metric descriptor names.
var registeredMetrics = make(map[Metric]bool)
var registeredMetrics = make(map[string]bool)

// metricsRegistry contains all of the registered metrics.
//
// This is written to only at init time, and read only after that.
var metricsRegistry = make(map[Metric]*MetricDescriptor)
var metricsRegistry = make(map[string]*MetricDescriptor)

// DescriptorForMetric returns the MetricDescriptor from the global registry.
//
// Returns nil if MetricDescriptor not present.
func DescriptorForMetric(metric Metric) *MetricDescriptor {
return metricsRegistry[metric]
func DescriptorForMetric(metricName string) *MetricDescriptor {
return metricsRegistry[metricName]
}

func registerMetric(name Metric, def bool) {
if registeredMetrics[name] {
logger.Fatalf("metric %v already registered", name)
func registerMetric(metricName string, def bool) {
if registeredMetrics[metricName] {
logger.Fatalf("metric %v already registered", metricName)
}
registeredMetrics[name] = true
registeredMetrics[metricName] = true
if def {
DefaultMetrics = DefaultMetrics.Add(name)
DefaultMetrics = DefaultMetrics.Add(metricName)
}
}

Expand Down Expand Up @@ -256,8 +257,8 @@ func snapshotMetricsRegistryForTesting() func() {
oldRegisteredMetrics := registeredMetrics
oldMetricsRegistry := metricsRegistry

registeredMetrics = make(map[Metric]bool)
metricsRegistry = make(map[Metric]*MetricDescriptor)
registeredMetrics = make(map[string]bool)
metricsRegistry = make(map[string]*MetricDescriptor)
maps.Copy(registeredMetrics, registeredMetrics)
maps.Copy(metricsRegistry, metricsRegistry)

Expand Down
75 changes: 0 additions & 75 deletions experimental/stats/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
// Package stats contains experimental metrics/stats API's.
package stats

import "maps"

// MetricsRecorder records on metrics derived from metric registry.
type MetricsRecorder interface {
// RecordInt64Count records the measurement alongside labels on the int
Expand All @@ -39,76 +37,3 @@ type MetricsRecorder interface {
// gauge associated with the provided handle.
RecordInt64Gauge(handle *Int64GaugeHandle, incr int64, labels ...string)
}

// Metric is an identifier for a metric.
type Metric string

// Metrics is a set of metrics to record. Once created, Metrics is immutable,
// however Add and Remove can make copies with specific metrics added or
// removed, respectively.
//
// Do not construct directly; use NewMetrics instead.
type Metrics struct {
// metrics are the set of metrics to initialize.
metrics map[Metric]bool
}

// NewMetrics returns a Metrics containing Metrics.
func NewMetrics(metrics ...Metric) *Metrics {
newMetrics := make(map[Metric]bool)
for _, metric := range metrics {
newMetrics[metric] = true
}
return &Metrics{
metrics: newMetrics,
}
}

// Metrics returns the metrics set. The returned map is read-only and must not
// be modified.
func (m *Metrics) Metrics() map[Metric]bool {
return m.metrics
}

// Add adds the metrics to the metrics set and returns a new copy with the
// additional metrics.
func (m *Metrics) Add(metrics ...Metric) *Metrics {
newMetrics := make(map[Metric]bool)
for metric := range m.metrics {
newMetrics[metric] = true
}

for _, metric := range metrics {
newMetrics[metric] = true
}
return &Metrics{
metrics: newMetrics,
}
}

// Join joins the metrics passed in with the metrics set, and returns a new copy
// with the merged metrics.
func (m *Metrics) Join(metrics *Metrics) *Metrics {
newMetrics := make(map[Metric]bool)
maps.Copy(newMetrics, m.metrics)
maps.Copy(newMetrics, metrics.metrics)
return &Metrics{
metrics: newMetrics,
}
}

// Remove removes the metrics from the metrics set and returns a new copy with
// the metrics removed.
func (m *Metrics) Remove(metrics ...Metric) *Metrics {
newMetrics := make(map[Metric]bool)
for metric := range m.metrics {
newMetrics[metric] = true
}

for _, metric := range metrics {
delete(newMetrics, metric)
}
return &Metrics{
metrics: newMetrics,
}
}
8 changes: 4 additions & 4 deletions internal/testutils/stats/test_metrics_recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type TestMetricsRecorder struct {
// mu protects data.
mu sync.Mutex
// data is the most recent update for each metric name.
data map[estats.Metric]float64
data map[string]float64
}

// NewTestMetricsRecorder returns a new TestMetricsRecorder.
Expand All @@ -56,7 +56,7 @@ func NewTestMetricsRecorder() *TestMetricsRecorder {
floatHistoCh: testutils.NewChannelWithSize(10),
intGaugeCh: testutils.NewChannelWithSize(10),

data: make(map[estats.Metric]float64),
data: make(map[string]float64),
}
}

Expand All @@ -65,15 +65,15 @@ func NewTestMetricsRecorder() *TestMetricsRecorder {
func (r *TestMetricsRecorder) Metric(name string) (float64, bool) {
r.mu.Lock()
defer r.mu.Unlock()
data, ok := r.data[estats.Metric(name)]
data, ok := r.data[name]
return data, ok
}

// ClearMetrics clears the metrics data store of the test metrics recorder.
func (r *TestMetricsRecorder) ClearMetrics() {
r.mu.Lock()
defer r.mu.Unlock()
r.data = make(map[estats.Metric]float64)
r.data = make(map[string]float64)
}

// MetricsData represents data associated with a metric.
Expand Down
81 changes: 81 additions & 0 deletions stats/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright 2024 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package stats

import "maps"

// MetricSet is a set of metrics to record. Once created, MetricSet is immutable,
// however Add and Remove can make copies with specific metrics added or
// removed, respectively.
//
// Do not construct directly; use NewMetricSet instead.
type MetricSet struct {
// metrics are the set of metrics to initialize.
metrics map[string]bool
}

// NewMetricSet returns a MetricSet containing metricNames.
func NewMetricSet(metricNames ...string) *MetricSet {
newMetrics := make(map[string]bool)
for _, metric := range metricNames {
newMetrics[metric] = true
}
return &MetricSet{metrics: newMetrics}
}

// Metrics returns the metrics set. The returned map is read-only and must not
// be modified.
func (m *MetricSet) Metrics() map[string]bool {
return m.metrics
}

// Add adds the metricNames to the metrics set and returns a new copy with the
// additional metrics.
func (m *MetricSet) Add(metricNames ...string) *MetricSet {
newMetrics := make(map[string]bool)
for metric := range m.metrics {
newMetrics[metric] = true
}

for _, metric := range metricNames {
newMetrics[metric] = true
}
return &MetricSet{metrics: newMetrics}
}

// Join joins the metrics passed in with the metrics set, and returns a new copy
// with the merged metrics.
func (m *MetricSet) Join(metrics *MetricSet) *MetricSet {
newMetrics := make(map[string]bool)
maps.Copy(newMetrics, m.metrics)
maps.Copy(newMetrics, metrics.metrics)
return &MetricSet{metrics: newMetrics}
}

// Remove removes the metricNames from the metrics set and returns a new copy
// with the metrics removed.
func (m *MetricSet) Remove(metricNames ...string) *MetricSet {
newMetrics := make(map[string]bool)
for metric := range m.metrics {
newMetrics[metric] = true
}

for _, metric := range metricNames {
delete(newMetrics, metric)
}
return &MetricSet{metrics: newMetrics}
}
29 changes: 15 additions & 14 deletions stats/opentelemetry/client_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,18 +260,19 @@ func (h *clientStatsHandler) processRPCEnd(ctx context.Context, ai *attemptInfo,
}

const (
// ClientAttemptStarted is the number of client call attempts started.
ClientAttemptStarted estats.Metric = "grpc.client.attempt.started"
// ClientAttemptDuration is the end-to-end time taken to complete a client
// call attempt.
ClientAttemptDuration estats.Metric = "grpc.client.attempt.duration"
// ClientAttemptSentCompressedTotalMessageSize is the compressed message
// bytes sent per client call attempt.
ClientAttemptSentCompressedTotalMessageSize estats.Metric = "grpc.client.attempt.sent_total_compressed_message_size"
// ClientAttemptRcvdCompressedTotalMessageSize is the compressed message
// bytes received per call attempt.
ClientAttemptRcvdCompressedTotalMessageSize estats.Metric = "grpc.client.attempt.rcvd_total_compressed_message_size"
// ClientCallDuration is the time taken by gRPC to complete an RPC from
// application's perspective.
ClientCallDuration estats.Metric = "grpc.client.call.duration"
// ClientAttemptStartedMetricName is the number of client call attempts
// started.
ClientAttemptStartedMetricName string = "grpc.client.attempt.started"
// ClientAttemptDurationMetricName is the end-to-end time taken to complete
// a client call attempt.
ClientAttemptDurationMetricName string = "grpc.client.attempt.duration"
// ClientAttemptSentCompressedTotalMessageSizeMetricName is the compressed
// message bytes sent per client call attempt.
ClientAttemptSentCompressedTotalMessageSizeMetricName string = "grpc.client.attempt.sent_total_compressed_message_size"
// ClientAttemptRcvdCompressedTotalMessageSizeMetricName is the compressed
// message bytes received per call attempt.
ClientAttemptRcvdCompressedTotalMessageSizeMetricName string = "grpc.client.attempt.rcvd_total_compressed_message_size"
// ClientCallDurationMetricName is the time taken by gRPC to complete an RPC
// from application's perspective.
ClientCallDurationMetricName string = "grpc.client.call.duration"
)
8 changes: 4 additions & 4 deletions stats/opentelemetry/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package opentelemetry_test
import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
estats "google.golang.org/grpc/experimental/stats"
"google.golang.org/grpc/stats"
"google.golang.org/grpc/stats/opentelemetry"

"go.opentelemetry.io/otel/sdk/metric"
Expand Down Expand Up @@ -88,7 +88,7 @@ func ExampleMetrics_excludeSome() {
// To exclude specific metrics, initialize Options as follows:
opts := opentelemetry.Options{
MetricsOptions: opentelemetry.MetricsOptions{
Metrics: opentelemetry.DefaultMetrics().Remove(opentelemetry.ClientAttemptDuration, opentelemetry.ClientAttemptRcvdCompressedTotalMessageSize),
Metrics: opentelemetry.DefaultMetrics().Remove(opentelemetry.ClientAttemptDurationMetricName, opentelemetry.ClientAttemptRcvdCompressedTotalMessageSizeMetricName),
},
}
do := opentelemetry.DialOption(opts)
Expand All @@ -103,7 +103,7 @@ func ExampleMetrics_disableAll() {
// To disable all metrics, initialize Options as follows:
opts := opentelemetry.Options{
MetricsOptions: opentelemetry.MetricsOptions{
Metrics: estats.NewMetrics(), // Distinct to nil, which creates default metrics. This empty set creates no metrics.
Metrics: stats.NewMetricSet(), // Distinct to nil, which creates default metrics. This empty set creates no metrics.
},
}
do := opentelemetry.DialOption(opts)
Expand All @@ -118,7 +118,7 @@ func ExampleMetrics_enableSome() {
// To only create specific metrics, initialize Options as follows:
opts := opentelemetry.Options{
MetricsOptions: opentelemetry.MetricsOptions{
Metrics: estats.NewMetrics(opentelemetry.ClientAttemptDuration, opentelemetry.ClientAttemptRcvdCompressedTotalMessageSize), // only create these metrics
Metrics: stats.NewMetricSet(opentelemetry.ClientAttemptDurationMetricName, opentelemetry.ClientAttemptRcvdCompressedTotalMessageSizeMetricName), // only create these metrics
},
}
do := opentelemetry.DialOption(opts)
Expand Down
Loading

0 comments on commit 3c0586a

Please sign in to comment.