Skip to content

Commit 3232fa0

Browse files
authored
Prevent NPE when using otel metrics bridge asynchronously to agent start (#3880)
1 parent 03afb23 commit 3232fa0

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

CHANGELOG.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ Use subheadings with the "=====" level for adding notes for unreleased changes:
3131
3232
=== Unreleased
3333
34+
[float]
35+
===== Bug fixes
36+
* Prevent NPE in OpenTelemetry metrics bridge in case of asynchronous agent start - {pull}3880[#3880]
37+
3438
[[release-notes-1.x]]
3539
=== Java Agent version 1.x
3640

apm-agent-plugins/apm-opentelemetry/apm-opentelemetry-embedded-metrics-sdk/src/main/java/co/elastic/apm/agent/embeddedotel/EmbeddedSdkManager.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@
1818
*/
1919
package co.elastic.apm.agent.embeddedotel;
2020

21-
import co.elastic.apm.agent.tracer.AbstractLifecycleListener;
2221
import co.elastic.apm.agent.embeddedotel.proxy.ProxyMeterProvider;
2322
import co.elastic.apm.agent.sdk.logging.Logger;
2423
import co.elastic.apm.agent.sdk.logging.LoggerFactory;
24+
import co.elastic.apm.agent.tracer.AbstractLifecycleListener;
2525
import co.elastic.apm.agent.tracer.Tracer;
26+
import io.opentelemetry.api.metrics.MeterProvider;
2627
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
2728
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
2829

@@ -65,6 +66,10 @@ public ProxyMeterProvider getMeterProvider() {
6566
if (sdkInstance == null) {
6667
startSdk();
6768
}
69+
if (sdkInstance == null) {
70+
logger.warn("Returning NoOp-MeterProvider because OpenTelemetry metrics SDK could not be initialized!");
71+
return new ProxyMeterProvider(MeterProvider.noop());
72+
}
6873
return new ProxyMeterProvider(sdkInstance);
6974
}
7075

@@ -78,7 +83,11 @@ synchronized void reset() {
7883
}
7984

8085
private synchronized void startSdk() {
81-
if (isShutdown || sdkInstance != null || tracer == null) {
86+
if (isShutdown || sdkInstance != null) {
87+
return;
88+
}
89+
if (tracer == null) {
90+
logger.warn("Cannot initialize OpenTelemetry metrics SDK because tracer has not started yet");
8291
return;
8392
}
8493
logger.debug("Starting embedded OpenTelemetry metrics SDK");
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package co.elastic.apm.agent.embeddedotel;
2+
3+
import co.elastic.apm.agent.embeddedotel.proxy.ProxyMeter;
4+
import co.elastic.apm.agent.tracer.Tracer;
5+
import org.junit.jupiter.api.Test;
6+
7+
import static org.assertj.core.api.Assertions.assertThat;
8+
9+
public class EmbeddedSdkManagerTest {
10+
11+
/**
12+
* The instrumentation of the agent is performed before {@link EmbeddedSdkManager#init(Tracer)} is invoked.
13+
* This means if the agent is started asynchronously, it can happen that {@link EmbeddedSdkManager#getMeterProvider()}
14+
* is invoked before the tracer has been provided.
15+
* This test verifies that in that case no exception occurs and a noop-meter implementation is used.
16+
*/
17+
@Test
18+
public void ensureNoExceptionOnMissingTracer() throws Exception {
19+
ProxyMeter meter = new EmbeddedSdkManager().getMeterProvider().get("foobar");
20+
assertThat(meter.getDelegate()).isInstanceOf(Class.forName("io.opentelemetry.api.metrics.DefaultMeter"));
21+
}
22+
}

0 commit comments

Comments
 (0)