-
Notifications
You must be signed in to change notification settings - Fork 19
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
Support for tracing asynchronous operations #124
Conversation
/** | ||
* Like {@link #startSpan(String, SpanType)}, but does not set or modify tracing thread state. | ||
*/ | ||
public static DetachedSpan startDetachedSpan(String operation, SpanType type) { |
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.
This might be clearer if we call it startAsyncSpan
instead.
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.
However it's not necessarily asynchronous, it's no different from any other span except that it is not connected to any thread-local state.
perhaps an alternative here would be exposing |
I'd prefer not to expose the |
|
Agreed that we're in an odd place, and there's not a lot we can do without either breaking API or creating sprawl. The If we wanted to focus on safety, the blab: I don't have a great solution. |
Hey, just jumping in on this now since I'm going to need something like this for dialogue. Has any more thought gone into this issue, or are the comments here up to date and we just need to come to an agreement on some proposal? |
Hey @ellisjoe, a month or so ago I caught up with @markelliot and we discussed a couple models. Mark was planning to put together a sample proposal/implementation that included a concept of span ownership, but he may have been pulled into other things. I'd be happy to chat through possibilities. |
* as the parent instead of thread state. | ||
*/ | ||
@MustBeClosed | ||
SpanToken attach(String operationName, SpanType type); |
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.
What's the difference between calling detach(operation)
and then complete()
vs attach(operation)
and then close()
? is it just that calling attach also overrides my current thread local state?
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.
attach applies a new span to the current thread, from attach()
to close()
This can be done multiple times to create sibling spans with the DetachedSpan
as a parent.
DetachedSpan.complete
, is used to complete the detached span, which is not associated with a thread. There is danger that complete is never called, and we fail to associate the child spans (from attach
) with the original parent of this detached span, but I don't think there are good options to avoid that.
This model means that you cannot ever detach or attach an existing span that is already bound to a thread, each time that we attach or detach we mark a new operation. I've found that otherwise, it can become difficult to trace where our tracing spans have actually come from.
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.
Oh I see, so you'd start your DetachedSpan
, then you could attach()
it once your async task starts running, and then go back to using the normal Tracer.startSpan()
methods throughout.
Think the thing that seems a bit funky is that you need to close the SpanToken
rather than just using Tracer.completeSpan()
.
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.
That is correct, the reason for the different type is so we can reset the original tracing data on the attached thread. We could ignore that, and apply state directly, but it would be confusing to api consumers whether or not the attach creates a new tracing span, and how many they are responsible for completing.
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.
I think this may have been more obvious to me if the attach()
method was on Tracers
rather than here. In my head, at least at the moment, Tracers
deals with all the threading business, and so I could imagine wanting to call Tracers.attach(detachedSpan)
which would then give me a SpanToken
to close and reset the thread's trace. And then on DetachedSpan
you just would just have newSpan()
which gives you a new DetachedSpan
parented by the current one. That way DetachedSpan
has nothing to do with threading.
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.
👍 That sounds good to me.
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.
As a point of reference, that also seems to be what these guys are doing as well: https://github.com/open-telemetry/opentelemetry-java/blob/master/api/src/main/java/io/opentelemetry/trace/Tracer.java#L140
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.
Tracers.attach(detachedSpan)
would also need an operation name param. It would also require us to pass some additional data between DetachedSpan and Tracer, which isn't currently possible. Right now, the DetachedSpan interface doesn't leak whether or not it is sampled, but that is required in order to attach to a thread.
Holding off fixing this up until #180 has gone in to unblock other work |
35f344c
to
1ea1675
Compare
Rebased, have to catch a flight shortly, will knock out the rest when I can. |
e93254f
to
b45f25d
Compare
I've updated the API, there's still some implementation code that I need to move around. I don't like having the DetachedSpan implementations living in Tracer, but I can clean that up once we're happy with the ergonomics. |
4a1aae2
to
b9b7d4a
Compare
return Optional.empty(); | ||
} | ||
|
||
private static final class SampledDetachedSpan implements DetachedSpan { |
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.
Could we convert DetachedSpan into an abstract class, and inline Smapled/UnsampledDetachedSpan there? It would make the layout consistent with how Trace is currently implemented
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.
I could go either way on this. the DetachedSpan interface is meant to be relatively straightforward to read, and detached from implementation details because it's an API that will be consumed by developers using this library. Trace is an implementation detail, and isn't really consumed outside of this library.
If we moved these to the DetachedSpan class, we would also need to implement a package private accessor for the raw value of the Tracer trace thread-local, which could be dangerous if folks try to get clever.
} | ||
|
||
@Override | ||
public DetachedSpan detach(String operation, SpanType type) { |
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.
What use case do you envision for this?
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.
Consider a webserver: When a request is received on a non-blocking thread, I'd like to start a detached span representing the entire request. Later, before processing, the request is enqueued to a larger thread pool where we allow work -- I'd like the ability to track time spent enqueued, despite not having attached the span to thread.
Unblocking 👍 I think the next steps are to publish an RC from here and then make sure it looks sensible in conjure-java-runtime. |
Dan and I are trying this out on conjure-java-runtime's https://github.com/palantir/conjure-java-runtime/compare/ds/use-new-tracing?expand=1, findings so far:
|
* Revert "CloseableSpan exposes ids necessary to set headers" This reverts commit 1f188ac. * Tracer#getTraceMetadata * parentSpanId is empty * nit * Update tracing/src/main/java/com/palantir/tracing/Tracer.java Co-Authored-By: Carter Kozak <ckozak@ckozak.net>
👍 |
Released 3.2.0 |
Added a Tracer API to create a span that is not attached to a
thread.