Skip to content
This repository has been archived by the owner on May 23, 2023. It is now read-only.

Commit

Permalink
V0.32.0 (#337)
Browse files Browse the repository at this point in the history
* Deprecate the StringTag.set() overload taking a StringTag. (#262)
* Implement Trace Identifiers. (#280)
* Bump JaCoCo to use a Java 10 friendly version (#306)
* Remove finish span on close (#301)
  * Deprecate finishSpanOnClose on activation.
  * Add ScopeManager.activeSpan() and Tracer.activateSpan().
  * Clarify the API changes and deprecations.
  * Add an error reporting sample to opentracing-testbed.
* Simple layer on top of ByteBuffer for BINARY format. (#276)
* Add generic typed setTag/withTag (#311)
* Allow injecting into maps of type Map<String,Object> (#310)
* Add simple registerIfAbsent to global tracer (#289)
* Split Inject and Extract Builtin interfaces (#316)
* Deprecate ScopeManager.active() (#326)
* Make Tracer extends Closable. (#329)
* Do not make isRegistered() synchronized. (#333)
* Deprecate AutoFinishScopeManager (#335)
  • Loading branch information
carlosalberto authored Mar 25, 2019
1 parent 6a0f42e commit ed1925b
Show file tree
Hide file tree
Showing 87 changed files with 1,832 additions and 405 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ env:
# Ex. travis encrypt -r org/repo BINTRAY_KEY=xxx-https://bintray.com/profile/edit-xxx --add
- secure: "PAtbtImeyHnjFR+yPVKggZgXb4oMXchM6YV3+qoYs6LExiqhwRPe4e+gAhfLESHUjiEoixAM77eAuk3Cqpklwtpy3Qwh3ptDtNm1d3VycDbhMVHkeIGaCJlHTitJHwegAHedrqH4qS3sRCG1Ke5Dxs1z1NtuLnIKhoiWKMW9SdNuLt+Wo+uYJnlr2Z78AVrChSsV4CiaJ5jZlFhRHO+cf22Xdx69Z2Imh7/3X+WBXIKqqNewegBlzvtQzZsknhFHmQV8UTJ1lCw6EcGOw5DXqqcRGmkRMsITeGMaUMd21Es2MeIHVsNS6aysLeAF15pbo3C9nhGJ11JWwNaeBVSpK+s8friNEOssJdvn+2W/NKrEHeKcEDwZRqKbOqUeGkwHb4n2nZd3oqc6/0O4Wf3q4bB1Dsh1PpL0tE5oeIbeUT0JMpk+MHIxzHyt5HuPnNqCk09psNbr110DiYNNddJKZOcv/hfxTuao55tbcg7C1tWYYcFxyMN3hE+EOEqhs3e4vOldFZSuF4/3lLYKBPl+Uin8eIUdzNQ01L3iy+FdB1haLS9V+kr72ZYABW0VdAj3Sw2GGsLsv5Xw2p8U3rcJBRm4mzrMSdfdN9YX2pOA/1Ch9rOiercKoy0hg2Q8PkORBJcOKS4uGPAAqrazAkpdih+sDTn7Sq+6sN1UNUR33fw="
# Ex. travis encrypt -r org/repo GH_TOKEN=XXX-https://github.com/settings/tokens-XXX --add
- secure: "n8Vv4rxhnRpLzhqj3j/iuduN4GeeB8UnyIS/mXnwViZ88L/EwGzpwXkV42igoXpTlafZzCRPwQC8q9hcut0T37F6cbVW8S1oGc8BdLNwiHve8JLRdA4f+0HUgzQeS8N/o2Dkgf41Ku105NR8JXtCezi7NxaL73ugp5NpqGKHriM91sYjQh7iU+2u7HxzGWPVt3DYKL5Qhvbr41FQCi01pRwOf51Xj4UCbn8xle0lEGXsaI1sBl+lABsLhIl5Eoc97GxFM9TXiKP35/BDlJ12Y9pa6i1swbhb5sgS/Zcbr8px55+1qa/AcG9lHoSwwoqwTlDLuWKC9TJ7NhwzkYa0w20/k5pfWYyO+W69JWb3+WEOObCii1td6D+u9Cyy8IL9cXTedADaBEQCfIITqXMqI311Lt3mR4YLJ3q7JiHs8YBoLQb6xpkeZqHbhWXdIuuOyMBlkO0nSpfXend1Skzwok0s0iIsOIYjjRe/QVpKFlQECDxJDUPQqAarbhaodh5wL50t71+kYTYmw5uou3Qb+Cm5ZUkJmK01qya6lE3Oa0GHTJiK5qiciA0O0yVQtf7uwuBnRvN/b6EvwWdJpTUUYYM25yBY4v8oI/z4gcD0RMC0AZVj8em6KmbWhYduSDLgsNm+EYQ/9ziJTYEWP2Obd4BhOcSVxUEPn7aLVz6WGtw="
- secure: "p1Z3Y8cbgEpOrlejqzoR91DGlrdkCjaErDn1EfUj7AdB+B1KtYvy6XGMRfB2YTiHucK/4wFFbxgkchoqDWM/N8h+oCDi0ogJ1BmIFsb4alQJnotrDSrpI4fxAK+e0jlNrLi9PYYEftSVVh71lo6zKIE41wflK+wm90XJtf56cOSDd7q7Xip2qPP5OXcpu49Arce60+jCp2jLa+4pMiqvXQAZTsrkXdMDiPYgRfNqjT5qJ+fTNF/soIH0Vdy3yEbwrx/CwRSxumZ3ntyXZ7bxiUIMjRIhwO50nigBNJzHJqYaeguEKhfugWk+iSqxaZf9LVbSfG3c/IsvCFzna8BjSs9SV9DUe8a7x7OcvU3wlnSd4bPCvv4QDLsLfbbxhNbYg3asvRHUAOXxudA5LoLK+eZwD74efr/CHyU1uTPMwgNHUxPeLHFQJRYjq1+NTQFkp/Dc+DC8oYRv/Tf1eSHgg5d3j84eU/cClSsACf9Lt3GLziDmJCkctPA22CkrWULKSn/DrvsJqYfoBpof4AM1QBPIB2MuKuk1nHJ+vhBnfeP4bKFsMjZWZrRcWw9zt2zl7NVJFh/W4wMHiq75ZF+Z7msYKCB22e7buMTnDqNBapO6PEXmk6972Q00QmI+rFMYGEpRDgbxZixMVRcPL+89EWhAZplfbI+YiOoSZQEFPNU="
# Ex. travis encrypt -r org/repo SONATYPE_USER=your_sonatype_account
- secure: "oE16AjpS/aabLRNkQN6SmyfYJwCwBqYOvqyhPPZCYDYfZpBtJHugUXdds9GYc6BXfgPKF3QJQ727dPqXrmbh9UPkSyE1LYv1De/HbGsPmwBn+S2fg1Id2BrV3qVPg7aYaO8EX0zIxfh5BxY0woC4Lj9Wl5EbTYf00h/JhCaKr1ZYR9/gzG8Ngyexr+FLlKFCKhka+3iEcwCz8feyxcPCsgGo3TiNI42Q9cLGpqGAuStQcwUZe2296qQd1Zn9khZYpP5bm7+mOCI62xXI+PEIES+ss/kB8b9pfUiHgfxtKS6gs4I3oDEelJw3fjrHdsgMs6YfLTPp9yKMMqSIzcp4dmqOf5zxadCKQ+eETervLJEngZAwzuAvdeh8/9Az8eN96FDfKWrf8tkbkdzY9Ajqk5qra4vx87ChQ/u6Am9OV6dqwIBU4i7sBUa55jXQns8gE2nT+R0xAM57Arolr768QriPAiUlom8AmeUryUWj1S8JC+jjNhw0v9wFk2JEkrY1WBrCStnCYAPZ3CP5uoNGsQS42t0Cd05TtjHjnJE8EHfHHFiWSF1+ov7GkAQQXqH473T1Be7HPJo9EQ5PRsea5li2AtTU80dBuCaeqBnE6Tm1kuiVDrDo3kO/+C5fjF065z1Xvl42pcJhlYH/uNItQbGiFfcBP6hT3szVIDeSElc="
# Ex. travis encrypt -r org/repo SONATYPE_PASSWORD=your_sonatype_password
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changes by Version

## v0.32.0 (2019-03-20)

* Trace Identifiers added to `SpanContext`.
* Finishing `Span` upon Scope close is deprecated overall.
* `ScopeManager.active()` is deprecated.
* `SpanBuilder.startActive()` is deprecated.
* `AutoFinishScopeManager` is deprecated.
* Added a new `Binary` format on top of `ByteBuffer`.
* Added generic typed `setTag()`/`withTag()` versions.
* Split Inject and Extract builtin interfaces.
* `Tracer` implements `Closable`.
* Added `GlobalTracer.registerIfAbsent()`.

## v0.31.0 (2018-01-12)
* `BaseSpan` and `ActiveSpan` are simplified into a single `Span` class.
* `Scope` replaces `ActiveSpan`, removing `Continuations`.
Expand Down
87 changes: 32 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,36 +26,30 @@ That said, instrumentation for packages that are themselves statically configure

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 requires that every `Tracer` contains a `ScopeManager` that grants access to the active `Span` through a `Scope`. Any `Span` may be transferred to another callback or thread, but not `Scope`; more on this below.
It's inconvenient to pass an active `Span` from function to function manually, so OpenTracing requires that every `Tracer` contains a `ScopeManager` that grants access to the active `Span` along with a `Scope` to signal deactivation. Any `Span` may be transferred to another callback or thread, but not `Scope`; more on this below.

#### Accessing the active Span through `Scope`
#### Accessing the active Span

Access to the active span is straightforward:

```java
io.opentracing.Tracer tracer = ...;
...
Scope scope = tracer.scopeManager().active();
if (scope != null) {
scope.span().log("...");
Span span = tracer.scopeManager().activeSpan();
if (span != null) {
span.log("...");
}
```

### Starting a new Span

The common case starts a `Scope` that's automatically registered for intra-process propagation via `ScopeManager`.

Note that `startActive(true)` finishes the span on `Scope.close()`.
Use it carefully because the `try-with-resources` construct finishes the span before
the `catch` or `finally` blocks are executed, which makes logging exceptions and
setting tags impossible. It is recommended to start the span and activate it later in `try-with-resources`.
This makes the span available in catch and finally blocks.
The common case starts a `Span` and then sets it as the active instance via `ScopeManager`:

```java
io.opentracing.Tracer tracer = ...;
...
Span span = tracer.buildSpan("someWork").start();
try (Scope scope = tracer.scopeManager().activate(span, false)) {
try (Scope scope = tracer.scopeManager().activate(span)) {
// Do things.
} catch(Exception ex) {
Tags.ERROR.set(span, true);
Expand All @@ -65,27 +59,13 @@ try (Scope scope = tracer.scopeManager().activate(span, false)) {
}
```

The following code uses `try-with-resources` to finish the span.

```java
io.opentracing.Tracer tracer = ...;
...
try (Scope scope = tracer.buildSpan("someWork").startActive(true)) {
// Do things.
//
// `scope.span()` allows us to pass the `Span` to newly created threads.
} catch(Exception ex) {
// cannot record the exception in the span since scope is not accessible and span is finished
}
```

**If there is a `Scope`, it will act as the parent to any newly started `Span`** unless
**If there is already an active `Span`, it will act as the parent to any newly started `Span`** unless
the programmer invokes `ignoreActiveSpan()` at `buildSpan()` time or specified parent context explicitly:

```java
io.opentracing.Tracer tracer = ...;
...
Scope scope = tracer.buildSpan("someWork").ignoreActiveSpan().startActive();
Span span = tracer.buildSpan("someWork").ignoreActiveSpan().start();
```

### Deferring asynchronous work
Expand All @@ -101,31 +81,32 @@ Consider the case where a `Span`'s lifetime logically starts in one thread and e

The `"ServiceHandlerSpan"` is _active_ while 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).

**The `ScopeManager` API makes it possible to fetch the `span()` in `FunctionA` and re-activate it in `FunctionB`.** Note that every `Tracer` contains a `ScopeManager`. These are the steps:
**The `ScopeManager` API makes it possible to fetch the `span` in `FunctionA` and re-activate it in `FunctionB`.** Note that every `Tracer` contains a `ScopeManager`. These are the steps:

1. Start a `Span` via either `startManual` or `startActive(false)` to prevent the `Span` from being finished upon `Scope` deactivation.
2. In the closure/`Runnable`/`Future`/etc itself, invoke `tracer.scopeManager().activate(span, false)` to re-activate the `Span` and get a new `Scope`, then `deactivate()` it when the `Span` is no longer active (or use try-with-resources for less typing).
3. In the closure/`Runnable`/`Future`/etc where the end of the task is reached, invoke `tracer.scopeManager().activate(span, true)` to re-activate the `Span` and have the new `Scope` close the `Span` automatically.
1. Start a `Span` via `start`.
2. At the beginning of the closure/`Runnable`/`Future`/etc itself, invoke `tracer.scopeManager().activate(span)` to re-activate the `Span` and get a new `Scope`, then `close()` it when the `Span` is no longer active (or use try-with-resources for less typing).
3. Invoke `span.finish()` when the work is done.

For example:
Here is an example using `CompletableFuture`:

```java
io.opentracing.Tracer tracer = ...;
...
// STEP 1 ABOVE: start the Scope/Span
try (Scope scope = tracer.buildSpan("ServiceHandlerSpan").startActive(false)) {
// STEP 1 ABOVE: start the Span.
final Span span = tracer.buildSpan("ServiceHandlerSpan").start();
try (Scope scope = tracer.scopeManager().activate(span)) {
// Do work.
...
final Span span = scope.span();
doAsyncWork(new Runnable() {
@Override
public void run() {

// STEP 2 ABOVE: reactivate the Span in the callback, passing true to
// startActive() if/when the Span must be finished.
try (Scope scope = tracer.scopeManager().activate(span, false)) {
...
}

future = CompletableFuture.supplyAsync(() -> {

// STEP 2 ABOVE: reactivate the Span in the callback.
try (Scope scope = tracer.scopeManager().activate(span)) {
...
}
}).thenRun(() -> {
// STEP 3 ABOVE: finish the Span when the work is done.
span.finish();
});
}
```
Expand All @@ -134,17 +115,13 @@ Observe that passing `Scope` to another thread or callback is not supported. Onl

In practice, all of this is most fluently accomplished through the use of an OpenTracing-aware `ExecutorService` and/or `Runnable`/`Callable` adapter; they factor out most of the typing.

## Compatibility with Opentracing 0.30
## Deprecated members since 0.31

For users supporting instrumentation code using Opentracing 0.30, there is a [0.30 compatibility package](https://github.com/opentracing/opentracing-java-v030) that can be used to wrap a 0.31 `Tracer` and expose it as a 0.30 `Tracer`:
`ScopeManager.active(Span, boolean)` and `SpanBuilder.startActive()` have been deprecated as part of removing automatic `Span` finish upon `Scope` close, as doing it through try-with statements would make it hard to properly handle errors (`Span` objects would get finished before a catch block would be reached).
This improves API safety, and makes it more difficult to do the wrong thing and end up with unexpected errors.

```java
io.opentracing.Tracer upstreamTracer = ...;
io.opentracing.v_030.Tracer tracer = new TracerShim(upstreamTracer);
try (ActiveSpan span = tracer.buildSpan("ServiceHandlerSpan").startActive()) {
...
}
```
`Scope.span()` and `ScopeManager.scope()` have been deprecated in order to prevent the anti-pattern of passing `Scope` objects between threads (`Scope` objects are not guaranteed to be thread-safe).
Now `Scope` will be responsible for `Span` deactivation only, instead of being a `Span` container.

## Instrumentation Tests

Expand Down
2 changes: 1 addition & 1 deletion opentracing-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<parent>
<groupId>io.opentracing</groupId>
<artifactId>parent</artifactId>
<version>0.31.1-SNAPSHOT</version>
<version>0.32.0-RC3-SNAPSHOT</version>
</parent>

<artifactId>opentracing-api</artifactId>
Expand Down
9 changes: 7 additions & 2 deletions opentracing-api/src/main/java/io/opentracing/Scope.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
*/
public interface Scope extends Closeable {
/**
* Mark the end of the active period for the current thread and {@link Scope},
* updating the {@link ScopeManager#active()} in the process.
* Mark the end of the active period for the current context (usually a thread)
* and {@link Scope}, updating {@link ScopeManager#active()} and {@link ScopeManager#activeSpan()}
* in the process.
*
* <p>
* NOTE: Calling {@link #close} more than once on a single {@link Scope} instance leads to undefined
Expand All @@ -37,7 +38,11 @@ public interface Scope extends Closeable {
void close();

/**
* @deprecated use {@link Span} directly or access it through {@link ScopeManager#activeSpan()}
* Return the corresponding active {@link Span} for this instance.
*
* @return the {@link Span} that's been scoped by this {@link Scope}
*/
@Deprecated
Span span();
}
89 changes: 77 additions & 12 deletions opentracing-api/src/main/java/io/opentracing/ScopeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,100 @@

/**
* The {@link ScopeManager} interface abstracts both the activation of {@link Span} instances via
* {@link ScopeManager#activate(Span, boolean)} and access to an active {@link Span}/{@link Scope}
* via {@link ScopeManager#active()}.
* {@link ScopeManager#activate(Span)} and access to an active {@link Span}
* via {@link ScopeManager#activeSpan()}.
*
* @see Scope
* @see Tracer#scopeManager()
*/
public interface ScopeManager {

/**
* Make a {@link Span} instance active.
* Set the specified {@link Span} as the active instance for the current
* context (usually a thread).
*
* @param span the {@link Span} that should become the {@link #active()}
* @param finishSpanOnClose whether span should automatically be finished when {@link Scope#close()} is called
* <p>
* The returned {@link Scope} represents the active state for the span.
* Once its active period is due, {@link Scope#close()} ought to be called.
* To ease this operation, {@link Scope} supports try-with-resources.
* Observe the span will not be automatically finished when {@link Scope#close()}
* is called.
*
* <p>
* The corresponding {@link Span} can be accessed at any time through {@link #activeSpan()}.
*
* <p>
* Usage:
* <pre><code>
* Span span = tracer.buildSpan("...").start();
* try (Scope scope = tracer.scopeManager().activate(span)) {
* span.setTag("...", "...");
* ...
* } catch (Exception e) {
* span.log(...);
* } finally {
* // Optionally finish the Span if the operation it represents
* // is logically completed at this point.
* span.finish();
* }
* </code></pre>
*
* @param span the {@link Span} that should become the {@link #activeSpan()}
* @return a {@link Scope} instance to control the end of the active period for the {@link Span}. It is a
* programming error to neglect to call {@link Scope#close()} on the returned instance.
*/
Scope activate(Span span, boolean finishSpanOnClose);
Scope activate(Span span);

/**
* Return the currently active {@link Scope} which can be used to access the currently active
* {@link Scope#span()}.
* @deprecated use {@link #activeSpan()} instead.
* Return the currently active {@link Scope} which can be used to deactivate the currently active
* {@link Span}.
*
* <p>
* Observe that {@link Scope} is expected to be used only in the same thread where it was
* created, and thus should not be passed across threads.
*
* <p>
* If there is an {@link Scope non-null scope}, its wrapped {@link Span} becomes an implicit parent
* (as {@link References#CHILD_OF} reference) of any
* newly-created {@link Span} at {@link Tracer.SpanBuilder#startActive(boolean)} or {@link SpanBuilder#start()}
* time rather than at {@link Tracer#buildSpan(String)} time.
* Because both {@link #active()} and {@link #activeSpan()} reference the current
* active state, they both will be either null or non-null.
*
* @return the {@link Scope active scope}, or null if none could be found.
*/
@Deprecated
Scope active();

/**
* Return the currently active {@link Span}.
*
* <p>
* Because both {@link #active()} and {@link #activeSpan()} reference the current
* active state, they both will be either null or non-null.
*
* @return the {@link Span active span}, or null if none could be found.
*/
Span activeSpan();

/**
* @deprecated use {@link #activate(Span)} instead.
* Set the specified {@link Span} as the active instance for the current
* context (usually a thread).
*
* <p>
* Finishing the {@link Span} upon {@link Scope#close()} is discouraged,
* as reporting errors becomes impossible:
* <pre><code>
* try (Scope scope = tracer.scopeManager().activate(span, true)) {
* } catch (Exception e) {
* // Not possible to report errors, as
* // the span has been already finished.
* }
* </code></pre>
*
* @param span the {@link Span} that should become the {@link #activeSpan()}
* @param finishSpanOnClose whether span should automatically be finished when {@link Scope#close()} is called
* @return a {@link Scope} instance to control the end of the active period for the {@link Span}. It is a
* programming error to neglect to call {@link Scope#close()} on the returned instance.
*/
@Deprecated
Scope activate(Span span, boolean finishSpanOnClose);
}
4 changes: 4 additions & 0 deletions opentracing-api/src/main/java/io/opentracing/Span.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
package io.opentracing;

import io.opentracing.tag.Tag;
import java.util.Map;

/**
Expand Down Expand Up @@ -44,6 +45,9 @@ public interface Span {
/** Same as {@link #setTag(String, String)}, but for numeric values. */
Span setTag(String key, Number value);

/** Same as {@link #setTag(String, String)}, but with using Tag<T>. */
<T> Span setTag(Tag<T> tag, T value);

/**
* Log key:value pairs to the Span with the current walltime timestamp.
*
Expand Down
24 changes: 24 additions & 0 deletions opentracing-api/src/main/java/io/opentracing/SpanContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,30 @@
* @see Span#getBaggageItem(String)
*/
public interface SpanContext {
/**
* Return the ID of the trace.
*
* Should be globally unique. Every span in a trace shares this ID.
*
* An empty String will be returned if the tracer does not support this functionality
* (this is the case for no-op tracers, for example). null is an invalid return value.
*
* @return the trace ID for this context.
*/
String toTraceId();

/**
* Return the ID of the associated Span.
*
* Should be unique within a trace. Each span within a trace contains a different ID.
*
* An empty String will be returned if the tracer does not support this functionality
* (this is the case for no-op tracers, for example). null is an invalid return value.
*
* @return the Span ID for this context.
*/
String toSpanId();

/**
* @return all zero or more baggage items propagating along with the associated Span
*
Expand Down
Loading

0 comments on commit ed1925b

Please sign in to comment.