Skip to content
This repository has been archived by the owner on Jul 1, 2022. It is now read-only.

Add a ActiveSpanSource backed TraceContext #266

Merged
merged 10 commits into from
Oct 11, 2017
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
1 change: 1 addition & 0 deletions jaeger-apachehttpclient/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dependencies {
compile group: 'org.apache.httpcomponents', name: 'httpclient', version: apacheHttpComponentsVersion
compile group: 'org.apache.httpcomponents', name: 'httpasyncclient', version: apacheHttpComponentsVersion

testCompile project(path: ':jaeger-core', configuration: 'tests')
testCompile group: 'org.mock-server', name: 'mockserver-netty', version: '3.10.4'
testCompile group: 'junit', name: 'junit', version: junitVersion
testCompile group: 'org.mockito', name: 'mockito-core', version: mockitoVersion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import com.uber.jaeger.reporters.InMemoryReporter;
import com.uber.jaeger.samplers.ConstSampler;
import com.uber.jaeger.samplers.Sampler;
import com.uber.jaeger.utils.TestUtils;
import io.opentracing.util.GlobalTracer;
import java.util.List;
import org.apache.http.HttpHost;
import org.apache.http.concurrent.FutureCallback;
Expand All @@ -32,6 +34,7 @@
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.message.BasicHttpRequest;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand Down Expand Up @@ -64,6 +67,7 @@ public void setUp() {
reporter = new InMemoryReporter();
Sampler sampler = new ConstSampler(true);
tracer = new Tracer.Builder("test_service", reporter, sampler).build();
GlobalTracer.register(tracer);

parentSpan = (Span) tracer.buildSpan("parent_operation").startManual();
parentSpan.setBaggageItem(BAGGAGE_KEY, BAGGAGE_VALUE);
Expand All @@ -72,6 +76,11 @@ public void setUp() {
TracingUtils.getTraceContext().push(parentSpan);
}

@After
public void tearDown() throws Exception {
TestUtils.resetGlobalTracer();
}

@Test
public void testAsyncHttpClientTracing() throws Exception {
HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom();
Expand Down
1 change: 1 addition & 0 deletions jaeger-context/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ description = 'A library for thread-local context and utility methods for propag

dependencies {
compile group: 'io.opentracing', name: 'opentracing-api', version: opentracingVersion
compile group: 'io.opentracing', name: 'opentracing-util', version: opentracingVersion

// Testing Frameworks
testCompile group: 'junit', name: 'junit', version: junitVersion
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2017, Uber Technologies, Inc
*
* 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 com.uber.jaeger.context;

import io.opentracing.ActiveSpan;
import io.opentracing.ActiveSpanSource;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.util.GlobalTracer;
import io.opentracing.util.ThreadLocalActiveSpan;

import java.lang.reflect.Field;

/**
* This is a {@link TraceContext} that relies on the {@link ActiveSpanSource} registered with {@link
* GlobalTracer}.
*/
public class ActiveSpanSourceTraceContext implements TraceContext {
Copy link
Member

Choose a reason for hiding this comment

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

Are you sure we need a new class instead of changing ThreadLocalTraceContext? If someone is already using ThreadLocalTraceContext directly, then it won't work correctly any longer, so I think it warrants a breaking API change (namely having an argument to the constructor).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could also simply remove the ThreadLocalTraceContext instead of marking it @Deprecated

Copy link
Member

Choose a reason for hiding this comment

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

why create extra churn with classes/filenames/history when we can reuse the same class and re-implement it as needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could you provide justification for sticking with the old name?

The new name is more descriptive.

Javac itself doesn't care about what this class used to be called.

As far as git goes, it uses binary blobs to track file content. I expect it to be able to handle this operation efficiently. Have you seen examples where it hasn't? Should we be optimizing for git history size?


/**
* This is a hack to retrieve the span wrapped by the {@link ThreadLocalActiveSpan} implementation
Copy link
Member

Choose a reason for hiding this comment

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

let's mention that this is a temporary hack until 0.31

* to shoehorn into the {@link TraceContext} implementation. This is being done so that
* instrumentation relying on {@link Tracer} is consistent with instrumentation using {@link
* TraceContext}. We expect to remove this when opentracing-api version 0.31 is released.
*/
private static final Field wrappedSpan;

static {
try {
wrappedSpan = ThreadLocalActiveSpan.class.getDeclaredField("wrapped");
wrappedSpan.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unable to access ThreadLocalActiveSpan.wrapped reflectively.", e);
}
}

public ActiveSpanSourceTraceContext() {
}

/** Makes the span active. */
@Override
public void push(Span span) {
GlobalTracer.get().makeActive(span);
}

/** Deactivates the current active span. */
@Override
public Span pop() {
ActiveSpan activeSpan = GlobalTracer.get().activeSpan();
Span span = getSpan(activeSpan);
activeSpan.deactivate();
return span;
}

/** Retrieves the current active span. */
@Override
public Span getCurrentSpan() {
ActiveSpan activeSpan = GlobalTracer.get().activeSpan();
return getSpan(activeSpan);
}

@Override
public boolean isEmpty() {
return GlobalTracer.get().activeSpan() == null;
}

private Span getSpan(ActiveSpan activeSpan) {
Span span;
try {
span = (Span) wrappedSpan.get(activeSpan);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}

return span;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,28 @@

package com.uber.jaeger.context;

import io.opentracing.util.GlobalTracer;

import java.util.concurrent.ExecutorService;

public class TracingUtils {
private static final TraceContext traceContext = new ThreadLocalTraceContext();
private static TraceContext traceContext = new ActiveSpanSourceTraceContext();

public static TraceContext getTraceContext() {
assertGlobalTracerIsRegistered();
return traceContext;
}

public static ExecutorService tracedExecutor(ExecutorService wrappedExecutorService) {
assertGlobalTracerIsRegistered();
return new TracedExecutorService(wrappedExecutorService, traceContext);
}

private TracingUtils(){}
private static void assertGlobalTracerIsRegistered() {
if (!GlobalTracer.isRegistered()) {
throw new IllegalStateException("Please register a io.opentracing.util.GlobalTracer.");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@yurishkuro I felt it was simpler to use GlobalTracer.get() directly in ActiveSpanSourceTraceContext. It makes tests dirtier, but it's temporary code.
What is your opinion on the assertGlobalTracerIsRegistered check?

Copy link
Member

Choose a reason for hiding this comment

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

why not pass it the GlobalTracer.INSTANCE as we discussed? By using GlobalTracer directly you're introducing tight coupling in the new class, which didn't need to happen.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The type of GlobalTracer.INSTANCE is GlobalTracer and I didn't see that as being particularly advantageous because it still couples ActiveSpanSourceTraceContext to the implementation of GlobalTracer.

}
}

private TracingUtils() {}
}
11 changes: 11 additions & 0 deletions jaeger-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,20 @@ shadowJar {
classifier 'okhttp381'
}

task testJar(type: Jar, dependsOn: testClasses) {
baseName = "test-${project.archivesBaseName}"
from sourceSets.test.output
}

configurations {
tests
}

artifacts {
archives(shadowJar.archivePath) {
builtBy shadowJar
}
tests testJar
}

task jaegerVersion {
Expand All @@ -43,3 +53,4 @@ task jaegerVersion {
}

compileJava.dependsOn jaegerVersion

29 changes: 29 additions & 0 deletions jaeger-core/src/test/java/com/uber/jaeger/utils/TestUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2017, The Jaeger 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 com.uber.jaeger.utils;

import io.opentracing.NoopTracerFactory;
import io.opentracing.util.GlobalTracer;

import java.lang.reflect.Field;

public class TestUtils {
public static void resetGlobalTracer() throws NoSuchFieldException, IllegalAccessException {
// Reset opentracing's global tracer
Field field = GlobalTracer.class.getDeclaredField("tracer");
field.setAccessible(true);
field.set(null, NoopTracerFactory.create());
}
}
1 change: 1 addition & 0 deletions jaeger-dropwizard/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dependencies {
compile group: 'io.dropwizard.metrics', name: 'metrics-core', version: '3.1.0'
compile group: 'io.dropwizard', name: 'dropwizard-hibernate', version: '0.9.1'

testCompile project(path: ':jaeger-core', configuration: 'tests')
testCompile group: 'org.glassfish.jersey.containers', name: 'jersey-container-grizzly2-http', version: jerseyVersion
testCompile group: 'org.glassfish.jersey.test-framework.providers', name: 'jersey-test-framework-provider-grizzly2', version: jerseyVersion
testCompile group: 'junit', name: 'junit', version: junitVersion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import com.uber.jaeger.context.TracingUtils;
import com.uber.jaeger.reporters.InMemoryReporter;
import com.uber.jaeger.samplers.ConstSampler;
import com.uber.jaeger.utils.TestUtils;
import io.opentracing.util.GlobalTracer;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
Expand All @@ -32,6 +34,7 @@
import javax.ws.rs.core.Response;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.After;
import org.junit.Test;

public class JerseyServerFilterTest extends JerseyTest {
Expand All @@ -46,11 +49,18 @@ protected Application configure() {

ResourceConfig resourceConfig = new ResourceConfig(HelloResource.class,
StormlordResource.class);
GlobalTracer.register(tracer);
undertest = new JerseyServerFilter(tracer, TracingUtils.getTraceContext());
resourceConfig.register(undertest);
return resourceConfig;
}

@After
public void tearDown() throws Exception {
super.tearDown();
TestUtils.resetGlobalTracer();
}

@Path("hello")
public static class HelloResource {
@GET
Expand Down
2 changes: 2 additions & 0 deletions jaeger-jaxrs2/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ dependencies {
compile project(':jaeger-core')
compile project(':jaeger-context')

testCompile project(path: ':jaeger-core', configuration: 'tests')
testCompile group: 'org.glassfish.jersey.containers', name: 'jersey-container-grizzly2-http', version: jerseyVersion
testCompile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: jerseyVersion
testCompile group: 'org.glassfish.jersey.core', name: 'jersey-client', version: jerseyVersion
testCompile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: jerseyVersion
testCompile group: 'org.glassfish.jersey.media', name: 'jersey-media-moxy', version: jerseyVersion
testCompile group: 'org.glassfish.jersey.test-framework.providers', name: 'jersey-test-framework-provider-grizzly2', version: jerseyVersion
testCompile group: 'junit', name: 'junit', version: junitVersion
testCompile group: 'org.mockito', name: 'mockito-core', version: mockitoVersion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,13 @@ public void filter(
// hitting this case means previous filter was not called
return;
}
serverSpan = traceContext.pop();
serverSpan = traceContext.getCurrentSpan();

Tags.HTTP_STATUS.set(serverSpan, containerResponseContext.getStatus());
serverSpan.finish();

// We are relying on the ActiveSpanSource implementation to `close` the span, and
// hence don't need to call `finish`.
traceContext.pop();
Copy link
Member

Choose a reason for hiding this comment

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

please add comments explaining this order (i.e. that we cannot call pop as before since it will deactivate & finish the span).

Copy link
Member

Choose a reason for hiding this comment

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

is this the only place in the whole project where we call pop?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do. No, we call it in our wrapped Callable and Runnable

} catch (Exception e) {
log.error("Server Filter Response:", e);
}
Expand Down
Loading