Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
43db7b5
add 'common handler' test
malafeev Aug 13, 2017
26b97cd
Add an example for multiple callbacks for an active span.
carlosalberto Aug 15, 2017
661a6ff
apply received feedback
malafeev Aug 15, 2017
1930580
fix thread name
malafeev Aug 15, 2017
6b4e518
Let the Logger format the message instead of concatenating values.
carlosalberto Aug 15, 2017
9d9e3f5
Reverse the sleep time for the threads in TestMultipleCallbacks.
carlosalberto Aug 15, 2017
697321c
Merge pull request #1 from carlosalberto/multiple_callbacks
malafeev Aug 15, 2017
7b0720a
Add an example of nested callbacks.
carlosalberto Aug 17, 2017
8205f1f
Merge pull request #2 from carlosalberto/nested_callbacks
malafeev Aug 17, 2017
6ba0b1c
Add a late-finish Span example.
carlosalberto Aug 17, 2017
c1390b0
Add an example for an active span being temporary replaced.
carlosalberto Aug 17, 2017
0904ea2
Merge pull request #3 from carlosalberto/actives_replacement
malafeev Aug 18, 2017
dcbaab7
Merge pull request #4 from carlosalberto/late_span_finish
malafeev Aug 18, 2017
211e8be
one more check
malafeev Aug 18, 2017
bf5ac9a
use one Random, return Future
malafeev Aug 18, 2017
e925d86
refactoring + one more case for parent-span issue
malafeev Aug 18, 2017
5209880
Make all tests pass with the Scope API
bhs Aug 13, 2017
f91856c
Update the latest examples with the Scope prototype.
carlosalberto Aug 22, 2017
f62b2e8
Update the README with instructions to build/test the PR.
carlosalberto Aug 23, 2017
a144e92
Clarify the PR installation step/need.
carlosalberto Aug 23, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,34 @@ tester examples of common instrumentation patterns

[ci-img]: https://travis-ci.org/opentracing-contrib/java-examples.svg?branch=master
[ci]: https://travis-ci.org/opentracing-contrib/java-examples

## Testing against a Java Opentracing PR/branch.

In order to test these examples against https://github.com/bhs/opentracing-java/pull/5, you have to fetch the PR locally, and then install it in local Maven repository (required once only):

$ cd opentracing_java/
$ git remote add bhs https://github.com/bhs/opentracing-java
$ git fetch bhs pull/5/head:bhs/scopes
$ git checkout bhs/scopes
$ mvn compile install

By default the version for a build looks like `0.30.1-SNAPSHOT`, which helps to keep the stable and the testing one side by side.

Next, look for the `<properties>` section in the `pom.xml` file under this directory, updating the `opentracing` version; and also add a dependency to the `usecases` package:

```xml
<opentracing.version>0.30.1-SNAPSHOT</opentracing.version>
...
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-usecases</artifactId>
<version>${opentracing.version}</version>
<scope>test</scope>
</dependency>
```

Finally, run (under this directory as well):

$ mvn test

Any further changes under this repository will not need re-installing anything, simply re-running this last command.
41 changes: 38 additions & 3 deletions src/test/java/io/opentracing/contrib/examples/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
import io.opentracing.mock.MockSpan;
import io.opentracing.mock.MockTracer;
import io.opentracing.tag.AbstractTag;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

public class TestUtils {

Expand All @@ -17,13 +22,43 @@ public Integer call() throws Exception {
};
}

public static MockSpan getByTag(List<MockSpan> spans, AbstractTag key, Object value) {
public static MockSpan getOneByTag(List<MockSpan> spans, AbstractTag key, Object value) {
List<MockSpan> found = new ArrayList<>();
for (MockSpan span : spans) {
if (span.tags().get(key.getKey()).equals(value)) {
return span;
found.add(span);
}
}
return null;
if (found.size() > 1) {
throw new RuntimeException("Ups, it's too much");
}
return found.isEmpty() ? null : found.get(0);
}

public static void sleep() {
try {
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(2000));
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}

public static void sleep(long milliseconds) {
try {
TimeUnit.MILLISECONDS.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}

public static void sortByStartMicros(List<MockSpan> spans) {
Collections.sort(spans, new Comparator<MockSpan>() {
@Override
public int compare(MockSpan o1, MockSpan o2) {
return Long.compare(o1.startMicros(), o2.startMicros());
}
});
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package io.opentracing.contrib.examples.activate_deactivate;

import io.opentracing.ActiveSpan;
import io.opentracing.ActiveSpan.Continuation;
import io.opentracing.Scope;
import io.opentracing.usecases.AutoFinishScopeManager;
import io.opentracing.usecases.AutoFinishScopeManager.AutoFinishScope;
import io.opentracing.tag.Tags;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -15,27 +17,34 @@ public class Callback implements Runnable {

private static final Logger logger = LoggerFactory.getLogger(Callback.class);

private final Continuation continuation;
private final Random random = new Random();

Callback(ActiveSpan activeSpan) {
continuation = activeSpan.capture();
private final AutoFinishScope.Continuation continuation;

Callback(Scope activeSpan) {
continuation = ((AutoFinishScope)activeSpan).defer();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

casting doesn't look nice. What if it's not AutoFinishScope?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey!

So, if you are talking about the chance of Scope not being a AutoFinishScope here, I can add the check for sanity purposes (even though we know that for this example, we always get an Auto one :) )

But if you are talking about doing such cast overall - that's a reason to try to include the defer and Continuation api into the main interface (i.e. io.opentracing.Scope)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, my concern about generic use case

logger.info("Callback created");
}

/**
* Can be used continuation.activate().deactivate() chain only. It is splitted for testing
* purposes (span should not be finished before deactivate() called here).
*/
@Override
public void run() {
logger.info("Callback started");
ActiveSpan activeSpan = continuation.activate();

Scope scope = continuation.activate();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}

activeSpan
.setTag(Tags.HTTP_STATUS.getKey(), 200); // we need it to test that finished span has it
activeSpan.deactivate();
// set random tag starting with 'test_tag_' to test that finished span has all of them
scope.span().setTag("test_tag_" + random.nextInt(), "random");

scope.close();
logger.info("Callback finished");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;

import io.opentracing.ActiveSpan;
import io.opentracing.Scope;
import io.opentracing.Scope.Observer;
import io.opentracing.mock.MockSpan;
import io.opentracing.mock.MockTracer;
import io.opentracing.mock.MockTracer.Propagator;
import io.opentracing.tag.Tags;
import io.opentracing.util.ThreadLocalActiveSpanSource;
import io.opentracing.usecases.AutoFinishScopeManager;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -23,10 +27,15 @@ public class TestCallback {

private static final Logger logger = LoggerFactory.getLogger(TestCallback.class);

private final MockTracer tracer = new MockTracer(new ThreadLocalActiveSpanSource(),
Propagator.TEXT_MAP);
private final MockTracer tracer = new MockTracer(Propagator.TEXT_MAP);
private final ScheduledExecutorService service = Executors.newScheduledThreadPool(1);

@Before
public void before() {
tracer.reset();
tracer.setScopeManager(new AutoFinishScopeManager());
}

@Test
public void test() throws Exception {
Thread entryThread = entryThread();
Expand All @@ -39,7 +48,34 @@ public void test() throws Exception {
List<MockSpan> finished = tracer.finishedSpans();
assertEquals(1, finished.size());

assertEquals(200, finished.get(0).tags().get(Tags.HTTP_STATUS.getKey()));
assertEquals(1, getTestTagsCount(finished.get(0)));
}

@Test
public void test_two_callbacks() throws Exception {
Thread entryThread = entryThreadWithTwoCallbacks();
entryThread.start();
entryThread.join(10_000);
// Entry thread is completed but Callbacks are still running (or even not started)

await().atMost(15, TimeUnit.SECONDS).until(reportedSpansSize(tracer), equalTo(1));

List<MockSpan> finished = tracer.finishedSpans();
assertEquals(1, finished.size());

// Check that two callbacks finished and each added to span own tag ('test_tag_{random}')
assertEquals(2, getTestTagsCount(finished.get(0)));
}

private int getTestTagsCount(MockSpan mockSpan) {
Map<String, Object> tags = mockSpan.tags();
int tagCounter = 0;
for (String tagKey : tags.keySet()) {
if (tagKey.startsWith("test_tag_")) {
tagCounter++;
}
}
return tagCounter;
}

/**
Expand All @@ -50,15 +86,40 @@ private Thread entryThread() {
@Override
public void run() {
logger.info("Entry thread started");
ActiveSpan activeSpan = tracer.buildSpan("parent").startActive();
Runnable callback = new Callback(activeSpan);

// Callback is executed at some unpredictable time and we are not able to check status of the callback
service.schedule(callback, 500, TimeUnit.MILLISECONDS);
try (Scope scope = tracer.buildSpan("parent").startActive()) {
Runnable callback = new Callback(scope);

// Callback is executed at some unpredictable time and we are not able to check status of the callback
service.schedule(callback, 500, TimeUnit.MILLISECONDS);
}

activeSpan.deactivate();
logger.info("Entry thread finished");
}
});
}

/**
* Thread will be completed before callback completed.
*/
private Thread entryThreadWithTwoCallbacks() {
return new Thread(new Runnable() {
@Override
public void run() {
logger.info("Entry thread 2x started");
try (Scope scope = tracer.buildSpan("parent").startActive()) {
Runnable callback = new Callback(scope);
Runnable callback2 = new Callback(scope);

Random random = new Random();

// Callbacks are executed at some unpredictable time
service.schedule(callback, random.nextInt(1000) + 100, TimeUnit.MILLISECONDS);
service.schedule(callback2, random.nextInt(1000) + 100, TimeUnit.MILLISECONDS);

}
logger.info("Entry thread 2x finished");
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package io.opentracing.contrib.examples.active_span_replacement;

import static com.jayway.awaitility.Awaitility.await;
import static io.opentracing.contrib.examples.TestUtils.reportedSpansSize;
import static io.opentracing.contrib.examples.TestUtils.sleep;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;

import io.opentracing.Scope;
import io.opentracing.Scope.Observer;
import io.opentracing.Span;
import io.opentracing.mock.MockSpan;
import io.opentracing.mock.MockTracer;
import io.opentracing.mock.MockTracer.Propagator;
import io.opentracing.util.ThreadLocalScopeManager;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import org.junit.Before;
import org.junit.Test;

public class TestActiveSpanReplacement {

private final MockTracer tracer = new MockTracer(Propagator.TEXT_MAP);

private final ExecutorService executor = Executors.newCachedThreadPool();

@Before
public void before() {
tracer.reset();
tracer.setScopeManager(new ThreadLocalScopeManager());
}

@Test
public void test() throws Exception {
/* Start an isolated task and query for its result -and finish it- in another task/thread */
Span span = tracer.buildSpan("initial").startManual();
submitAnotherTask(span);

await().atMost(15, TimeUnit.SECONDS).until(reportedSpansSize(tracer), equalTo(3));

List<MockSpan> spans = tracer.finishedSpans();
assertEquals(3, spans.size());
assertEquals("initial", spans.get(0).operationName()); /* Isolated task. */
assertEquals("subtask", spans.get(1).operationName());
assertEquals("task", spans.get(2).operationName());

/* task/subtask are part of the same trace,
* and subtask is a child of task */
assertEquals(spans.get(1).context().traceId(), spans.get(2).context().traceId());
assertEquals(spans.get(2).context().spanId(), spans.get(1).parentId());

/* initial task is not related in any way to those two tasks */
assertNotEquals(spans.get(0).context().traceId(), spans.get(1).context().traceId());
assertEquals(0, spans.get(0).parentId());

assertNull(tracer.scopeManager().active());
}

private void submitAnotherTask(final Span span) {

executor.submit(new Runnable() {
@Override
public void run () {
/* Create a new Span for this task */
try (Scope taskSpan = tracer.buildSpan("task").startActive(Observer.FINISH_ON_CLOSE)) {

/* Simulate work strictly related to the initial Span. */
try (Scope initialSpan = span.activate(Observer.FINISH_ON_CLOSE)) {
sleep(50);
}

/* Restore the span for this task and create a subspan */
try (Scope subTask = tracer.buildSpan("subtask").startActive(Observer.FINISH_ON_CLOSE)) {
}
}
}
});
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.opentracing.contrib.examples.client_server;

import io.opentracing.ActiveSpan;
import io.opentracing.Scope;
import io.opentracing.Scope.Observer;
import io.opentracing.Tracer;
import io.opentracing.propagation.Format.Builtin;
import io.opentracing.propagation.TextMapInjectAdapter;
Expand All @@ -17,19 +18,13 @@ public Client(ArrayBlockingQueue<Message> queue, Tracer tracer) {
this.tracer = tracer;
}

public void send() {
public void send() throws InterruptedException {
Message message = new Message();

ActiveSpan activeSpan = tracer.buildSpan("send").startActive();
activeSpan.setTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT);
tracer.inject(activeSpan.context(), Builtin.TEXT_MAP, new TextMapInjectAdapter(message));

try {
try (Scope scope = tracer.buildSpan("send").startActive(Observer.FINISH_ON_CLOSE)) {
scope.span().setTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT);
tracer.inject(scope.span().context(), Builtin.TEXT_MAP, new TextMapInjectAdapter(message));
queue.put(message);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
activeSpan.deactivate();
}
}

Expand Down
Loading