open-telemetry / open-telemetry/opentelemetry-java

No tracer provider in the OpenTelemetrySdk builder makes the application do a lot of work for spans that will be dropped

Open
#8,740 8 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Bug
Dominant language
Java
Stars
2.5k
Forks
1k
Avg merge
3d 17h
Merged PRs (30d)
58

Description

Describe the bug

When the tracer provider is not set in the OpenTelemetrySdk builder, spans claim they are recorded, but there is no exporter defined for them.
Therefore, despite appropriately guarding the attribute creation code with if (!span.isRecording()), an application can waste resources generating spans with attributes that will never be exported anyway.

Steps to reproduce
This reduced test case shows the problem:

    @Test
    public void shouldNotEmitSpansWhenTracingDisabledButLoggingEnabled2() {
        // Given
        OpenTelemetry openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(null).build();
        // Same as OpenTelemetry openTelemetry = OpenTelemetrySdk.builder().build();

        // When
        Span span = openTelemetry.getTracer("test").spanBuilder("test-span").startSpan();

        // Then
        assertThat(span.isRecording()).isFalse(); // Fails!
    }

Of course our setup code is a bit more complicated: we have a real logger provider, but no tracer provider, and we ended up passing null for the tracer provider.

What did you expect to see?
In the test above, the assertion assertThat(span.isRecording()).isFalse(); should pass. As a result, all the application span code would be a noop.

What did you see instead?
In the test above, the assertion assertThat(span.isRecording()).isFalse(); does not pass. As a result, all the application span code does a lot of useless work.

Workaround
First attempt:
Do the following instead:

SdkTracerProvider noopTracer = SdkTracerProvider.builder().setSampler(alwaysOff()).build();
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(noopTracer).build();

But even that is not optimal, it will run through a lot of code on this line:
openTelemetry.getTracer("test").spanBuilder("test-span").startSpan();

I was hoping I could find a way to setSdkTracer#tracerEnabled to false, but I could not.
I wanted to override SdkTracerProviderBuilder#tracerConfiguratorBuilder, but there is no public API to do so either.

Second attempt:
In the end, the best workaround I found is the following:

SdkTracerProvider noopTracer = SdkTracerProvider.builder().build();
noopTracer.close();
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder().setTracerProvider(noopTracer).build();

This ensures we take one of the fast paths in io.opentelemetry.sdk.trace.SdkTracer#spanBuilder, which returns a NoopSpanBuilder, and then the call to io.opentelemetry.api.trace.SpanBuilder.startSpan does as little as possible, and the returned io.opentelemetry.api.trace.PropagatedSpan isRecording() method returns false.
Which what we want.

Conclusion:
To cut a long story short, the default is surprising, and making it to behave as noop required a surprising amount of work, and it is a bit "heavy". i.e. doing the "right thing" in this case is not exactly trivial.

What version and what artifacts are you using?
io.opentelemetry:opentelemetry-sdk-trace:1.62.0

Environment
Compiler: Amazon Correto 17.0.19
OS: Ubuntu 24.04.4 LTS

Additional context
n/a

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the reduced test for OpenTelemetrySdk.builder().build() and inspect SdkTracer#spanBuilder, including the NoopSpanBuilder fast path described in the report. Trace how a missing tracer provider affects Span.isRecording(), then add a regression test that verifies spans are no-ops and application span work is avoided when tracing is not configured.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
observability
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.