Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read data from current span before closing #12433

Closed
EddeCCC opened this issue Oct 10, 2024 · 4 comments
Closed

Read data from current span before closing #12433

EddeCCC opened this issue Oct 10, 2024 · 4 comments

Comments

@EddeCCC
Copy link

EddeCCC commented Oct 10, 2024

Greetings,

is it somehow possible to read data, like name or attributes, of the current Span before it's closed?
I tried to get the data with Span.current() or Context.current(), but I haven't been successful yet.
I also couldn't find a way to convert the current Span to a SdkSpan object.

Background:

We are developing an OTel agent extension, which should also create spans for specific methods.
However, before we start our own span for the method, we would like to check, if there is already a span recording this method, so we don't record it twice. This could happen for example because the method is part of the agent's zero code instrumentation or the method is annotated with @WithSpan.

Since the spans we want to read are not created by ourselves, I don't believe we can work with custom SpanProcessors or Samplers, because we can't change the SDK used by the agent itself.

I would be very grateful for any help or advice.

Best Regards

@trask trask transferred this issue from open-telemetry/opentelemetry-java Oct 10, 2024
@trask
Copy link
Member

trask commented Oct 10, 2024

hi @EddeCCC, inside of a Java agent extension I think you can cast Span to SdkSpan, does this work for you?

@EddeCCC
Copy link
Author

EddeCCC commented Oct 11, 2024

Hi @trask,
I tried using the following class:

package io.opentelemetry.sdk.trace;

import io.opentelemetry.api.trace.Span;

public class SpanUtil {

  public static void checkSpan() {
    SdkSpan span = (SdkSpan) Span.current();
    System.out.println("SPAN NAME: " + span.getName());
  }
}

However, when I call the method, I get an IllegalAcessError. Probably there is a problem with the module system or some ClassLoaders.

java.lang.IllegalAccessError: failed to access class io.opentelemetry.sdk.trace.SdkSpan from class io.opentelemetry.sdk.trace.SpanUtil (io.opentelemetry.sdk.trace.SdkSpan is in unnamed module of loader io.opentelemetry.javaagent.bootstrap.AgentClassLoader @7eda2dbb; io.opentelemetry.sdk.trace.SpanUtil is in unnamed module of loader io.opentelemetry.javaagent.tooling.ExtensionClassLoader @65ae6ba4)
	at io.opentelemetry.sdk.trace.SpanUtil.checkSpan(SpanUtil.java:21)
	at rocks.inspectit.gepard.agent.instrumentation.hook.action.SpanAction.startSpan(SpanAction.java:35)
	at rocks.inspectit.gepard.agent.instrumentation.hook.MethodHook.onEnter(MethodHook.java:40)
	at com.example.demo.GreetingController.myMethod(GreetingController.java:70)
	...

We have a quite complex set-up, where we inject an interface method MethodHook.onEnter into the application via the bootstrap classloader. This interface will be called in our ByteBuddy advice. However, the implementation of this interface is located inside the agent extension. Thus, we trigger our code through the application, but the code is executed within the agent.

Do you think, you can help me here? My last idea would be, to use reflection.

Regards

@EddeCCC
Copy link
Author

EddeCCC commented Oct 14, 2024

The reflection approach worked for me:

public SpanData checkSpan() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    Class<?> sdkSpanClass = Class.forName("io.opentelemetry.sdk.trace.SdkSpan");
    Span span = Span.current();

    Object sdkSpan = sdkSpanClass.cast(span);
    Method toSpanData = sdkSpanClass.getDeclaredMethod("toSpanData");
    toSpanData.setAccessible(true);

    SpanData spanData = (SpanData) toSpanData.invoke(sdkSpan);
    return spanData.getName();
  }

@trask If you might know a more "clean" approach, I would be happy to know about it. Otherwise, we can close this :)

@laurit
Copy link
Contributor

laurit commented Oct 14, 2024

Currently extension classes are loaded in a child loader of the agent class loader. As the package private SdkSpan and your SpanUtil are in different class loaders they'll also be in different runtime packages. If you only need to invoke toSpanData then you could cast to ReadableSpan instead of SdkSpan. ReadableSpan is public so having the classes in different loaders won't matter. Reflection should also work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants