From 75d807add9e33c52d419b63e2c9e4e546fa5319b Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Thu, 13 Feb 2020 12:46:49 -0800 Subject: [PATCH] Fix race condition on loading SDK (#165) This broke during last merge from DataDog repo because context class loader is no longer set to the agent's class loader. --- .../auto/tooling/AgentInstaller.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/agent-tooling/src/main/java/io/opentelemetry/auto/tooling/AgentInstaller.java b/agent-tooling/src/main/java/io/opentelemetry/auto/tooling/AgentInstaller.java index b5c45cedc5..17fe0d0390 100644 --- a/agent-tooling/src/main/java/io/opentelemetry/auto/tooling/AgentInstaller.java +++ b/agent-tooling/src/main/java/io/opentelemetry/auto/tooling/AgentInstaller.java @@ -54,11 +54,22 @@ public class AgentInstaller { public static ResettableClassFileTransformer installBytebuddyAgent( final Instrumentation inst, final AgentBuilder.Listener... listeners) { - // need to trigger loading of OpenTelemetry SDK before instrumentation can possibly cause - // io.opentelemetry.OpenTelemetry to be loaded, since as soon as io.opentelemetry.OpenTelemetry, - // it looks up implementation via SPI, and if it doesn't find one, it loads the No-op - // implementation and it cannot be replaced later - OpenTelemetry.getTracerFactory(); + final ClassLoader savedContextClassLoader = Thread.currentThread().getContextClassLoader(); + try { + // calling (shaded) OpenTelemetry.getTracerFactory() with context class loader set to the + // agent class loader, so that SPI finds the agent's (isolated) SDK, and (shaded) + // OpenTelemetry registers it, and then when instrumentation calls (shaded) + // OpenTelemetry.getTracerFactory() later, they get back the agent's (isolated) SDK + // + // but if we don't trigger this early registration, then if instrumentation is the first to + // call (shaded) OpenTelemetry.getTracerFactory(), then SPI can't see the agent class loader, + // and so (shaded) OpenTelemetry registers the no-op TracerFactory, and it cannot be replaced + // later + Thread.currentThread().setContextClassLoader(AgentInstaller.class.getClassLoader()); + OpenTelemetry.getTracerFactory(); + } finally { + Thread.currentThread().setContextClassLoader(savedContextClassLoader); + } INSTRUMENTATION = inst;