Skip to content

Commit

Permalink
in-process propagation resolves opentracing/specification#23
Browse files Browse the repository at this point in the history
  • Loading branch information
pavolloffay committed Mar 30, 2017
1 parent bc1983e commit 8cf3178
Show file tree
Hide file tree
Showing 16 changed files with 789 additions and 19 deletions.
13 changes: 10 additions & 3 deletions opentracing-api/src/main/java/io/opentracing/Span.java
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
Expand All @@ -22,16 +22,21 @@
* <p>Spans are created by the {@link Tracer#buildSpan} interface.
*/
public interface Span extends Closeable {

SpanManager.Visibility visibility();

/**
* Retrieve the associated SpanContext.
*
* This may be called at any time, including after calls to finish().
* This may be called at any time, including after calls to protectSpan().
*
* @return the SpanContext that encapsulates Span state that should propagate across process boundaries.
*/
SpanContext context();

/**
* Deactivates spans from spanManager.
*
* 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
Expand All @@ -42,12 +47,14 @@ public interface Span extends Closeable {
void finish();

/**
* Deactivates spans from spanManager.
*
* Sets an explicit end timestamp 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.
*
* @param finishMicros an explicit finish time, in microseconds since the epoch
* @param finishMicros an explicit protectSpan time, in microseconds since the epoch
*
* @see Span#context()
*/
Expand Down
70 changes: 70 additions & 0 deletions opentracing-api/src/main/java/io/opentracing/SpanManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* 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;

/**
* @author Pavol Loffay
*/
public interface SpanManager {

/**
* @param span span to bundle into visibility, there is always only one visibility per span
* @return visibility
*/
Visibility bundle(Span span);

/**
* @return not finished active span or null
*/
VisibilityContext active();

interface Visibility {
/**
* @return visibility context which is used to activate/deactivate span
*/
VisibilityContext capture();

/**
* @return associated span or null if visibility is marked as finished.
*/
Span span();
/**
* @return always spanContext
*/
SpanContext context();

/**
* Mark associated span as finished.
*
* Should be called by {@link Span#finish()} or directly if one does not want to expose span.
* This method should be idempotent.
*
* review note: reverse operation should not be allowed.
*/
void hideSpan();
}

interface VisibilityContext {
/**
* on/activate - {@link SpanManager#active()} will return this object.
*/
VisibilityContext on();
/**
* off/deactivate - {@link SpanManager#active()} will not return this object.
*/
VisibilityContext off();

Visibility visibility();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* 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.util.concurrent.atomic.AtomicBoolean;

/**
* @author Pavol Loffay
*/
public class ThreadLocalSpanManager implements SpanManager {

private final ThreadLocal<SimpleLinkedVisibilityContext> activeContext = new ThreadLocal<SimpleLinkedVisibilityContext>();

@Override
public Visibility bundle(Span span) {
return span.visibility() == null ? new SimpleVisibility(span) : span.visibility();
}

@Override
public SimpleLinkedVisibilityContext active() {
return activeContext.get();
}

class SimpleVisibility implements Visibility {
private final Span span;
private AtomicBoolean hideSpan = new AtomicBoolean(false);

public SimpleVisibility(Span span) {
this.span = span;
}

@Override
public Span span() {
return hideSpan.get() ? null : span;
}

@Override
public SpanContext context() {
return span.context();
}

@Override
public SimpleLinkedVisibilityContext capture() {
return new SimpleLinkedVisibilityContext(this);
}

@Override
public void hideSpan() {
hideSpan.set(true);
}
}

class SimpleLinkedVisibilityContext implements SpanManager.VisibilityContext {

private final SimpleVisibility visibility;
private SimpleLinkedVisibilityContext previous;

public SimpleLinkedVisibilityContext(SimpleVisibility visibility) {
this.visibility = visibility;
}

@Override
public SimpleLinkedVisibilityContext on() {
previous = activeContext.get();
activeContext.set(this);
return this;
}

@Override
public SimpleLinkedVisibilityContext off() {
if (this == activeContext.get()) {
activeContext.set(previous);
}
// else should not happen

return this;
}

@Override
public Visibility visibility() {
return visibility;
}
}
}
6 changes: 5 additions & 1 deletion opentracing-api/src/main/java/io/opentracing/Tracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
*/
public interface Tracer {

// span could be directly returned
SpanManager spanManager();

/**
* Return a new SpanBuilder for a Span with the given `operationName`.
*
Expand Down Expand Up @@ -113,6 +116,8 @@ interface SpanBuilder extends SpanContext {
*/
SpanBuilder addReference(String referenceType, SpanContext referencedContext);

SpanBuilder asRoot();

/** Same as {@link Span#setTag(String, String)}, but for the span being built. */
SpanBuilder withTag(String key, String value);

Expand All @@ -127,6 +132,5 @@ interface SpanBuilder extends SpanContext {

/** Returns the started Span. */
Span start();

}
}
2 changes: 1 addition & 1 deletion opentracing-api/src/main/java/io/opentracing/tag/Tags.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
package io.opentracing.tag;

/**
* The following span tags are recommended for instrumentors who are trying to capture more
* The following span tags are recommended for instrumentors who are trying to bundle more
* semantic information about the spans. Tracers may expose additional features based on these
* standardized data points. Tag names follow a general structure of namespacing.
*
Expand Down
20 changes: 20 additions & 0 deletions opentracing-mock/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,26 @@
<groupId>${project.groupId}</groupId>
<artifactId>opentracing-api</artifactId>
</dependency>

<!-- for MDC demo will go away -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.23</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.23</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>
22 changes: 19 additions & 3 deletions opentracing-mock/src/main/java/io/opentracing/mock/MockSpan.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentracing.SpanManager;

/**
* MockSpans are created via MockTracer.buildSpan(...), but they are also returned via calls to
Expand All @@ -29,6 +30,8 @@ public final class MockSpan implements Span {
// A simple-as-possible (consecutive for repeatability) id generator.
private static AtomicLong nextId = new AtomicLong(0);

private final SpanManager.Visibility visibility;

private final MockTracer mockTracer;
private MockContext context;
private final long parentId; // 0 if there's no parent.
Expand Down Expand Up @@ -66,10 +69,10 @@ public long startMicros() {
return startMicros;
}
/**
* @return the finish time of the Span; only valid after a call to finish().
* @return the protectSpan time of the Span; only valid after a call to protectSpan().
*/
public long finishMicros() {
assert finishMicros > 0 : "must call finish() before finishMicros()";
assert finishMicros > 0 : "must call markAsFinished() before finishMicros()";
return finishMicros;
}

Expand All @@ -93,6 +96,11 @@ public List<RuntimeException> generatedErrors() {
return new ArrayList<>(errors);
}

@Override
public SpanManager.Visibility visibility() {
return visibility;
}

@Override
public synchronized MockContext context() {
return this.context;
Expand All @@ -107,6 +115,7 @@ public void finish() {
public synchronized void finish(long finishMicros) {
finishedCheck("Finishing already finished span");
this.finishMicros = finishMicros;
visibility.hideSpan();
this.mockTracer.appendFinishedSpan(this);
this.finished = true;
}
Expand Down Expand Up @@ -248,10 +257,17 @@ public long timestampMicros() {
}
}

MockSpan(MockTracer tracer, String operationName, long startMicros, Map<String, Object> initialTags, MockContext parent) {
MockSpan(MockTracer tracer, String operationName, long startMicros, Map<String, Object> initialTags, MockContext
parent, boolean activate) {
this.mockTracer = tracer;
this.operationName = operationName;
this.startMicros = startMicros;

this.visibility = tracer.spanManager().bundle(this);
if (activate) {
this.visibility.capture().on();
}

if (initialTags == null) {
this.tags = new HashMap<>();
} else {
Expand Down
Loading

0 comments on commit 8cf3178

Please sign in to comment.