-
Notifications
You must be signed in to change notification settings - Fork 344
Introduce ActiveSpan, ActiveSpan.Continuation, and ActiveSpanSource #115
Changes from 35 commits
000a8c3
6e24189
5c6b992
cc71c24
2058413
d533226
6b10c9b
f63d20b
e88b0a9
26b23f3
e48d475
79880a4
e3ee448
56d01f9
54e6166
24178b9
281e5dc
4707b23
5b6f17f
619fcd9
b26fe7c
d87c1c7
b1468f7
4087c3e
b39fe6d
28223dd
a8e1a1d
9799fd4
9dd7be6
49a3548
1c250e9
8776bff
cd16c62
07ad79a
089c904
574a7d2
c28c44c
4718dfb
bc351dc
6539f4a
36bdb45
4d03cc5
b5ddc97
bf4606c
ae36949
20a3c67
9856c90
f1e5aa7
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 |
---|---|---|
|
@@ -18,6 +18,135 @@ to facilitate unit-testing of OpenTracing Java instrumentation. | |
|
||
Packages are deployed to Maven Central under the `io.opentracing` group. | ||
|
||
## Usage | ||
|
||
### Initialization | ||
|
||
Initialization is OpenTracing-implementation-specific. Generally speaking, the pattern is to initialize a `Tracer` once for the entire process and to use that `Tracer` for the remainder of the process lifetime. The [GlobalTracer](https://github.com/opentracing/opentracing-java/blob/master/opentracing-util/src/main/java/io/opentracing/util/GlobalTracer.java) provides a helper for singleton access to the `Tracer`. | ||
|
||
### `ActiveSpan`s, `Continuation`s, and within-process prapagation | ||
|
||
For any Thread, at most one `Span` may be "active". Of course there may be many other `Spans` involved with the Thread which are (a) started, (b) not finished, and yet (c) not "active": perhaps they are waiting for I/O, blocked on a child Span, or otherwise off of the critical path. | ||
|
||
It's inconvenient to pass an active `Span` from function to function manually, so OpenTracing provides an `ActiveSpanSource` abstraction to grant access to an `ActiveSpan` and to pin and `capture()` it for re-activation in another Thread (e.g., in an async callback). | ||
|
||
Access to the active `Span` is straightforward: | ||
|
||
``` | ||
io.opentracing.Tracer tracer = ...; | ||
... | ||
ActiveSpan span = tracer.activeSpan(); | ||
if (span != null) { | ||
span.log("..."); | ||
} | ||
``` | ||
|
||
### Starting a new Span | ||
|
||
The simplest case – which does not take advantage of `ActiveSpanSource` – looks like this: | ||
|
||
``` | ||
io.opentracing.Tracer tracer = ...; | ||
... | ||
Span span = tracer.buildSpan("someWork").startManual(); | ||
try { | ||
// (do things / record data to `span`) | ||
} finally { | ||
span.finish(); | ||
} | ||
``` | ||
|
||
Or, to take advantage of `ActiveSpanSource` and automatic intra-process propagation, like this: | ||
|
||
``` | ||
io.opentracing.Tracer tracer = ...; | ||
... | ||
try (ActiveSpan activeSpan = tracer.buildSpan("someWork").startActive()) { | ||
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. might be good to give the full API example first, i.e.
and then the same with using try-with-resource, as a shorthand. The try-finally example better explains the API imo, without "magic". 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 did something... |
||
// Do things. | ||
// | ||
// If we create async work, `activeSpan.capture()` allows us to pass the `ActiveSpan` along as well. | ||
} | ||
``` | ||
|
||
The above is semantically equivalent to the more explicit try-finally version: | ||
|
||
``` | ||
io.opentracing.Tracer tracer = ...; | ||
... | ||
ActiveSpan activeSpan = tracer.buildSpan("someWork").startActive(); | ||
try { | ||
// Do things. | ||
} finally { | ||
activeSpan.deactivate(); | ||
} | ||
``` | ||
|
||
|
||
**If there is an `ActiveSpan`, it will act as the parent to any newly started `Span`** unless the programmer invokes `ignoreActiveSpan()` at `buildSpan()` time, like so: | ||
|
||
``` | ||
io.opentracing.Tracer tracer = ...; | ||
... | ||
ActiveSpan span = tracer.buildSpan("someWork").ignoreActiveSpan().startActive(); | ||
``` | ||
|
||
### Deferring asynchronous work | ||
|
||
Consider the case where a `Span`'s lifetime logically starts in one thread and ends in another. For instance, the intra-Span timing breakdown might look like this: | ||
|
||
``` | ||
[ ServiceHandlerSpan ] | ||
|-FunctionA-|-----waiting on an RPC------|-FunctionB-| | ||
|
||
------------------------------------------------> time | ||
``` | ||
|
||
The `"ServiceHandlerSpan"` is _active_ when it's running FunctionA and FunctionB, and inactive while it's waiting on an RPC (presumably modelled as its own Span, though that's not the concern here). | ||
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 find it a bit confusing referring to functions as execution contexts. Maybe mention that functionB is running in a different thread? 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. That's not really what I meant... I was more referring to things like the MDC state that doesn't have to do with OT. I was also (inadvertently) using the term to refer to a thread a few lines up, though, and I've changed that. 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. There's one other occurance in L29 |
||
|
||
**The `ActiveSpanSource` makes it easy to `capture()` the Span and execution context in `FunctionA` and re-activate it in `FunctionB`.** Note that every `Tracer` must also implement `ActiveSpanSource`. These are the steps: | ||
|
||
1. Start the `ActiveSpan` via `Tracer.startActive()` rather than via `Tracer.startManual()`; or, if the `Span` was already started manually via `startManual()`, call `ActiveSpanSource#makeActive(span)`. Either route will yield an `ActiveSpan` instance that encapsulates the `Span`. | ||
2. In the method/function that *allocates* the closure/`Runnable`/`Future`/etc, call `ActiveSpan#capture()` to obtain an `ActiveSpan.Continuation` | ||
3. In the closure/`Runnable`/`Future`/etc itself, invoke `ActiveSpan.Continuation#activate` to re-activate the `ActiveSpan`, then `deactivate()` it when the Span is no longer active (or use try-with-resources for less typing). | ||
|
||
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. So many verbs in a small bit of text... start, activate, adopt, allocate, defer, re-activate and deactivate ... |
||
For example: | ||
|
||
``` | ||
io.opentracing.Tracer tracer = ...; | ||
... | ||
// STEP 1 ABOVE: start the ActiveSpan | ||
try (ActiveSpan serviceSpan = tracer.buildSpan("ServiceHandlerSpan").startActive()) { | ||
... | ||
|
||
// STEP 2 ABOVE: capture the ActiveSpan | ||
final ActiveSpan.Continuation cont = serviceSpan.capture(); | ||
doAsyncWork(new Runnable() { | ||
@Override | ||
public void run() { | ||
|
||
// STEP 3 ABOVE: use the Continuation to reactivate the Span in the callback. | ||
try (ActiveSpan activeSpan = cont.activate()) { | ||
... | ||
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. In the case where this Runnable exists solely/primarily to make a remote call to some other service it seems inconvenient to have to 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. Interesting idea. Typically the RPC instrumentation creates a child span just before making the RPC call, and in the same thread, even if the response is handled in the other thread. So the span and its context is usually available, without needing to use the Continuation to inject(...). And in case of synchronous calls forcing the creation of Continuation just to inject(...) is unnecessary overhead. 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 that it's an interesting idea... that said, I really like that the inject machinery only depends upon immutable SpanContexts... in various edge cases that's important. 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 a stupid question because I don't know much about Java. But in this example, if I have access to the outer someMethod() {
final Span serviceSpan = tracer.buildSpan("ServiceHandlerSpan").start();
serviceSpan.setTag("key1", "value");
doAsyncWork(new Runnable() {
@Override
public void run() {
serviceSpan.setTag("key3", "value");
serviceSpan.finish();
}
}
serviceSpan.setTag("key2", "value");
} Would this not be possible? 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. @cwe1ss there are two problems. The larger one is that the 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. oh yes - I didn't think about the first issue. thx for the explanation! I wonder if Java will get async/await as well one day. It makes it sooo much easier! |
||
} | ||
} | ||
}); | ||
} | ||
``` | ||
|
||
In practice, all of this is most fluently accomplished through the use of an OpenTracing-aware `ExecutorService` and/or `Runnable`/`Callable` adapter; they can factor most of the typing. | ||
|
||
#### Automatic `finish()`ing via `ActiveSpan` reference counts | ||
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'm happy with 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 the behavior of active span is different between implementations, then frameworks wouldn't know what the right way is to instrument their code. So the spec must be unambiguous that de-activating the last instance of the active span always finishes the span. Is there another way to achieve that without ref counting? 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. Whether there's an |
||
|
||
When an `ActiveSpan` is created (either via `Tracer.SpanBuilder#startActive` or `ActiveSpanSource#makeActive(Span)`), the reference count associated with the `ActiveSpan` is `1`. | ||
|
||
- When an `ActiveSpan.Continuation` is created via `ActiveSpan#capture`, the reference count **increments** | ||
- When an `ActiveSpan.Continuation` is `ActiveSpan.Continuation#activate()`d and thus transformed back into an `ActiveSpan`, the reference count **is unchanged** | ||
- When an `ActiveSpan` is `ActiveSpan#deactivate()`d, the reference count **decrements** | ||
|
||
When the reference count decrements to zero, **the `Span`'s `finish()` method is invoked automatically.** | ||
|
||
When used as designed, the programmer should not need to invoke `Span#finish()` manually, but rather should let `ActiveSpan` and `ActiveSpan.Continuation` invoke `finish()` as soon as the last active or deferred `ActiveSpan` is deactivated. | ||
|
||
# Development | ||
|
||
This is a maven project, and provides a wrapper, `./mvnw` to pin a consistent | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/** | ||
* Copyright 2016-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; | ||
|
||
import java.io.Closeable; | ||
|
||
/** | ||
* In any execution context (or any thread, etc), there is at most one "active" {@link Span}/{@link ActiveSpan} | ||
* primarily responsible for the work accomplished by the surrounding application code. That {@link ActiveSpan} may be | ||
* accessed via the {@link ActiveSpanSource#activeSpan()} method. If the application needs to capture work that should | ||
* be part of the same Span, the Source provides a {@link ActiveSpan#capture} method that returns a | ||
* {@link Continuation}; this continuation may be used to re-activate and continue the {@link Span} in that other | ||
* asynchronous executor and/or thread. | ||
* | ||
* <p> | ||
* {@link ActiveSpan}s are created via {@link Tracer.SpanBuilder#startActive()} or {@link ActiveSpanSource#makeActive}. | ||
* They can be {@link ActiveSpan#capture()}ed as {@link ActiveSpan.Continuation}s, then | ||
* re-{@link Continuation#activate()}d later. | ||
* | ||
* <p> | ||
* NOTE: {@link ActiveSpan} extends {@link Closeable} rather than {@code AutoCloseable} in order to keep support | ||
* for JDK1.6. | ||
* | ||
* @see ActiveSpanSource | ||
*/ | ||
public interface ActiveSpan extends Closeable, 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. Maybe explicitly override the
(the first is more important than the second bullit) |
||
/** | ||
* Mark the end of the active period for the {@link Span} pinned by this {@link ActiveSpan}. When the last | ||
* {@link ActiveSpan} is deactivated for a given {@link Span}, it is automatically {@link Span#finish()}ed. | ||
* <p> | ||
* NOTE: Calling {@link #deactivate} more than once on a single {@link ActiveSpan} instance is undefined behavior. | ||
* | ||
* @see Closeable#close() {@link ActiveSpan}s are auto-closeable and may be used in try-with-resources blocks | ||
*/ | ||
void deactivate(); | ||
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. Should it also restore the previous active span that was current before this one was activated? 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. That's certainly what an obvious impl does, but is that part of the spec? E.g., imagine an ActiveSpanSource that plugs into a totally-synchronous HTTP serving framework... it might define the next active Span whenever the next request gets serviced, and not before. 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'm still a little bit worried about situations when there are multiple ActiveSpans associated with the same span. So deactivation causes multiple finishes. The second potential issue is that finish does not imply deactivation. (maybe I am trying to find infallible solution to all undefined use cases, Actually, I don't think these use cases are undefined, I just trying to protect naive use of OT). 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 am not sure what to say about this... I definitely see your point and agree that there is a risk here. Personally, I'm ok with it, but it's unfortunately just a judgement call and I have no data to suggest that programmers won't trip over this. I basically want to get people out of the habit of calling So, to be clear: you would be happier if we wrote something like this in the spec/docs:
Correct? I am not convinced I want to put that sort of bookkeeping responsibility upon implementations (esp since it still creates a weird ambiguity about the tagging/logging features of the Span after finish has been called), but maybe we can agree on what the hypothetical change would be. 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'm not very sure about this situations either.. About: If somebody would call deactivate span would be finished at a wrong place. 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 don't want to be a total ignorant but I am still thinking about various use cases. I have something contra ref count approach: imagine you call
and span won't be finished. In general an instrumented callable is created but between its execution an error can happen and callable won't be called. shouldn't be refCount increment moved to 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.
Of course you are correct about this. IMO it means that the framework would need an actual (internal-to-framework) code change to make tracing sensible, at least when a threadlocal is involved. Not a great answer, but I don't see how we solve this with any approach that's optimized for threadlocals. As for the refcounting: I am pretty certain that the increment needs to happen at Thoughts?? 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. Why is 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 just read the explanation below (regarding reference counts etc), but isn't this still something that could be done within 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. 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. @cwe1ss this is the downside of having ActiveSpan inherit from Span... it saves typing, but then these two conceptually similar (but sadly not equivalent) things – Just thinking out loud, another idea (??) would be to have a sort of |
||
|
||
/** | ||
* A synonym for {@link #deactivate()} that can be used in try-with-resources blocks. | ||
*/ | ||
@Override | ||
void close(); | ||
|
||
/** | ||
* "Capture" a new {@link Continuation} associated with this {@link ActiveSpan} and {@link Span}, as well as any | ||
* 3rd-party execution context of interest. | ||
* | ||
* <p> | ||
* <em>IMPORTANT:</em> the caller MUST {@link Continuation#activate()} and {@link ActiveSpan#deactivate()} the | ||
* returned {@link Continuation} or the pinned {@link Span} will never automatically {@link Span#finish()}. That is, | ||
* calling {@link #capture()} increments a refcount that must be decremented somewhere else. | ||
* | ||
* <p> | ||
* The associated {@link Span} will not {@link Span#finish()} while a {@link Continuation} is outstanding; in | ||
* this way, it provides a reference/pin just like an {@link ActiveSpan} does. | ||
* | ||
* @return a new {@link Continuation} to {@link Continuation#activate()} at the appropriate time. | ||
*/ | ||
Continuation capture(); | ||
|
||
/** | ||
* A {@link Continuation} can be used *once* to activate a Span along with any non-OpenTracing execution context | ||
* (e.g., MDC), then deactivate when processing activity moves on to another Span. (In practice, this active | ||
* period typically extends for the length of a deferred async closure invocation.) | ||
* | ||
* <p> | ||
* Most users do not directly interact with {@link Continuation}, {@link Continuation#activate()} or | ||
* {@link ActiveSpan#deactivate()}, but rather use {@link ActiveSpanSource}-aware Runnables/Callables/Executors. | ||
* Those higher-level primitives need not be defined within the OpenTracing core API, and so they are not. | ||
* | ||
* @see ActiveSpanSource#makeActive(Span) | ||
*/ | ||
interface Continuation { | ||
/** | ||
* Make the Span (and other execution context) encapsulated by this Continuation active and return it. | ||
* | ||
* <p> | ||
* NOTE: It is an error to call activate() more than once on a single Continuation instance. | ||
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 should happen, an exception? 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 don't like throwing exceptions from monitoring code... maybe just explain that it's the dreaded "undocumented behavior"? 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. There are only three options how the implementation can handle it
Is there a reasonable / workable implementation for the first option? If not, then the second option is practically equivalent to the third, since NullPointerException will happen anyway. 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. Hm, I guess there's also
? 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. How important is it to forbid 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. What benefits in particular would have Maybe there is yet another option: 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. @pavolloffay the benefit is pretty simple: callers would not have to check for
vs.
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. @bhs yes this is obvious. I was thinking about other benefits. This is definitely an interesting topic. By using Btw. there are two places for
for 1. if it returns no/null caller would probably start a new trace in almost all situations. 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. ACK re "this is obvious" – just wanted to point out the main usability benefit. It's more 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.
These are different cases.
Another option would be adding a separate method, e.g. There's one more case where this comes into play - creating new span. tracer.buildSpan("span1")
.withTag("x", "y")
.childOf(source.activeSpan())
.start() is illegal. It has to be: SpanBuilder builder = tracer.buildSpan("span1")
.withTag("x", "y");
Span active = source.activeSpan();
if(active) {
builder.childOf(active)
}
builder.start() It does not look very good. But in this case returning new span from activeSpan does not seem helpful - when creating a span when there is no active one I wouldn't want to create implicitly an active span and then instantly start a child one. |
||
* | ||
* @see ActiveSpanSource#makeActive(Span) | ||
* @return a handle to the newly-activated Span | ||
*/ | ||
ActiveSpan activate(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/** | ||
* Copyright 2016-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; | ||
|
||
/** | ||
* {@link ActiveSpanSource} allows an existing (possibly thread-local-aware) execution context provider to act as a | ||
* source for an actively-scheduled OpenTracing Span. | ||
* | ||
* @see ActiveSpan | ||
*/ | ||
public interface ActiveSpanSource { | ||
|
||
/** | ||
* @return the {@link ActiveSpan active span}, or null if none could be found. This does not affect the reference | ||
* count for the {@link ActiveSpan}. | ||
*/ | ||
ActiveSpan activeSpan(); | ||
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'm not sure if this has already been discussed, but from a user's standpoint I'd prefer returning a If the tag is expensive to compute, it would however be beneficial if the user could differ between proper and noop spans. But rather than checking for I think this is something we should decide on before merging, or at least before releasing a new version as this would be a somewhat breaking change (although remaining binary compatibility) to introduce later (check for 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. Are there no valid use-cases where you need the null value? E.g. only create a span if there's no active one etc? the general isSampled() functionality is tracked by opentracing/specification#8 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. Probably there are use cases for that. But I think the default use case is to set simple tags or add logs. IMHO an API should be optimized for the default use case. So maybe add 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. @felixbarny this has already been discussed, yes. Unfortunately the github thread here is so convoluted that I can't even find the relevant comment. :-( I am 💯% happy to add an issue about this (and block release of a new version of OT-Java accordingly), but IMO it can be decoupled from this PR. Just to prep you for my point-of-view: I generally think instrumentation will either (a) create a new Span, in which case there's no need for a If we actually think that it's going to be commonplace to use the OT interface as the logging API (rather than a registrant of the logging API), then I would be in favor of what you propose. That seems like the essential question. (I'm less convinced about arguments involving tags: they are almost always set at start()-time in my experience) 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. +1 for the separate issue I think this would actually be the main api end users would use. The use case that I have in mind is when ot is used by an agent, users should still be able to add custon tags. For example, I've implemented a search analytics Kibana dashboard on top of stagemonitor and OT for a customer. It works by adding meta info about the search via tags like no of hits and the search term. For these kinds of things it would be nice if null checks could be avoided. |
||
|
||
/** | ||
* Wrap and "makeActive" a {@link Span} by encapsulating it – and any active state (e.g., MDC state) in the | ||
* execution context – in a new {@link ActiveSpan}. | ||
* | ||
* @param span the Span just started | ||
* @return an {@link ActiveSpan} that encapsulates the given Span and any other Source-specific context (e.g., | ||
* MDC data) | ||
*/ | ||
ActiveSpan makeActive(Span 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. Possibly asked before: why makeActive and not activate ? 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. @sjoerdtalsma @ivantopo I don't want to overload that word since it's used by It does bring up an interesting point / problem, though, about the 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 to say that we couldn't rename this method. I previously called it Note that this method will be used (very) rarely... As such, I think it's ok for it to be lengthy. 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. +1 agreed on not overloading the term |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/** | ||
* Copyright 2016 The OpenTracing Authors | ||
* Copyright 2016-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 | ||
|
@@ -21,7 +21,7 @@ | |
* | ||
* <p>Spans are created by the {@link Tracer#buildSpan} interface. | ||
*/ | ||
public interface Span extends Closeable { | ||
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. NB: 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 don't see 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. Ah, I had thought (incorrectly) that the |
||
public interface Span { | ||
/** | ||
* Retrieve the associated SpanContext. | ||
* | ||
|
@@ -34,8 +34,9 @@ public interface Span extends Closeable { | |
/** | ||
* Sets the end timestamp to now and records the span. | ||
* | ||
* <p>With the exception of calls to Span.context(), this should be the last call made to the span instance, and to | ||
* do otherwise leads to undefined behavior. | ||
* <p>With the exception of calls to {@link #context}, this should be the last call made to the span instance. | ||
* Future calls to {@link #finish} are defined as noops, and future calls to methods other than {@link #context} | ||
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 added this comment text to define multiple |
||
* lead to undefined behavior. | ||
* | ||
* @see Span#context() | ||
*/ | ||
|
@@ -53,8 +54,6 @@ public interface Span extends Closeable { | |
*/ | ||
void finish(long finishMicros); | ||
|
||
void close(); | ||
|
||
/** | ||
* Set a key:value tag on the Span. | ||
*/ | ||
|
@@ -74,14 +73,14 @@ public interface Span extends Closeable { | |
* Caveat emptor. | ||
* | ||
* <p>A contrived example (using Guava, which is not required): | ||
* <pre>{@code | ||
span.log( | ||
ImmutableMap.Builder<String, Object>() | ||
.put("event", "soft error") | ||
.put("type", "cache timeout") | ||
.put("waited.millis", 1500) | ||
.build()); | ||
}</pre> | ||
* <pre><code> | ||
span.log( | ||
ImmutableMap.Builder<String, Object>() | ||
.put("event", "soft error") | ||
.put("type", "cache timeout") | ||
.put("waited.millis", 1500) | ||
.build()); | ||
</code></pre> | ||
* | ||
* @param fields key:value log fields. Tracer implementations should support String, numeric, and boolean values; | ||
* some may also support arbitrary Objects. | ||
|
@@ -110,9 +109,9 @@ public interface Span extends Closeable { | |
* | ||
* Shorthand for | ||
* | ||
* <pre>{@code | ||
span.log(Collections.singletonMap("event", event)); | ||
}</pre> | ||
* <pre><code> | ||
span.log(Collections.singletonMap("event", event)); | ||
</code></pre> | ||
* | ||
* @param event the event value; often a stable identifier for a moment in the Span lifecycle | ||
* @return the Span, for chaining | ||
|
@@ -124,9 +123,9 @@ public interface Span extends Closeable { | |
* | ||
* Shorthand for | ||
* | ||
* <pre>{@code | ||
span.log(timestampMicroseconds, Collections.singletonMap("event", event)); | ||
}</pre> | ||
* <pre><code> | ||
span.log(timestampMicroseconds, Collections.singletonMap("event", event)); | ||
</code></pre> | ||
* | ||
* @param timestampMicroseconds The explicit timestamp for the log record. Must be greater than or equal to the | ||
* Span's start timestamp. | ||
|
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.
s/prapagation/propagation/
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.
other than this trivial typo, no further comments from me, thx.