Description
Is your feature request related to a problem? Please describe.
Azure SDKs are instrumented natively. We have a plugin (azure-core-tracing-opentelemetry) shaded into the otel java agent.
Our SDKs are reactor/async heavy and we can't always rely that context propagation happens correctly. Also reactor instrumentation has relatively high overhead and some users want to disable it.
To help with context propagation we recommend users to pass it over explicitly through our own com.azure.core.util.Context
property bag.
It looks similar to the following:
Span parent = tracer.spanBuilder("parent").startSpan();
io.opentelemetry.context.Context traceContext = io.opentelemetry.context.Context.current().with(parent);
String response = sampleAzureClient.methodCall("get items",
new Context(PARENT_TRACE_CONTEXT_KEY, traceContext));
...
Life's good: tests are green, applications that manually instrument by installing the plugin work just fine.
But it does not work with the agent - as long as plugin is shaded, it does not recognize the type of the context in PARENT_TRACE_CONTEXT_KEY
key.
Repro
run with
-javaagent:"path/to/opentelemetry-javaagent.jar" -Dotel.traces.exporter=logging -Dotel.logs.exporter=none -Dotel.metrics.exporter=none
It'll print two scenarios:
- [Demonstrates the issue] parent span created in user app and passed explicitly as azure context prop. The child span (for http request created by Azure SDK) won't be correlated with parent passed by user app
- [All good] parent span created using the plugin as if it was created by an Azure SDK. The child span will be correlated with parent
Root cause
The plugin needs to cast the object behind PARENT_TRACE_CONTEXT_KEY
to io.opentelemetry.context.Context
to use it as an explicit parent to new spans.
But during shading and relocation, the type I need to cast to becomes io.opentelemetry.javaagent.shaded.io.opentelemetry.context.Context
.
The context created by the application is io.opentelemetry.javaagent.instrumentation.opentelemetryapi.context.AgentContextWrapper
and it implements the original io.opentelemetry.context.Context
, therefore it can't be used as parent.
Describe the solution you'd like
I'd like users to be able to pass me context explicitly that I can correlate with.
Ideally, native instrumentations should not worry about relocation/shading at all, but I'd be happy to add any duct tape and detect that plugin runs in the agent.
So essentially I'm looking for any guidance on how to solve this either in the shaded instrumentation part, or inside the azure plugin.
Describe alternatives you've considered
I tried detecting that I'm in the agent and calling AgentContextStorage.toAgentContext
to convert user-passed-context to the shaded one.
The only way however, I can resolve this method with reflection is by iterating over all methods on the class like
Class<?> agentCtxStorageClass = Class
.forName("io.opentelemetry.javaagent.instrumentation.opentelemetryapi.context.AgentContextStorage");
Method[] getAgentContext = agentCtxStorageClass.getMethods();
for (Method method : getAgentContext) {
if (method.getName().equals("getAgentContext")) {
return (io.opentelemetry.context.Context) method.invoke(null, data);
}
}
because even string literals in Class.forName("io.opentelemetry.context.Context")
are rewritten to the new shaded context type.