Skip to content

Commit 8437075

Browse files
authored
[otelgrpc] Do not panic for nil instruments (#4875)
* Do not panic for nil instr in grpc * Add changelog entry * Apply lint * Use noop pkg hist impls
1 parent ef8063b commit 8437075

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1313
- Add the new `go.opentelemetry.io/contrib/instrgen` package to provide auto-generated source code instrumentation. (#3068, #3108)
1414
- Add peer attributes to spans recorded by `NewClientHandler`, `NewServerHandler` in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc`. (#4873)
1515

16+
### Fixed
17+
18+
- Do not panic in `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` if `MeterProvider` returns a `nil` instrument. (#4875)
19+
1620
## [1.22.0/0.47.0/0.16.0/0.2.0] - 2024-01-18
1721

1822
### Added

instrumentation/google.golang.org/grpc/otelgrpc/config.go

+16
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"go.opentelemetry.io/otel"
1919
"go.opentelemetry.io/otel/attribute"
2020
"go.opentelemetry.io/otel/metric"
21+
"go.opentelemetry.io/otel/metric/noop"
2122
"go.opentelemetry.io/otel/propagation"
2223
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
2324
"go.opentelemetry.io/otel/trace"
@@ -89,34 +90,49 @@ func newConfig(opts []Option, role string) *config {
8990
metric.WithUnit("ms"))
9091
if err != nil {
9192
otel.Handle(err)
93+
if c.rpcDuration == nil {
94+
c.rpcDuration = noop.Float64Histogram{}
95+
}
9296
}
9397

9498
c.rpcRequestSize, err = c.meter.Int64Histogram("rpc."+role+".request.size",
9599
metric.WithDescription("Measures size of RPC request messages (uncompressed)."),
96100
metric.WithUnit("By"))
97101
if err != nil {
98102
otel.Handle(err)
103+
if c.rpcRequestSize == nil {
104+
c.rpcRequestSize = noop.Int64Histogram{}
105+
}
99106
}
100107

101108
c.rpcResponseSize, err = c.meter.Int64Histogram("rpc."+role+".response.size",
102109
metric.WithDescription("Measures size of RPC response messages (uncompressed)."),
103110
metric.WithUnit("By"))
104111
if err != nil {
105112
otel.Handle(err)
113+
if c.rpcResponseSize == nil {
114+
c.rpcResponseSize = noop.Int64Histogram{}
115+
}
106116
}
107117

108118
c.rpcRequestsPerRPC, err = c.meter.Int64Histogram("rpc."+role+".requests_per_rpc",
109119
metric.WithDescription("Measures the number of messages received per RPC. Should be 1 for all non-streaming RPCs."),
110120
metric.WithUnit("{count}"))
111121
if err != nil {
112122
otel.Handle(err)
123+
if c.rpcRequestsPerRPC == nil {
124+
c.rpcRequestsPerRPC = noop.Int64Histogram{}
125+
}
113126
}
114127

115128
c.rpcResponsesPerRPC, err = c.meter.Int64Histogram("rpc."+role+".responses_per_rpc",
116129
metric.WithDescription("Measures the number of messages received per RPC. Should be 1 for all non-streaming RPCs."),
117130
metric.WithUnit("{count}"))
118131
if err != nil {
119132
otel.Handle(err)
133+
if c.rpcResponsesPerRPC == nil {
134+
c.rpcResponsesPerRPC = noop.Int64Histogram{}
135+
}
120136
}
121137

122138
return c
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package otelgrpc
16+
17+
import (
18+
"context"
19+
"testing"
20+
21+
"github.com/stretchr/testify/assert"
22+
23+
"go.opentelemetry.io/otel/metric"
24+
"go.opentelemetry.io/otel/metric/embedded"
25+
)
26+
27+
func TestNilInstruments(t *testing.T) {
28+
mp := meterProvider{}
29+
c := newConfig([]Option{WithMeterProvider(mp)}, "test")
30+
31+
ctx := context.Background()
32+
assert.NotPanics(t, func() { c.rpcDuration.Record(ctx, 0) }, "rpcDuration")
33+
assert.NotPanics(t, func() { c.rpcRequestSize.Record(ctx, 0) }, "rpcRequestSize")
34+
assert.NotPanics(t, func() { c.rpcResponseSize.Record(ctx, 0) }, "rpcResponseSize")
35+
assert.NotPanics(t, func() { c.rpcRequestsPerRPC.Record(ctx, 0) }, "rpcRequestsPerRPC")
36+
assert.NotPanics(t, func() { c.rpcResponsesPerRPC.Record(ctx, 0) }, "rpcResponsesPerRPC")
37+
}
38+
39+
type meterProvider struct {
40+
embedded.MeterProvider
41+
}
42+
43+
func (meterProvider) Meter(string, ...metric.MeterOption) metric.Meter {
44+
return meter{}
45+
}
46+
47+
type meter struct {
48+
// Panic for non-implemented methods.
49+
metric.Meter
50+
}
51+
52+
func (meter) Int64Histogram(string, ...metric.Int64HistogramOption) (metric.Int64Histogram, error) {
53+
return nil, assert.AnError
54+
}
55+
56+
func (meter) Float64Histogram(string, ...metric.Float64HistogramOption) (metric.Float64Histogram, error) {
57+
return nil, assert.AnError
58+
}

0 commit comments

Comments
 (0)