-
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
Changes from 11 commits
3b3d363
63cfe5b
a233823
e94ac6e
65d1401
79dea5c
9be2556
5c10701
92b2224
f0faa91
5d38bba
d70fad0
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 |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/** | ||
* Copyright 2017 The OpenTracing Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except | ||
* in compliance with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License | ||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express | ||
* or implied. See the License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
package io.opentracing.contrib.observer; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* This interface provides information about the current {@link io.opentracing.Span} to the observer | ||
* methods. | ||
* | ||
*/ | ||
public interface SpanData { | ||
|
||
/** | ||
* This method returns an id that can be used for correlate actions invoked on a | ||
* stateful observer. It should only be used within the scope of an application, | ||
* to uniquely distinguish one span from another, to enable state to be maintained | ||
* within observer implementation where appropriate. | ||
* | ||
* @return The correlation id for the span, MUST implement equals/hashCode to enable | ||
* it to be used as a map key | ||
*/ | ||
Object getCorrelationId(); | ||
|
||
/** | ||
* The start time of the {@link io.opentracing.Span}. | ||
* | ||
* @return The start time (in microseconds) | ||
*/ | ||
long getStartTime(); | ||
|
||
/** | ||
* The finish time of the {@link io.opentracing.Span}. | ||
* | ||
* @return The finish time (in microseconds), or 0 if not available | ||
*/ | ||
long getFinishTime(); | ||
|
||
/** | ||
* The duration of the {@link io.opentracing.Span}. | ||
* | ||
* @return The duration (in microseconds), or 0 if the span is not finished | ||
*/ | ||
long getDuration(); | ||
|
||
/** | ||
* The operation name of the {@link io.opentracing.Span}. | ||
* | ||
* @return The operation name | ||
*/ | ||
String getOperationName(); | ||
|
||
/** | ||
* This method provides access to the tags associated with the span. If the | ||
* tracer implementation supports multiple values for a key, then only the | ||
* most recent value will be returned. | ||
* | ||
* @return The tags | ||
*/ | ||
Map<String, Object> getTags(); | ||
|
||
/** | ||
* This method retrieves a baggage item associated with the supplied key. | ||
* | ||
* @param key The key | ||
* @return The baggage item, or null if undefined | ||
*/ | ||
Object getBaggageItem(String key); | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/** | ||
* Copyright 2017 The OpenTracing Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except | ||
* in compliance with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License | ||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express | ||
* or implied. See the License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
package io.opentracing.contrib.observer; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* This interface represents an observer used to receive notifications related to a {@link io.opentracing.Span}. | ||
* | ||
*/ | ||
public interface SpanObserver { | ||
|
||
/** | ||
* Notifies the observer that the operation name has been changed. | ||
* | ||
* @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 commentThe 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 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. The naming was supposed to reflect invocation of the method name following the Anyone else have a preference? 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. I actually like |
||
|
||
/** | ||
* Notifies the observer that the tag with the supplied key has been set or updated | ||
* on a {@link io.opentracing.Span}. | ||
* | ||
* @param spanData The data for the span | ||
* @param key The tag key | ||
* @param value The tag value | ||
*/ | ||
void onSetTag(SpanData spanData, String key, Object value); | ||
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. I'd really like this method to be able to modify tags. One example: anonymizing IPs. See: https://github.com/stagemonitor/stagemonitor/blob/0.80.0.RC1/stagemonitor-tracing/src/main/java/org/stagemonitor/tracing/anonymization/AnonymizingSpanEventListener.java 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. Not sure I understand - do you mean modify the tag values in the observed span? 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. I mean modifying or omitting the tag value which is about to be set 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. I think that is out of scope for an observer which is essentially called after the fact. That sounds more like something a tracer wrapper should do? 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. If a wrapper is a superset of an observer lets make a wrapper then ;) 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. I think we are best of finding a middle ground - a combination of the wrapper and observer approach. I'm not proposing a full blown wrapper like a servlet filter with a filter chain for each span method. What I'm proposing is a very light-weight approach for modification of tags which does not require a "FilterChain" object: String onSetTag(String key, String value); Implementations can now influence the value. They can return it as-is if they don't want to modify it, return a different value or return null to omit adding the tag. I don't think this has a significantly higher overhead than a "pure" observer and we could handle more use cases with this approach. One more use case I have is to be able to configure a set of excluded tags. 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. I agree there are usecases, to bridge between framework instrumentations that generate a certain set of tags, and a tracer that is responsible for simply recording those tags. Having a way to plugin a tracer independent mechanism that can pre-process the tags and even logs would be good. However I still think it is better to have a distinction between Observer and something that could actively take part in controlling what information is being stored. One possibility is to have both concepts within the same repo - but have distinct APIs - Observer as now, dealing with the span lifecycle and change events, and a PreProcessor (TBD) that only has a few methods to e.g. allow changes to tags and logs? 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. @objectiser will be a new tag present in 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. Maybe we should clarify this somewhere in the javadoc. It should apply for the rest of the methods too 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. Agree this should be defined - my initial thought is that it is best post change, so that these callbacks could be performed asynchronously to not block the app or tracer. If the observer is interested in the previous state then it could cache the previous values itself. |
||
|
||
/** | ||
* Notifies the observer that the named baggage item has been set/changed. | ||
* | ||
* @param spanData The data for the span | ||
* @param key The baggage key | ||
* @param value The baggage value | ||
*/ | ||
void onSetBaggageItem(SpanData spanData, String key, String value); | ||
|
||
/** | ||
* Notifies the observer that a log event has been recorded. | ||
* | ||
* @param spanData The data for the span | ||
* @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the | ||
* Span's start timestamp. | ||
* @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; | ||
* some may also support arbitrary Objects. | ||
*/ | ||
void onLog(SpanData spanData, long timestampMicroseconds, Map<String, ?> fields); | ||
|
||
/** | ||
* Notifies the observer that a log event has been recorded. | ||
* | ||
* @param spanData The data for the span | ||
* @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the | ||
* Span's start timestamp. | ||
* @param event the event value; often a stable identifier for a moment in the Span lifecycle | ||
*/ | ||
void onLog(SpanData spanData, long timestampMicroseconds, String event); | ||
|
||
/** | ||
* Notifies the observer that a span associated with the supplied data has finished. | ||
* | ||
* @param spanData The data for the span | ||
* @param finishMicros The finish time in microseconds | ||
*/ | ||
void onFinish(SpanData spanData, 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.
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?