Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Add unmarshaling and validation for `OTLPHttpExporter`, `OTLPGrpcExporter`, `OTLPGrpcMetricExporter` and `OTLPHttpMetricExporter` to v1.0.0 model in `go.opentelemetry.io/contrib/otelconf`. (#8112)
- Add a `WithSpanNameFormatter` option to `go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo`. (#7986)
- Add unmarshaling and validation for `AttributeType`, `AttributeNameValue`, `SimpleSpanProcessor`, `SimpleLogRecordProcessor`, `ZipkinSpanExporter`, `NameStringValuePair`, `InstrumentType`, `ExperimentalPeerInstrumentationServiceMappingElem`, `ExporterDefaultHistogramAggregation`, `PullMetricReader` to v1.0.0 model in `go.opentelemetry.io/contrib/otelconf`. (#8127)
- `WithMetricAttributesFn` option in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` to define dynamic attributes on auto-instrumented metrics. (#8191)

### Changed

Expand Down
32 changes: 24 additions & 8 deletions instrumentation/google.golang.org/grpc/otelgrpc/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,15 @@ type Filter func(*stats.RPCTagInfo) bool

// config is a group of options for this instrumentation.
type config struct {
Filter Filter
InterceptorFilter InterceptorFilter
Propagators propagation.TextMapPropagator
TracerProvider trace.TracerProvider
MeterProvider metric.MeterProvider
SpanStartOptions []trace.SpanStartOption
SpanAttributes []attribute.KeyValue
MetricAttributes []attribute.KeyValue
Filter Filter
InterceptorFilter InterceptorFilter
Propagators propagation.TextMapPropagator
TracerProvider trace.TracerProvider
MeterProvider metric.MeterProvider
SpanStartOptions []trace.SpanStartOption
SpanAttributes []attribute.KeyValue
MetricAttributes []attribute.KeyValue
MetricAttributesFn func(ctx context.Context) []attribute.KeyValue

PublicEndpoint bool
PublicEndpointFn func(ctx context.Context, info *stats.RPCTagInfo) bool
Expand Down Expand Up @@ -193,3 +194,18 @@ func WithMetricAttributes(a ...attribute.KeyValue) Option {
}
})
}

type metricAttributesFnOption struct {
fn func(ctx context.Context) []attribute.KeyValue
}

func (o metricAttributesFnOption) apply(c *config) {
if o.fn != nil {
c.MetricAttributesFn = o.fn
}
}

// WithMetricAttributesFn returns an Option to add custom attributes to the metrics.
func WithMetricAttributesFn(fn func(ctx context.Context) []attribute.KeyValue) Option {
return metricAttributesFnOption{fn: fn}
}
49 changes: 49 additions & 0 deletions instrumentation/google.golang.org/grpc/otelgrpc/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
package otelgrpc_test

import (
"context"

"go.opentelemetry.io/otel/attribute"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"

"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
)
Expand All @@ -16,3 +20,48 @@ func ExampleNewClientHandler() {
func ExampleNewServerHandler() {
_ = grpc.NewServer(grpc.StatsHandler(otelgrpc.NewServerHandler()))
}

// ExampleNewClientHandler_withMetricAttributesFn demonstrates how to add a dynamic
// client-side attribute to the auto-instrumented metrics.
func ExampleNewClientHandler_withMetricAttributesFn() {
// should be centralized, example only
type retryAttemptKey struct{}

// a middleware must populate that key with the actual retry attempt, e.g.,
// ...
// ctx := context.WithValue(context.Background(), retryAttemptKey{}, attempt)
// ...

_, _ = grpc.NewClient("localhost", grpc.WithStatsHandler(otelgrpc.NewClientHandler(
otelgrpc.WithMetricAttributesFn(func(ctx context.Context) []attribute.KeyValue {
if attempt, ok := ctx.Value(retryAttemptKey{}).(int); ok {
return []attribute.KeyValue{
// Caution: example only.
// This must be a controlled, bounded and very limited set of numbers
// so that you don't end up with very high cardinality.
attribute.Int("retry.attempt", attempt),
}
}

return nil
}),
)))
}

// ExampleNewClientHandler_withMetricAttributesFn demonstrates how to add a dynamic
// server-side attribute to the auto-instrumented metrics.
func ExampleNewServerHandler_withMetricAttributesFn() {
_ = grpc.NewServer(grpc.StatsHandler(otelgrpc.NewServerHandler(
otelgrpc.WithMetricAttributesFn(func(ctx context.Context) []attribute.KeyValue {
md, ok := metadata.FromIncomingContext(ctx)
if ok {
if origins := md.Get("origin"); len(origins) > 0 && origins[0] != "" {
return []attribute.KeyValue{attribute.String("origin", origins[0])}
}
}

// Some use-cases might require to fallback to a default.
return []attribute.KeyValue{attribute.String("origin", "unknown")}
}),
)))
}
Loading