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 d10ea16
Show file tree
Hide file tree
Showing 14 changed files with 777 additions and 9 deletions.
7 changes: 6 additions & 1 deletion 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,6 +22,9 @@
* <p>Spans are created by the {@link Tracer#buildSpan} interface.
*/
public interface Span extends Closeable {

SpanManager.Visibility visibility();

/**
* Retrieve the associated SpanContext.
*
Expand All @@ -42,6 +45,8 @@ 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
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();

}
}
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>
18 changes: 17 additions & 1 deletion 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 @@ -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
34 changes: 30 additions & 4 deletions opentracing-mock/src/main/java/io/opentracing/mock/MockTracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import io.opentracing.References;
import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentracing.SpanManager;
import io.opentracing.ThreadLocalSpanManager;
import io.opentracing.Tracer;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap;
Expand All @@ -38,16 +40,22 @@
public class MockTracer implements Tracer {
private List<MockSpan> finishedSpans = new ArrayList<>();
private final Propagator propagator;
private final SpanManager spanManager;

public MockTracer() {
this(Propagator.PRINTER);
this(Propagator.PRINTER, new ThreadLocalSpanManager());
}

/**
* Create a new MockTracer that passes through any calls to inject() and/or extract().
*/
public MockTracer(Propagator propagator) {
this(propagator, new ThreadLocalSpanManager());
}

public MockTracer(Propagator propagator, SpanManager spanManager) {
this.propagator = propagator;
this.spanManager = spanManager;
}

/**
Expand Down Expand Up @@ -144,9 +152,14 @@ public <C> MockSpan.MockContext extract(Format<C> format, C carrier) {
};
}

@Override
public SpanManager spanManager() {
return spanManager;
}

@Override
public SpanBuilder buildSpan(String operationName) {
return new SpanBuilder(operationName);
return new SpanBuilder(operationName, spanManager);
}

@Override
Expand All @@ -170,8 +183,14 @@ public final class SpanBuilder implements Tracer.SpanBuilder {
private MockSpan.MockContext firstParent;
private Map<String, Object> initialTags = new HashMap<>();

SpanBuilder(String operationName) {
SpanBuilder(String operationName, SpanManager spanManager) {
this.operationName = operationName;

SpanManager.VisibilityContext inferredParent = spanManager.active();
if (inferredParent != null) {
addReference(inferredParent.visibility().span() == null ? References.FOLLOWS_FROM : References.CHILD_OF,
inferredParent.visibility().span().context());
}
}
@Override
public SpanBuilder asChildOf(SpanContext parent) {
Expand All @@ -192,6 +211,12 @@ public SpanBuilder addReference(String referenceType, SpanContext referencedCont
return this;
}

@Override
public Tracer.SpanBuilder asRoot() {
firstParent = null;
return this;
}

@Override
public SpanBuilder withTag(String key, String value) {
this.initialTags.put(key, value);
Expand Down Expand Up @@ -221,7 +246,8 @@ public MockSpan start() {
if (this.startMicros == 0) {
this.startMicros = MockSpan.nowMicros();
}
return new MockSpan(MockTracer.this, this.operationName, this.startMicros, initialTags, this.firstParent);
return new MockSpan(MockTracer.this, this.operationName, this.startMicros, initialTags,
this.firstParent, false);
}

@Override
Expand Down
Loading

0 comments on commit d10ea16

Please sign in to comment.