Skip to content

Commit dc009b8

Browse files
authored
Merge pull request #29 from agarbutt/upgrade-open-trace
Support for OpenTracing 0.33.0
2 parents 236ea52 + 876497c commit dc009b8

File tree

7 files changed

+267
-29
lines changed

7 files changed

+267
-29
lines changed

build.gradle

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,13 @@ dependencies {
4242
implementation 'com.amazonaws:aws-java-sdk-s3:1.11.163'
4343
implementation 'com.amazonaws:aws-java-sdk-kinesis:1.11.163'
4444
implementation 'com.amazonaws:aws-java-sdk-dynamodb:1.11.163'
45-
implementation('io.opentracing:opentracing-api:0.31.0')
46-
implementation('io.opentracing:opentracing-util:0.31.0')
47-
implementation('io.opentracing:opentracing-noop:0.31.0')
45+
implementation('io.opentracing:opentracing-api:0.33.0')
46+
implementation('io.opentracing:opentracing-util:0.33.0')
47+
implementation('io.opentracing:opentracing-noop:0.33.0')
4848

4949
testImplementation 'junit:junit:4.12'
50-
testImplementation 'io.opentracing:opentracing-mock:0.31.0'
50+
testImplementation 'org.hamcrest:hamcrest-library:1.3'
51+
testImplementation 'io.opentracing:opentracing-mock:0.33.0'
5152
}
5253

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

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: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
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;
1316
import java.util.concurrent.atomic.AtomicBoolean;
@@ -16,19 +19,20 @@ public class SpanUtil {
1619

1720
private SpanUtil() {}
1821

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-
}
22+
static <Input> Span buildSpan(
23+
Input input,
24+
Context context,
25+
Tracer tracer,
26+
SpanContext spanContext,
27+
AtomicBoolean isColdStart) {
28+
return EnhancedSpanBuilder.basedOn(tracer, "handleRequest")
29+
.asChildOf(spanContext)
30+
.withTag("aws.requestId", context.getAwsRequestId())
31+
.withTag("aws.lambda.arn", context.getInvokedFunctionArn())
32+
.optionallyWithTag(
33+
"aws.lambda.eventSource.arn", EventSourceParser.parseEventSourceArn(input))
34+
.optionallyWithTag("aws.lambda.coldStart", isColdStart.getAndSet(false))
35+
.start();
3236
}
3337

3438
public static Map<String, Object> createErrorAttributes(Throwable throwable) {
@@ -38,6 +42,6 @@ public static Map<String, Object> createErrorAttributes(Throwable throwable) {
3842
errorAttributes.put("message", throwable.getMessage());
3943
errorAttributes.put("stack", throwable.getStackTrace());
4044
errorAttributes.put("error.kind", "Exception");
41-
return errorAttributes;
45+
return Collections.unmodifiableMap(errorAttributes);
4246
}
4347
}

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

0 commit comments

Comments
 (0)