-
Notifications
You must be signed in to change notification settings - Fork 14
Add content type to additional data spans #388
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
Changes from 3 commits
50874ce
40de66d
e37fc3a
d1c3803
798ab73
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,13 +19,16 @@ | |
| import io.opentelemetry.api.GlobalOpenTelemetry; | ||
| import io.opentelemetry.api.common.AttributeKey; | ||
| import io.opentelemetry.api.trace.Span; | ||
| import io.opentelemetry.api.trace.SpanBuilder; | ||
| import io.opentelemetry.api.trace.Tracer; | ||
| import io.opentelemetry.context.Context; | ||
| import io.opentelemetry.instrumentation.api.util.VirtualField; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.io.UnsupportedEncodingException; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.lang.reflect.Method; | ||
| import java.nio.charset.Charset; | ||
| import org.hypertrace.agent.core.instrumentation.HypertraceCallDepthThreadLocalMap; | ||
| import org.hypertrace.agent.core.instrumentation.HypertraceSemanticAttributes; | ||
|
|
@@ -50,12 +53,34 @@ public static void addAttribute(Span span, AttributeKey<String> attributeKey, St | |
| if (span.isRecording()) { | ||
| span.setAttribute(attributeKey, value); | ||
| } else { | ||
| TRACER | ||
| .spanBuilder(HypertraceSemanticAttributes.ADDITIONAL_DATA_SPAN_NAME) | ||
| .setParent(Context.root().with(span)) | ||
| .setAttribute(attributeKey, value) | ||
| .startSpan() | ||
| .end(); | ||
| SpanBuilder spanBuilder = | ||
| TRACER | ||
| .spanBuilder(HypertraceSemanticAttributes.ADDITIONAL_DATA_SPAN_NAME) | ||
| .setParent(Context.root().with(span)) | ||
| .setAttribute(attributeKey, value); | ||
|
|
||
| // Also add content type if present | ||
| if (span.getClass().getName().equals("io.opentelemetry.sdk.trace.SdkSpan")) { | ||
| try { | ||
| Method getAttribute = | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needed to use reflection because this part of code will be running in the application class loader. And that will not have the sdk libraries which has this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we store content type in context along with parent span? Rather than retrieving with reflection from span.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can but we will need that change in all the framework instrumentations that we want to support. This was a one place change for this for all parent frameworks There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What method is this instrumentation on? Also how many framework instrumentation points do we support streaming bodies for?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is instrumented on the
We have 4 client instrumentations and all support streaming. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, my concern is with overhead, will let you take call on which approach to go. If we go with reflection, should we at least cache the Method object because that wouldn't change, will it? If that's not an expensive operation then nvm.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, added the method to static block during instantiation. Will be called only once. |
||
| span.getClass().getDeclaredMethod("getAttribute", AttributeKey.class); | ||
| getAttribute.setAccessible(true); | ||
| Object reqContentType = | ||
| getAttribute.invoke(span, AttributeKey.stringKey("http.request.header.content-type")); | ||
| if (reqContentType != null) { | ||
| spanBuilder.setAttribute("http.request.header.content-type", (String) reqContentType); | ||
| } | ||
| Object resContentType = | ||
| getAttribute.invoke( | ||
| span, AttributeKey.stringKey("http.response.header.content-type")); | ||
| if (resContentType != null) { | ||
| spanBuilder.setAttribute("http.response.header.content-type", (String) resContentType); | ||
| } | ||
| } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { | ||
| // ignore and continue | ||
|
shashank11p marked this conversation as resolved.
|
||
| } | ||
| } | ||
| spanBuilder.startSpan().end(); | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this
Context.root()instead ofContext.current()?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because if the
spanhas ended, then the current may not actually be the parent of this additional-data.It could be inside the scope of another span, but we want this additional-data with response body to be present under the
spanwhich we are passing down from the VirtualStoreThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which
spanhas ended?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if we had a root span -> parent span (which has the inputstream).
Now, the parent span is ended, but the inputstream.read() is not yet called, but the inputstream is passed down, and another span is created, and then the input stream is read. Then the current span where input stream is read is not the actual span under which we want to create the additional data span. So that may the reason. We would want it like:
I wasn't involved when this code was written, so I'm also trying to think and justify this.