-
Notifications
You must be signed in to change notification settings - Fork 4
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
Initial version of Observer APIs #3
Conversation
* @param name The tag name | ||
* @param value The tag value | ||
*/ | ||
void onWithTag(String name, Object value); |
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.
Maybe join with SpanObserver
? How would implementations know wether a specific tag is set on the SpanBuilder
or the Span
? If there is only one onSetTag
method which is invoked no matter if the tag was actually set on a SpanBuilder
or a Span
, people don't have to worry about that.
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.
Do you mean have one interface SpanObserver
that is used by the SpanBuilder
to notify, so it would potentially call onSetTag
and onAddReference
before onStart
, and then afterwards potentially have onSetTag
called other times before finally onFinish
?
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.
Correct. That's how I implemented this for stagemonitor: https://github.com/stagemonitor/stagemonitor/blob/master/stagemonitor-tracing/src/main/java/org/stagemonitor/tracing/wrapper/SpanEventListener.java
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 would be fine my me - although would like to get other feedback first before applying change.
* | ||
* @param finishMicros The finish time in microseconds | ||
*/ | ||
void onFinish(long finishMicros); |
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.
Maybe add Span
parameter similar to onStart
?
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.
None of the other methods (apart from onStart
) are supplied the Span
- what would be the purpose of adding it here?
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.
You could use the instance to set additional tags onFinish. Another use case is reporting. See also https://github.com/opentracing-contrib/java-span-reporter/blob/master/span-reporter/src/main/java/io/opentracing/contrib/reporter/Reporter.java#L22
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.
In both these cases the Observer instance could save the span supplied with the onStart
and reuse it when any of the other methods were invoked - although I understand the benefit if an impl was only interested in doing something onFinish
it would not require an Observer instance per span.
Currently the go observer only supplies it onStart
, so if we wanted to change the approach then would need to address it there aswell.
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.
it would not require an Observer instance per span.
That's the key point. In stagemonitor, I have the notion of a StatelessEventListener which is a single instance reused for all spans. This saves a lot of object instantiation and reduces GC overhead imposed by the agent.
Another feature my impl currently supports is altering and omitting of certain tags via the onSetTag method.
* | ||
* @param operationName The new operation name | ||
*/ | ||
void onSetOperationName(String operationName); |
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.
Note: the operation name can be set multiple times for a span and could also be set via the SpanBuilder. As you only know the operation name for certain when Span#finish
is invoked, in my impl onFinish has a operationName parameter.
@hkshaw1990 @bhs @yurishkuro @pavolloffay @jpkrohling As highlighted by @felixbarny an important issue to address is whether the |
My vote would be for both. Stateless observers can easily be implemented via stateful ones. See https://github.com/stagemonitor/stagemonitor/blob/0.80.0.RC1/stagemonitor-tracing/src/main/java/org/stagemonitor/tracing/wrapper/StatelessSpanEventListener.java. Another key question is wether the WrappedSpan should support readback of tags and other stuff as implemented in |
Agree that stateless can be implemented via stateful - but the issue is the observer API would need to pass the tags and references to some of the callbacks - so would require agreement on how this would be done. |
Before giving my vote, would it be possible to add some examples to the code repository, showing the use cases you had in mind? |
@tedsuo had a similar comment about stateless observers, with the same caveat - to do stateless we need some sort of read-back mechanism, e.g. for SpanID. |
If I understand this right, we probably would need a stateful span observer (atleast) from the perspective of a perfevents observer. In case of a perfevents observer, some metrics are opened for a span in |
Its true that there is no standard concept of span id in OpenTracing
currently, but that wouldn't necessarily prevent the Observer callbacks
supplying some form of correlation id that would be provided by the tracer
impl, but it would only be for local correlation purposes.
You mentioned metrics opened for `onSetTag()` - just curious what metrics
would be related to tags?
…On Tue, Jun 20, 2017 at 3:07 PM, Hemant Kumar ***@***.***> wrote:
If I understand this right, we probably would need a stateful span
observer (atleast) from the perspective of a perfevents observer. In case
of a perfevents observer, some metrics are opened for a span in onStart()
and onSetTag(), and those metrics are read and closed in onFinish(). We
need to maintain the contexts of those metrics somewhere. Considering that
there is no span observer per span (in case of stateless), we would need a
unique id for a span, which I am not sure if opentracing or a tracer impl
mandates that (correct me if I am wrong). However, since a stateless
approach will have smaller overhead, I am open to any suggestions to have a
stateless perfevents observer.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#3 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAKC0kCywTY2eMDevql8gpNOkX5nNE2Eks5sF9IxgaJpZM4N9ebI>
.
|
@objectiser regarding onSetTag(), I would need to monitor a span for platform (hardware) related metrics, i.e., as soon as a span is started with some tags or if a span is later tagged with something like : sp.SetTag("perfevents", "cpu-cycles,instructions"), in the callback, I would start monitoring these metrics from that point for that span. At onFinish(), these metrics need to be collected and the related file descriptors (event contexts) need to be closed. |
Next iteration - I think it addresses the previous comments - so provides support for stateful/less with a simple example of each. Each callback has access to the current state of the span via SpanData - so (for example) the finish method could access the latest operation name. The main issue is how to provide access to tags, when potentially multiple tags could be added with the same key. The spec does not clearly indicate whether this is supported, so wondering what the usecase is here - or whether it is just to support tracers that allow this? |
I think there are tracers which support it.
I think this can be handy. And also something to iterate over all tags? |
…calculate the duration, e.g. for reporting metrics
I am not so sure about the stateful approach for observer since you might keep two states (the span one and the spanObserver one). Are there any |
@jcchavezs In general I think the state maintained within a stateful observer will be observer specific - so the example I have added is misleading in that sense - because the stateful observer methods could obtain any span related data from the |
* be used within the application to uniquely distinguish one span from another, | ||
* to enable state to be maintained within observer implementation where appropriate. | ||
* | ||
* @return The unique id for the span |
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 would add that the critical requirement for the return value is to implement equals/hashCode to allow it to be used as a map key.
…ide example, removed example observer classes
Have updated the SpanObserver related to tags to just provide |
… useful in java-metrics
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.
LGTM, although I would prefer a different method name for the onSet...
methods.
* @param spanData The data for the span | ||
* @param operationName The new operation name | ||
*/ | ||
void onSetOperationName(SpanData spanData, String operationName); |
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.
Sorry I missed this on the first review, but wouldn't it be more semantically accurate to have Change
instead of Set
on the name? onOperationNameChange
for instance.
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.
The naming was supposed to reflect invocation of the method name following the on
- so in this case when the setOperationName
is called. But I have no problem with using a different convention.
Anyone else have a preference?
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 actually like onOperationNameChange(d)
as it hints that it can be called several times.
How does a implementor of the |
I have the same concern. We could return:
I think btw. javadoc does not say anything about it) |
* @return The correlation id for the span, MUST implement equals/hashCode to enable | ||
* it to be used as a map key | ||
*/ | ||
Object getCorrelationId(); |
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.
Without opentracing/specification#24, how should this be implemented in a Tracer implementation agnostic way?
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.
The only purpose of the returned value is to act as a key for looking up information that may have previously be cached for the span. Once the span is finished, it has no other purpose - i.e. it is not a long term reference to gain access to the span.
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 see. But can't SpanData itself be used as the map key then?
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.
Its possible, although I would prefer to have it separate. But open to other opinions.
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.
Maybe create a separate issue for that? Or should we agree on something before merging? Also, shouldn't the default equals/hashCode implementation (object identity) be good enough?
+1 on previous comments, that observer should only observe things and not change. Changes should be done in filters/interceptors. Do we want to put ALL these in the same repo? About the wrapper, certainly it is one possible impl but I thought we want to define an API which could be implemented by the tracer itself. If ^^ holds I see these two things as extensions to the current API, therefore names like |
The main reason I was proposing this is because it may be good for both observer and filter to have access to the |
Ok, then we might have a misconception. I thought this repo was about wrapping or decorating (maybe |
@felixbarny I don't think it needs to be one way or the other - a tracer could natively support the observer API but equally we could provide a wrapper as an alternative that takes on the management of observers. It would be good to offer options. |
Have created issues for the areas raised - including renaming the repo, as I think it would be better to get this PR merged first. So essentially there will be two APIs (currently) - Observer and Filter/Interceptor, and a default wrapper impl that provides support for managing these APIs outside the tracer impls. So to make progress would be good to just focus this PR on completing the observer API. Any comments on that topic welcome. |
I think this LGTM, if anyone from OTSC could review it would be 💯 |
* | ||
* @return The tags | ||
*/ | ||
Map<String,List<Object>> getTags(); |
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.
nit: missing space after comma
* @return The correlation id for the span, MUST implement equals/hashCode to enable | ||
* it to be used as a map key | ||
*/ | ||
Object getCorrelationId(); |
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.
Maybe create a separate issue for that? Or should we agree on something before merging? Also, shouldn't the default equals/hashCode implementation (object identity) be good enough?
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.
LGTM
@pavolloffay I'm happy to take a look (and actually have already taken a look) but felt that the discussion was so in-depth that it might not be helpful to have "another cook in the kitchen", esp since this is OT-contrib. Are there particular (somewhat-)open questions that would benefit from an additional perspective? |
@bhs apart from the "spin-off-issues" #7 and #6 I'd like to have another opinion about the modification of tag values via return values from onSetTag and on the Also, |
Based on @yurishkuro 's response in opentracing/specification#79 (comment) the Span API implies one tag value per key, even if some tracers may retain previous values - so this is implementation specific. Therefore it would seem more appropriate that the retrieval of the tags should take the same approach - be optimised for single value retrieval, but cater for multivalue if an implementation supports it and there are actually multiple values for a particular key. This could be achieved using If the untyped value is not desirable, then Thoughts? Votes? |
Ideally, the API for tags should provide:
Maybe it's better to go with the simplest approach and just assume there is one tag with the given key. Multi value tags can be spotted by |
This is quite problematic as a user of the method you can't be sure wether the tracer will return a List or a String. To write tracer agnostic code they would have to do an Iff we want to support multi value tags readback we should probably have two methods - |
Ok sounds like a plan :) - will simplify to |
you are right! To start yet another discussion (sorry about that) what about additional typed tag accessor methods? boolean getBooleanTag();
String getStringTag();
Number getNumberTag(); That would cut down on casts and instanceof checks. Personally, I don't quite like the idea to introduce a |
That should be fine - should If the requested type is not correct (apart from the above), should the method just return null or an exception? |
No
Not an easy one... As exceptions in monitoring code can be quite "dangerous" I'd vote for return null. |
@felixbarny @jpkrohling @yurishkuro @hkshaw1990 @pavolloffay Thanks all for the comments. Further work will be continued in the raised issues - but if there are any further points regarding the current API that need to be discussed, then please raise additional issues. Next step is to rename the repo. |
Initial stab at the observer API. Uses similar approach to https://github.com/opentracing-contrib/go-observer/blob/master/observer.go.
Main differences:
SpanBuilderObserver
to receive notifications related to the different steps in the builder process. If we want to collapse this into anTracerObserver.onStart
method, then we would need to decide how the tags and references would be supplied to the observer impl.SpanObserver
also includes methods for receiving notifcations about set/changed baggage and also logs. Baggage would be required by https://github.com/opentracing-contrib/java-metrics, and also potentially information from structured log events.