Why Spans Disappear in Tests
When GlobalOpenTelemetry.getTracer() is called before any TracerProvider is registered, the OpenTelemetry Java SDK falls back to NoopTracerProvider. This provider returns NoopTracer instances that create NoopSpan objects. These spans implement the Span interface but record no data, invoke no processors, and emit no warnings. Consequently, tests that assert on collected spans may pass while producing zero telemetry—a false positive.
Recommended Test Setup
1. Supply an In‑Memory Exporter via JUnit 5 Extension
Yes. Create a JUnit 5 extension (or a @BeforeEach method) that builds an SdkTracerProvider with an InMemorySpanExporter wrapped in a SimpleSpanProcessor, then registers it globally:
SdkTracerProvider provider = SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(new InMemorySpanExporter()))
.build();
OpenTelemetry.setGlobalTracerProvider(provider);
After each test, close the provider to flush spans and release resources:
@AfterEach
void tearDown() {
provider.close();
}
2. Pattern for Short‑Lived Test Processes
For tests that run in a forked JVM or where shutdown hooks are unreliable, avoid relying on the JVM shutdown hook. Instead, use try‑with‑resources or explicit close() in a teardown method. This guarantees the InMemorySpanExporter receives finished spans before the test ends.
3. Detecting Accidental Noop Usage in CI
Enable debug logging without modifying test code by setting the system property otel.java.debug=true. In the CI logs, look for lines mentioning NoopTracerProvider. Absence of such lines (or presence of SdkTracerProvider initialization) confirms a real provider is active. Alternatively, add a logging SpanProcessor that logs the span class; NoopSpan indicates the no‑op fallback.
Verification Checklist
- Run a test that creates and ends a span, then assert
exporter.getFinishedSpanItems().size() == 1. - Execute the suite with
-Dotel.java.debug=true and verify no NoopTracerProvider log appears. - Optionally, attach a custom
SpanProcessor that logs span.getClass().getName(); ensure it shows SdkSpan, not NoopSpan.
Assumptions & Caveats
- Assumes OpenTelemetry Java SDK 1.30+; log wording may differ across versions.
InMemorySpanExporter holds all finished spans in memory—clear it between tests or use a bounded exporter for high‑volume tests.- If tests run in parallel with shared global state, each test must isolate its provider (e.g., via thread‑local or per‑test registration).