Skip to content

stats/opentelemetry: Cleanup OpenTelemetry API's before stabilization #7874

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}

Check warning on line 75 in stats/metrics.go

View check run for this annotation

Codecov / codecov/patch

stats/metrics.go#L71-L75

Added lines #L71 - L75 were not covered by tests

for _, metric := range metricNames {
delete(newMetrics, metric)
}
return &MetricSet{metrics: newMetrics}

Check warning on line 80 in stats/metrics.go

View check run for this annotation

Codecov / codecov/patch

stats/metrics.go#L77-L80

Added lines #L77 - L80 were not covered by tests
}
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
Loading