Skip to content

Commit b6259b8

Browse files
committed
Support for OpenTracing 0.33.0
1 parent 118cf5c commit b6259b8

File tree

7 files changed

+254
-30
lines changed

7 files changed

+254
-30
lines changed

build.gradle

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,13 @@ dependencies {
4343
implementation 'com.amazonaws:aws-java-sdk-kinesis:1.11.163'
4444
implementation 'com.amazonaws:aws-java-sdk-dynamodb:1.11.163'
4545
implementation 'com.googlecode.json-simple:json-simple:1.1'
46-
implementation('io.opentracing:opentracing-api:0.31.0')
47-
implementation('io.opentracing:opentracing-util:0.31.0')
48-
implementation('io.opentracing:opentracing-noop:0.31.0')
46+
implementation('io.opentracing:opentracing-api:0.33.0')
47+
implementation('io.opentracing:opentracing-util:0.33.0')
48+
implementation('io.opentracing:opentracing-noop:0.33.0')
4949

5050
testImplementation 'junit:junit:4.12'
51-
testImplementation 'io.opentracing:opentracing-mock:0.31.0'
51+
testImplementation 'org.hamcrest:hamcrest-library:1.3'
52+
testImplementation 'io.opentracing:opentracing-mock:0.33.0'
5253
}
5354

5455
jar {
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.newrelic.opentracing.aws;
2+
3+
import io.opentracing.Span;
4+
import io.opentracing.SpanContext;
5+
import io.opentracing.Tracer;
6+
7+
public class EnhancedSpanBuilder {
8+
private final Tracer.SpanBuilder spanBuilder;
9+
10+
public static EnhancedSpanBuilder basedOn(Tracer tracer, String operationName) {
11+
return new EnhancedSpanBuilder(tracer.buildSpan(operationName));
12+
}
13+
14+
private EnhancedSpanBuilder(Tracer.SpanBuilder innerSpanBuilder) {
15+
spanBuilder = innerSpanBuilder;
16+
}
17+
18+
public EnhancedSpanBuilder asChildOf(SpanContext spanContext) {
19+
this.spanBuilder.asChildOf(spanContext);
20+
return this;
21+
}
22+
23+
/** Same as {@link Span#setTag(String, String)}, but for the span to be built. */
24+
EnhancedSpanBuilder withTag(String key, String value) {
25+
this.spanBuilder.withTag(key, value);
26+
return this;
27+
}
28+
29+
/** Same as {@link Span#setTag(String, boolean)}, but for the span to be built. */
30+
EnhancedSpanBuilder withTag(String key, boolean value) {
31+
this.spanBuilder.withTag(key, value);
32+
return this;
33+
}
34+
35+
/** Same as {@link Span#setTag(String, Number)}, but for the span to be built. */
36+
EnhancedSpanBuilder withTag(String key, Number value) {
37+
this.spanBuilder.withTag(key, value);
38+
return this;
39+
}
40+
41+
/**
42+
* A shorthand for withTag("key", "value").
43+
*
44+
* <p>If parent==null, this is a noop.
45+
*/
46+
EnhancedSpanBuilder optionallyWithTag(String key, String value) {
47+
if (value != null) {
48+
this.spanBuilder.withTag(key, value);
49+
}
50+
return this;
51+
}
52+
53+
EnhancedSpanBuilder optionallyWithTag(String key, boolean value) {
54+
if (value) {
55+
this.spanBuilder.withTag(key, true);
56+
}
57+
return this;
58+
}
59+
60+
EnhancedSpanBuilder optionallyWithTag(String key, Number value) {
61+
if (value != null) {
62+
this.spanBuilder.withTag(key, value);
63+
}
64+
return this;
65+
}
66+
67+
public Span start() {
68+
return this.spanBuilder.start();
69+
}
70+
}

src/main/java/com/newrelic/opentracing/aws/HeadersParser.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import io.opentracing.SpanContext;
1010
import io.opentracing.Tracer;
1111
import io.opentracing.propagation.Format;
12-
import io.opentracing.propagation.TextMapExtractAdapter;
12+
import io.opentracing.propagation.TextMapAdapter;
1313
import java.util.Map;
1414

1515
final class HeadersParser {
@@ -23,12 +23,12 @@ static <Input> SpanContext parseAndExtract(Tracer tracer, Input input) {
2323
final Object headers = map.get("headers");
2424
if (headers instanceof Map) {
2525
final Map<String, String> headerStr = (Map<String, String>) headers;
26-
return tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapExtractAdapter(headerStr));
26+
return tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapAdapter(headerStr));
2727
}
2828
} else if (input instanceof com.amazonaws.Request) {
2929
final Request request = (Request) input;
3030
final Map<String, String> headers = request.getHeaders();
31-
return tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapExtractAdapter(headers));
31+
return tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapAdapter(headers));
3232
}
3333
} catch (IllegalArgumentException exception) {
3434
}

src/main/java/com/newrelic/opentracing/aws/SpanUtil.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,29 @@
66
package com.newrelic.opentracing.aws;
77

88
import com.amazonaws.services.lambda.runtime.Context;
9-
import io.opentracing.Scope;
9+
import io.opentracing.Span;
10+
import io.opentracing.SpanContext;
11+
import io.opentracing.Tracer;
1012
import io.opentracing.tag.Tags;
13+
import java.util.Collections;
1114
import java.util.HashMap;
1215
import java.util.Map;
13-
import java.util.concurrent.atomic.AtomicBoolean;
1416

1517
public class SpanUtil {
1618

1719
private SpanUtil() {}
1820

19-
public static <Input> void setTags(
20-
Scope scope, Context context, Input input, AtomicBoolean isColdStart) {
21-
scope.span().setTag("aws.requestId", context.getAwsRequestId());
22-
scope.span().setTag("aws.lambda.arn", context.getInvokedFunctionArn());
23-
24-
final String sourceArn = EventSourceParser.parseEventSourceArn(input);
25-
if (sourceArn != null) {
26-
scope.span().setTag("aws.lambda.eventSource.arn", sourceArn);
27-
}
28-
29-
if (isColdStart.getAndSet(false)) {
30-
scope.span().setTag("aws.lambda.coldStart", true);
31-
}
21+
static <Input> Span buildSpan(
22+
Input input, Context context, Tracer tracer, SpanContext spanContext) {
23+
return EnhancedSpanBuilder.basedOn(tracer, "handleRequest")
24+
.asChildOf(spanContext)
25+
.withTag("aws.requestId", context.getAwsRequestId())
26+
.withTag("aws.lambda.arn", context.getInvokedFunctionArn())
27+
.optionallyWithTag(
28+
"aws.lambda.eventSource.arn", EventSourceParser.parseEventSourceArn(input))
29+
.optionallyWithTag(
30+
"aws.lambda.coldStart", TracingRequestHandler.isColdStart.getAndSet(false))
31+
.start();
3232
}
3333

3434
public static Map<String, Object> createErrorAttributes(Throwable throwable) {
@@ -38,6 +38,6 @@ public static Map<String, Object> createErrorAttributes(Throwable throwable) {
3838
errorAttributes.put("message", throwable.getMessage());
3939
errorAttributes.put("stack", throwable.getStackTrace());
4040
errorAttributes.put("error.kind", "Exception");
41-
return errorAttributes;
41+
return Collections.unmodifiableMap(errorAttributes);
4242
}
4343
}

src/main/java/com/newrelic/opentracing/aws/TracingRequestHandler.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import com.amazonaws.services.lambda.runtime.Context;
99
import io.opentracing.Scope;
10+
import io.opentracing.Span;
1011
import io.opentracing.SpanContext;
1112
import io.opentracing.Tracer;
1213
import io.opentracing.propagation.Format;
@@ -42,16 +43,18 @@ default Output handleRequest(Input input, Context context) {
4243
final Tracer tracer = GlobalTracer.get();
4344
final SpanContext spanContext = extractContext(tracer, input);
4445

45-
try (Scope scope = tracer.buildSpan("handleRequest").asChildOf(spanContext).startActive(true)) {
46-
SpanUtil.setTags(scope, context, input, isColdStart);
46+
Span span = SpanUtil.buildSpan(input, context, tracer, spanContext);
47+
try (Scope scope = tracer.activateSpan(span)) {
4748
try {
4849
Output output = doHandleRequest(input, context);
49-
ResponseParser.parseResponse(output, scope.span());
50+
ResponseParser.parseResponse(output, span);
5051
return output;
5152
} catch (Throwable throwable) {
52-
scope.span().log(SpanUtil.createErrorAttributes(throwable));
53+
span.log(SpanUtil.createErrorAttributes(throwable));
5354
throw throwable;
5455
}
56+
} finally {
57+
span.finish();
5558
}
5659
}
5760

src/main/java/com/newrelic/opentracing/aws/TracingRequestStreamHandler.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import com.amazonaws.services.lambda.runtime.Context;
99
import io.opentracing.Scope;
10+
import io.opentracing.Span;
1011
import io.opentracing.SpanContext;
1112
import io.opentracing.Tracer;
1213
import io.opentracing.propagation.Format;
@@ -41,14 +42,16 @@ default void handleRequest(InputStream input, OutputStream output, Context conte
4142
final Tracer tracer = GlobalTracer.get();
4243
final SpanContext spanContext = extractContext(tracer, input);
4344

44-
try (Scope scope = tracer.buildSpan("handleRequest").asChildOf(spanContext).startActive(true)) {
45-
SpanUtil.setTags(scope, context, input, isColdStart);
45+
Span span = SpanUtil.buildSpan(input, context, tracer, spanContext);
46+
try (Scope scope = tracer.activateSpan(span)) {
4647
try {
4748
doHandleRequest(input, output, context);
4849
} catch (Throwable throwable) {
49-
scope.span().log(SpanUtil.createErrorAttributes(throwable));
50+
span.log(SpanUtil.createErrorAttributes(throwable));
5051
throw throwable;
5152
}
53+
} finally {
54+
span.finish();
5255
}
5356
}
5457

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package com.newrelic.opentracing.aws;
2+
3+
import static io.opentracing.propagation.Format.Builtin.TEXT_MAP;
4+
import static org.hamcrest.MatcherAssert.assertThat;
5+
import static org.hamcrest.Matchers.*;
6+
7+
import io.opentracing.References;
8+
import io.opentracing.mock.MockSpan;
9+
import io.opentracing.mock.MockTracer;
10+
import io.opentracing.propagation.TextMapAdapter;
11+
import java.util.HashMap;
12+
import java.util.Map;
13+
import java.util.Random;
14+
import org.junit.After;
15+
import org.junit.Before;
16+
import org.junit.Test;
17+
18+
public class EnhancedSpanBuilderTest {
19+
20+
private Random random = new Random();
21+
22+
private MockTracer tracer;
23+
private MockSpan.MockContext context;
24+
25+
@Before
26+
public void beforeEach() {
27+
Map<String, String> parentIds = new HashMap<>();
28+
parentIds.put("traceid", Math.abs(this.random.nextLong()) + "");
29+
parentIds.put("spanid", Math.abs(this.random.nextLong()) + "");
30+
31+
this.tracer = new MockTracer();
32+
this.context = (MockSpan.MockContext) tracer.extract(TEXT_MAP, new TextMapAdapter(parentIds));
33+
}
34+
35+
@After
36+
public void afterEach() {
37+
this.tracer.close();
38+
this.tracer.reset();
39+
}
40+
41+
@Test
42+
public void basedOn() {
43+
MockSpan builtSpan = (MockSpan) EnhancedSpanBuilder.basedOn(this.tracer, "AnOperation").start();
44+
assertThat(builtSpan.operationName(), is(equalTo("AnOperation")));
45+
assertThat(builtSpan.tags().entrySet(), hasSize(0));
46+
}
47+
48+
@Test
49+
public void asChildOf() {
50+
MockSpan.Reference expectedReference =
51+
new MockSpan.Reference(this.context, References.CHILD_OF);
52+
53+
MockSpan builtSpan =
54+
(MockSpan)
55+
EnhancedSpanBuilder.basedOn(this.tracer, "AnOperation").asChildOf(this.context).start();
56+
57+
assertThat(builtSpan.operationName(), is(equalTo("AnOperation")));
58+
assertThat(builtSpan.references(), hasSize(1));
59+
assertThat(builtSpan.references(), contains(expectedReference));
60+
assertThat(builtSpan.tags().entrySet(), hasSize(0));
61+
}
62+
63+
@Test
64+
public void withTagStringKeyValue() {
65+
MockSpan builtSpan =
66+
(MockSpan)
67+
EnhancedSpanBuilder.basedOn(this.tracer, "AnOperation")
68+
.withTag("ATag", "SomeValue")
69+
.start();
70+
71+
assertThat(builtSpan.tags(), hasEntry("ATag", "SomeValue"));
72+
}
73+
74+
@Test
75+
public void withTagBooleanValues() {
76+
boolean expectedValue = this.random.nextBoolean();
77+
MockSpan builtSpan =
78+
(MockSpan)
79+
EnhancedSpanBuilder.basedOn(this.tracer, "AnOperation")
80+
.withTag("ABooleanKey", expectedValue)
81+
.start();
82+
83+
assertThat(builtSpan.tags().entrySet(), hasSize(1));
84+
assertThat(builtSpan.tags(), hasEntry("ABooleanKey", expectedValue));
85+
}
86+
87+
@Test
88+
public void withTagNumberValues() {
89+
Integer expectedValue = this.random.nextInt();
90+
MockSpan builtSpan =
91+
(MockSpan)
92+
EnhancedSpanBuilder.basedOn(this.tracer, "AnOperation")
93+
.withTag("ANumberKey", expectedValue)
94+
.start();
95+
96+
assertThat(builtSpan.tags().entrySet(), hasSize(1));
97+
assertThat(builtSpan.tags(), hasEntry("ANumberKey", expectedValue));
98+
}
99+
100+
@Test
101+
public void optionallyWithTagDoesNotSetWithNullStrings() {
102+
String expectedValue = null;
103+
MockSpan builtSpan =
104+
(MockSpan)
105+
EnhancedSpanBuilder.basedOn(this.tracer, "AnOperation")
106+
.optionallyWithTag("ATagKey", expectedValue)
107+
.start();
108+
109+
assertThat(builtSpan.tags().entrySet(), hasSize(0));
110+
}
111+
112+
@Test
113+
public void optionallyWithTagStringKeyValue() {
114+
MockSpan builtSpan =
115+
(MockSpan)
116+
EnhancedSpanBuilder.basedOn(this.tracer, "AnOperation")
117+
.optionallyWithTag("ATag", "SomeValue")
118+
.start();
119+
120+
assertThat(builtSpan.tags(), hasEntry("ATag", "SomeValue"));
121+
}
122+
123+
@Test
124+
public void optionallyWithTagDoesNotSetWithNullNumbers() {
125+
Number expectedValue = null;
126+
MockSpan builtSpan =
127+
(MockSpan)
128+
EnhancedSpanBuilder.basedOn(this.tracer, "AnOperation")
129+
.optionallyWithTag("ATagKey", expectedValue)
130+
.start();
131+
132+
assertThat(builtSpan.tags().entrySet(), hasSize(0));
133+
}
134+
135+
@Test
136+
public void optionallyWithTagNumberValues() {
137+
Integer expectedValue = this.random.nextInt();
138+
MockSpan builtSpan =
139+
(MockSpan)
140+
EnhancedSpanBuilder.basedOn(this.tracer, "AnOperation")
141+
.optionallyWithTag("ANumberKey", expectedValue)
142+
.start();
143+
144+
assertThat(builtSpan.tags().entrySet(), hasSize(1));
145+
assertThat(builtSpan.tags(), hasEntry("ANumberKey", expectedValue));
146+
}
147+
}

0 commit comments

Comments
 (0)