From 998412ced7c4e894a7234da390644b48056b4dbc Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:26:27 -0700 Subject: [PATCH] [service] Allow users to disable the tracer provider via the feature gate `service.noopTracerProvider` (#10859) Previously the service was returning an instance of a SDK tracer provider regardless of whether there were any processors configured causing resources to be consumed unnecessarily. Fixes #10858 --------- Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- ...deboten_disable-tracer-without-config.yaml | 25 +++++++++++++ internal/globalgates/globalgates.go | 5 +++ service/go.mod | 2 +- service/telemetry/tracer.go | 6 +++ service/telemetry/tracer_test.go | 37 +++++++++++++++++++ 5 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 .chloggen/codeboten_disable-tracer-without-config.yaml diff --git a/.chloggen/codeboten_disable-tracer-without-config.yaml b/.chloggen/codeboten_disable-tracer-without-config.yaml new file mode 100644 index 00000000000..09e0a4da069 --- /dev/null +++ b/.chloggen/codeboten_disable-tracer-without-config.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: service + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "Allow users to disable the tracer provider via the feature gate `service.noopTracerProvider`" + +# One or more tracking issues or pull requests related to the change +issues: [10858] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: The service is returning an instance of a SDK tracer provider regardless of whether there were any processors configured causing resources to be consumed unnecessarily. + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/internal/globalgates/globalgates.go b/internal/globalgates/globalgates.go index 346bd2d64fd..5f4d470d122 100644 --- a/internal/globalgates/globalgates.go +++ b/internal/globalgates/globalgates.go @@ -24,3 +24,8 @@ var DisableOpenCensusBridge = featuregate.GlobalRegistry().MustRegister("service featuregate.WithRegisterFromVersion("v0.105.0"), featuregate.WithRegisterToVersion("v0.109.0"), featuregate.WithRegisterDescription("`Disables the OpenCensus bridge meaning any component still using the OpenCensus SDK will no longer be able to produce telemetry.")) + +var NoopTracerProvider = featuregate.GlobalRegistry().MustRegister("service.noopTracerProvider", + featuregate.StageAlpha, + featuregate.WithRegisterFromVersion("v0.107.0"), + featuregate.WithRegisterDescription("Sets a Noop OpenTelemetry TracerProvider to reduce memory allocations. This featuregate is incompatible with the zPages extension.")) diff --git a/service/go.mod b/service/go.mod index 09fd63fa326..52669085b4a 100644 --- a/service/go.mod +++ b/service/go.mod @@ -21,6 +21,7 @@ require ( go.opentelemetry.io/collector/extension v0.106.1 go.opentelemetry.io/collector/extension/zpagesextension v0.106.1 go.opentelemetry.io/collector/featuregate v1.12.0 + go.opentelemetry.io/collector/internal/globalgates v0.106.1 go.opentelemetry.io/collector/pdata v1.12.0 go.opentelemetry.io/collector/pdata/testdata v0.106.1 go.opentelemetry.io/collector/processor v0.106.1 @@ -86,7 +87,6 @@ require ( go.opentelemetry.io/collector/config/internal v0.106.1 // indirect go.opentelemetry.io/collector/consumer/consumerprofiles v0.106.1 // indirect go.opentelemetry.io/collector/extension/auth v0.106.1 // indirect - go.opentelemetry.io/collector/internal/globalgates v0.106.1 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.106.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect go.opentelemetry.io/contrib/zpages v0.53.0 // indirect diff --git a/service/telemetry/tracer.go b/service/telemetry/tracer.go index 4434af2fc74..52068ec404e 100644 --- a/service/telemetry/tracer.go +++ b/service/telemetry/tracer.go @@ -13,6 +13,9 @@ import ( "go.opentelemetry.io/otel/propagation" semconv "go.opentelemetry.io/otel/semconv/v1.26.0" "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" + + "go.opentelemetry.io/collector/internal/globalgates" ) const ( @@ -45,6 +48,9 @@ func attributes(set Settings, cfg Config) map[string]interface{} { // New creates a new Telemetry from Config. func newTracerProvider(ctx context.Context, set Settings, cfg Config) (trace.TracerProvider, error) { + if globalgates.NoopTracerProvider.IsEnabled() { + return noop.NewTracerProvider(), nil + } sch := semconv.SchemaURL res := config.Resource{ SchemaUrl: &sch, diff --git a/service/telemetry/tracer_test.go b/service/telemetry/tracer_test.go index 6a86d284b58..126f681c0b4 100644 --- a/service/telemetry/tracer_test.go +++ b/service/telemetry/tracer_test.go @@ -4,11 +4,16 @@ package telemetry // import "go.opentelemetry.io/collector/service/telemetry" import ( + "context" "testing" "github.com/stretchr/testify/require" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/featuregate" + "go.opentelemetry.io/collector/internal/globalgates" "go.opentelemetry.io/collector/service/telemetry/internal" ) @@ -56,6 +61,38 @@ func TestAttributes(t *testing.T) { } } +func TestNewTracerProvider(t *testing.T) { + tests := []struct { + name string + wantTracerProvider any + noopTracer bool + }{ + { + name: "noop tracer provider", + noopTracer: true, + wantTracerProvider: noop.TracerProvider{}, + }, + { + name: "tracer provider", + wantTracerProvider: &sdktrace.TracerProvider{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + previousValue := globalgates.NoopTracerProvider.IsEnabled() + err := featuregate.GlobalRegistry().Set(globalgates.NoopTracerProvider.ID(), tt.noopTracer) + require.NoError(t, err) + defer func() { + err = featuregate.GlobalRegistry().Set(globalgates.NoopTracerProvider.ID(), previousValue) + require.NoError(t, err) + }() + provider, err := newTracerProvider(context.TODO(), internal.Settings{}, Config{}) + require.NoError(t, err) + require.IsType(t, tt.wantTracerProvider, provider) + }) + } +} + func ptr[T any](v T) *T { return &v }