Skip to content

Commit 5adc271

Browse files
authored
autoexport: Add support for metrics (#4229)
1 parent a7e57bb commit 5adc271

13 files changed

+479
-349
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1414
- Add `"go.opentelemetry.io/contrib/samplers/jaegerremote".WithSamplingStrategyFetcher` which sets custom fetcher implementation. (#4045)
1515
- Add `"go.opentelemetry.io/contrib/config"` package that includes configuration models generated via go-jsonschema. (#4376)
1616
- Add `NewSDK` function to `"go.opentelemetry.io/contrib/config"`. The initial implementation only returns noop providers. (#4414)
17+
- Add metrics support to `go.opentelemetry.io/contrib/exporters/autoexport`. (#4229)
1718

1819
### Changed
1920

2021
- Dropped compatibility testing for [Go 1.19].
2122
The project no longer guarantees support for this version of Go. (#4352)
2223

24+
### Deprecated
25+
26+
- In `go.opentelemetry.io/contrib/exporters/autoexport`, `Option` was renamed to `SpanOption`. The old name is deprecated but continues to be supported as an alias. (#4229)
27+
2328
### Fixed
2429

2530
- The `go.opentelemetry.io/contrib/samplers/jaegerremote` sampler does not panic when the default HTTP round-tripper (`http.DefaultTransport`) is not `*http.Transport`. (#4045)

exporters/autoexport/exporter_test.go

-136
This file was deleted.

exporters/autoexport/go.mod

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ go 1.20
44

55
require (
66
github.com/stretchr/testify v1.8.4
7+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0
8+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0
79
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0
810
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0
911
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0
10-
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0
1112
go.opentelemetry.io/otel/sdk v1.19.0
13+
go.opentelemetry.io/otel/sdk/metric v1.19.0
1214
)
1315

1416
require (
@@ -20,6 +22,7 @@ require (
2022
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
2123
github.com/pmezard/go-difflib v1.0.0 // indirect
2224
go.opentelemetry.io/otel v1.19.0 // indirect
25+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // indirect
2326
go.opentelemetry.io/otel/metric v1.19.0 // indirect
2427
go.opentelemetry.io/otel/trace v1.19.0 // indirect
2528
go.opentelemetry.io/proto/otlp v1.0.0 // indirect

exporters/autoexport/go.sum

+8-2
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,24 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
2424
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
2525
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
2626
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
27+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 h1:ZtfnDL+tUrs1F0Pzfwbg2d59Gru9NCH3bgSHBM6LDwU=
28+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU=
29+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 h1:NmnYCiR0qNufkldjVvyQfZTHSdzeHoZ41zggMsdMcLM=
30+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0/go.mod h1:UVAO61+umUsHLtYb8KXXRoHtxUkdOPkYidzW3gipRLQ=
31+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 h1:wNMDy/LVGLj2h3p6zg4d0gypKfWKSWI14E1C4smOgl8=
32+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0/go.mod h1:YfbDdXAAkemWJK3H/DshvlrxqFB2rtW4rY6ky/3x/H0=
2733
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
2834
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
2935
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk=
3036
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I=
3137
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
3238
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
33-
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0 h1:Nw7Dv4lwvGrI68+wULbcq7su9K2cebeCUrDjVrUJHxM=
34-
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0/go.mod h1:1MsF6Y7gTqosgoZvHlzcaaM8DIMNZgJh87ykokoNH7Y=
3539
go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
3640
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
3741
go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
3842
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
43+
go.opentelemetry.io/otel/sdk/metric v1.19.0 h1:EJoTO5qysMsYCa+w4UghwFV/ptQgqSL/8Ni+hx+8i1k=
44+
go.opentelemetry.io/otel/sdk/metric v1.19.0/go.mod h1:XjG0jQyFJrv2PbMvwND7LwCEhsJzCzV5210euduKcKY=
3945
go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
4046
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
4147
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=

exporters/autoexport/metrics.go

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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 autoexport // import "go.opentelemetry.io/contrib/exporters/autoexport"
16+
17+
import (
18+
"context"
19+
"os"
20+
21+
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
22+
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
23+
"go.opentelemetry.io/otel/sdk/metric"
24+
)
25+
26+
// MetricOption applies an autoexport configuration option.
27+
type MetricOption = option[metric.Reader]
28+
29+
// WithFallbackMetricReader sets the fallback exporter to use when no exporter
30+
// is configured through the OTEL_METRICS_EXPORTER environment variable.
31+
func WithFallbackMetricReader(exporter metric.Reader) MetricOption {
32+
return withFallback[metric.Reader](exporter)
33+
}
34+
35+
// NewMetricReader returns a configured [go.opentelemetry.io/otel/sdk/metric.Reader]
36+
// defined using the environment variables described below.
37+
//
38+
// OTEL_METRICS_EXPORTER defines the metrics exporter; supported values:
39+
// - "none" - "no operation" exporter
40+
// - "otlp" (default) - OTLP exporter; see [go.opentelemetry.io/otel/exporters/otlp/otlpmetric]
41+
//
42+
// OTEL_EXPORTER_OTLP_PROTOCOL defines OTLP exporter's transport protocol;
43+
// supported values:
44+
// - "grpc" - protobuf-encoded data using gRPC wire format over HTTP/2 connection;
45+
// see: [go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc]
46+
// - "http/protobuf" (default) - protobuf-encoded data over HTTP connection;
47+
// see: [go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp]
48+
//
49+
// An error is returned if an environment value is set to an unhandled value.
50+
//
51+
// Use [RegisterMetricReader] to handle more values of OTEL_METRICS_EXPORTER.
52+
//
53+
// Use [WithFallbackMetricReader] option to change the returned exporter
54+
// when OTEL_TRACES_EXPORTER is unset or empty.
55+
//
56+
// Use [IsNoneMetricReader] to check if the retured exporter is a "no operation" exporter.
57+
func NewMetricReader(ctx context.Context, opts ...MetricOption) (metric.Reader, error) {
58+
return metricsSignal.create(ctx, opts...)
59+
}
60+
61+
// RegisterMetricReader sets the MetricReader factory to be used when the
62+
// OTEL_METRICS_EXPORTERS environment variable contains the exporter name. This
63+
// will panic if name has already been registered.
64+
func RegisterMetricReader(name string, factory func(context.Context) (metric.Reader, error)) {
65+
must(metricsSignal.registry.store(name, factory))
66+
}
67+
68+
var metricsSignal = newSignal[metric.Reader]("OTEL_METRICS_EXPORTER")
69+
70+
func init() {
71+
RegisterMetricReader("otlp", func(ctx context.Context) (metric.Reader, error) {
72+
proto := os.Getenv(otelExporterOTLPProtoEnvKey)
73+
if proto == "" {
74+
proto = "http/protobuf"
75+
}
76+
77+
switch proto {
78+
case "grpc":
79+
r, err := otlpmetricgrpc.New(ctx)
80+
if err != nil {
81+
return nil, err
82+
}
83+
return metric.NewPeriodicReader(r), nil
84+
case "http/protobuf":
85+
r, err := otlpmetrichttp.New(ctx)
86+
if err != nil {
87+
return nil, err
88+
}
89+
return metric.NewPeriodicReader(r), nil
90+
default:
91+
return nil, errInvalidOTLPProtocol
92+
}
93+
})
94+
RegisterMetricReader("none", func(ctx context.Context) (metric.Reader, error) {
95+
return newNoopMetricReader(), nil
96+
})
97+
}

exporters/autoexport/metrics_test.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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 autoexport // import "go.opentelemetry.io/contrib/exporters/autoexport"
16+
17+
import (
18+
"context"
19+
"fmt"
20+
"reflect"
21+
"testing"
22+
23+
"go.opentelemetry.io/otel/sdk/metric"
24+
25+
"github.com/stretchr/testify/assert"
26+
)
27+
28+
func TestMetricExporterNone(t *testing.T) {
29+
t.Setenv("OTEL_METRICS_EXPORTER", "none")
30+
got, err := NewMetricReader(context.Background())
31+
assert.NoError(t, err)
32+
assert.True(t, IsNoneMetricReader(got))
33+
}
34+
35+
func TestMetricExporterOTLP(t *testing.T) {
36+
t.Setenv("OTEL_METRICS_EXPORTER", "otlp")
37+
38+
for _, tc := range []struct {
39+
protocol, exporterType string
40+
}{
41+
{"http/protobuf", "*otlpmetrichttp.Exporter"},
42+
{"", "*otlpmetrichttp.Exporter"},
43+
{"grpc", "*otlpmetricgrpc.Exporter"},
44+
} {
45+
t.Run(fmt.Sprintf("protocol=%q", tc.protocol), func(t *testing.T) {
46+
t.Setenv("OTEL_EXPORTER_OTLP_PROTOCOL", tc.protocol)
47+
48+
got, err := NewMetricReader(context.Background())
49+
assert.NoError(t, err)
50+
assert.IsType(t, &metric.PeriodicReader{}, got)
51+
52+
// Implementation detail hack. This may break when bumping OTLP exporter modules as it uses unexported API.
53+
exporterType := reflect.Indirect(reflect.ValueOf(got)).FieldByName("exporter").Elem().Type()
54+
assert.Equal(t, tc.exporterType, exporterType.String())
55+
})
56+
}
57+
}
58+
59+
func TestMetricExporterOTLPOverInvalidProtocol(t *testing.T) {
60+
t.Setenv("OTEL_METRICS_EXPORTER", "otlp")
61+
t.Setenv("OTEL_EXPORTER_OTLP_PROTOCOL", "invalid-protocol")
62+
63+
_, err := NewMetricReader(context.Background())
64+
assert.Error(t, err)
65+
}

0 commit comments

Comments
 (0)