Skip to content

Commit cc033a1

Browse files
author
Anuraag Agrawal
authored
Inject OpenTelemetrySdk into lambda library instrumentation instead o… (#2328)
* Inject OpenTelemetrySdk into lambda library instrumentation instead of using global. * Update javadoc * Drift
1 parent bc77ab0 commit cc033a1

26 files changed

+228
-139
lines changed

instrumentation/aws-lambda-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambda/v1_0/AwsLambdaInstrumentationHelper.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,21 @@
55

66
package io.opentelemetry.javaagent.instrumentation.awslambda.v1_0;
77

8+
import io.opentelemetry.api.GlobalOpenTelemetry;
89
import io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaMessageTracer;
910
import io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaTracer;
1011

1112
public final class AwsLambdaInstrumentationHelper {
1213

13-
private static final AwsLambdaTracer FUNCTION_TRACER = new AwsLambdaTracer();
14+
private static final AwsLambdaTracer FUNCTION_TRACER =
15+
new AwsLambdaTracer(GlobalOpenTelemetry.get());
1416

1517
public static AwsLambdaTracer functionTracer() {
1618
return FUNCTION_TRACER;
1719
}
1820

19-
private static final AwsLambdaMessageTracer MESSAGE_TRACER = new AwsLambdaMessageTracer();
21+
private static final AwsLambdaMessageTracer MESSAGE_TRACER =
22+
new AwsLambdaMessageTracer(GlobalOpenTelemetry.get());
2023

2124
public static AwsLambdaMessageTracer messageTracer() {
2225
return MESSAGE_TRACER;

instrumentation/aws-lambda-1.0/library/README.md

+18-6
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,20 @@ Available wrappers:
1515

1616
## Using handlers
1717
To use the instrumentation, replace your function classes that implement `RequestHandler` (or `RequestStreamHandler`) with those
18-
that extend `TracingRequestHandler` (or `TracingRequestStreamHandler`). You will need to change the method name to `doHandleRequest`.
18+
that extend `TracingRequestHandler` (or `TracingRequestStreamHandler`). You will need to change the method name to `doHandleRequest`
19+
and pass an initialized `OpenTelemetrySdk` to the base class.
1920

2021
```java
2122
public class MyRequestHandler extends TracingRequestHandler<String, String> {
23+
24+
private static final OpenTelemetrySdk SDK = OpenTelemetrySdk.builder()
25+
.addSpanProcessor(spanProcessor)
26+
.buildAndRegisterGlobal();
27+
28+
public MyRequestHandler() {
29+
super(SDK);
30+
}
31+
2232
// Note the method is named doHandleRequest instead of handleRequest.
2333
@Override
2434
protected String doHandleRequest(String input, Context context) {
@@ -100,13 +110,15 @@ For API Gateway (HTTP) requests instrumented by using one of following methods:
100110
- wrapping with `TracingRequestStreamWrapper` or `TracingRequestApiGatewayWrapper`
101111
traces can be propagated with supported HTTP headers (see https://github.com/open-telemetry/opentelemetry-java/tree/master/extensions/trace_propagators).
102112

103-
In order to enable requested propagation, configure it in your code as early as possible. For example B3 propagation configuration would look like as follows:
113+
In order to enable requested propagation for a handler, configure it on the SDK you build.
104114

105115
```java
106116
static {
107-
OpenTelemetry.setGlobalPropagators(
108-
DefaultContextPropagators.builder()
109-
.addTextMapPropagator(B3Propagator.getInstance())
110-
.build());
117+
OpenTelemetrySdk.builder()
118+
...
119+
.setPropagators(ContextPropagators.create(B3Propagator.injectingSingleHeader()))
120+
.buildAndRegisterGlobal();
111121
}
112122
```
123+
124+
If using the wrappers, set the `OTEL_PROPAGATORS` environment variable as descibed [here](https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#propagator).

instrumentation/aws-lambda-1.0/library/aws-lambda-1.0-library.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ apply from: "$rootDir/gradle/instrumentation-library.gradle"
1717

1818
dependencies {
1919
compileOnly deps.opentelemetrySdk
20+
compileOnly deps.opentelemetrySdkAutoconfigure
2021

2122
library group: 'com.amazonaws', name: 'aws-lambda-java-core', version: '1.0.0'
2223
// First version to includes support for SQSEvent, currently the most popular message queue used
@@ -39,6 +40,7 @@ dependencies {
3940
'com.fasterxml.jackson.core:jackson-databind:2.10.5.1',
4041
'commons-io:commons-io:2.2')
4142

43+
testImplementation deps.opentelemetrySdkAutoconfigure
4244
testImplementation deps.opentelemetryTraceProps
4345
testImplementation deps.guava
4446

instrumentation/aws-lambda-1.0/library/src/main/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaMessageTracer.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77

88
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
99
import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage;
10+
import io.opentelemetry.api.OpenTelemetry;
1011
import io.opentelemetry.api.trace.Span;
1112
import io.opentelemetry.api.trace.SpanBuilder;
1213
import io.opentelemetry.api.trace.SpanContext;
1314
import io.opentelemetry.api.trace.SpanKind;
14-
import io.opentelemetry.api.trace.Tracer;
1515
import io.opentelemetry.context.Context;
1616
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
1717
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
@@ -20,10 +20,8 @@ public class AwsLambdaMessageTracer extends BaseTracer {
2020

2121
private static final String AWS_TRACE_HEADER_SQS_ATTRIBUTE_KEY = "AWSTraceHeader";
2222

23-
public AwsLambdaMessageTracer() {}
24-
25-
public AwsLambdaMessageTracer(Tracer tracer) {
26-
super(tracer);
23+
public AwsLambdaMessageTracer(OpenTelemetry openTelemetry) {
24+
super(openTelemetry);
2725
}
2826

2927
public Context startSpan(SQSEvent event) {

instrumentation/aws-lambda-1.0/library/src/main/java/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaTracer.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
import com.amazonaws.services.lambda.runtime.Context;
1414
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
1515
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
16+
import io.opentelemetry.api.OpenTelemetry;
1617
import io.opentelemetry.api.trace.Span;
1718
import io.opentelemetry.api.trace.SpanBuilder;
1819
import io.opentelemetry.api.trace.SpanKind;
19-
import io.opentelemetry.api.trace.Tracer;
2020
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
2121
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes.FaasTriggerValues;
2222
import java.lang.invoke.MethodHandle;
@@ -47,10 +47,8 @@ public class AwsLambdaTracer extends BaseTracer {
4747
// cached accountId value
4848
private volatile String accountId;
4949

50-
public AwsLambdaTracer() {}
51-
52-
public AwsLambdaTracer(Tracer tracer) {
53-
super(tracer);
50+
public AwsLambdaTracer(OpenTelemetry openTelemetry) {
51+
super(openTelemetry);
5452
}
5553

5654
private void setAttributes(SpanBuilder span, Context context, Object input) {
@@ -118,7 +116,7 @@ public io.opentelemetry.context.Context startSpan(
118116

119117
public io.opentelemetry.context.Context startSpan(
120118
Context awsContext, SpanKind kind, Object input, Map<String, String> headers) {
121-
io.opentelemetry.context.Context parentContext = ParentContextExtractor.extract(headers);
119+
io.opentelemetry.context.Context parentContext = ParentContextExtractor.extract(headers, this);
122120

123121
SpanBuilder spanBuilder = tracer.spanBuilder(spanName(awsContext, input));
124122
setAttributes(spanBuilder, awsContext, input);

instrumentation/aws-lambda-1.0/library/src/main/java/io/opentelemetry/instrumentation/awslambda/v1_0/ParentContextExtractor.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ public class ParentContextExtractor {
2020

2121
private static final String AWS_TRACE_HEADER_ENV_KEY = "_X_AMZN_TRACE_ID";
2222

23-
static Context extract(Map<String, String> headers) {
23+
static Context extract(Map<String, String> headers, BaseTracer tracer) {
2424
Context parentContext = null;
2525
String parentTraceHeader = System.getenv(AWS_TRACE_HEADER_ENV_KEY);
2626
if (parentTraceHeader != null) {
2727
parentContext = fromXRayHeader(parentTraceHeader);
2828
}
2929
if (!isValidAndSampled(parentContext)) {
3030
// try http
31-
parentContext = fromHttpHeaders(headers);
31+
parentContext = fromHttpHeaders(headers, tracer);
3232
}
3333
return parentContext;
3434
}
@@ -42,8 +42,8 @@ private static boolean isValidAndSampled(Context context) {
4242
return (parentSpanContext.isValid() && parentSpanContext.isSampled());
4343
}
4444

45-
private static Context fromHttpHeaders(Map<String, String> headers) {
46-
return BaseTracer.extractWithGlobalPropagators(lowercaseMap(headers), MapGetter.INSTANCE);
45+
private static Context fromHttpHeaders(Map<String, String> headers, BaseTracer tracer) {
46+
return tracer.extract(lowercaseMap(headers), MapGetter.INSTANCE);
4747
}
4848

4949
// lower-case map getter used for extraction

instrumentation/aws-lambda-1.0/library/src/main/java/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestApiGatewayWrapper.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,21 @@
77

88
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
99
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
10+
import io.opentelemetry.sdk.OpenTelemetrySdk;
1011

1112
/**
1213
* Wrapper for {@link TracingRequestHandler}. Allows for wrapping a lambda proxied through API
1314
* Gateway, enabling single span tracing and HTTP context propagation.
1415
*/
1516
public class TracingRequestApiGatewayWrapper
16-
extends TracingRequestWrapperBase<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {}
17+
extends TracingRequestWrapperBase<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
18+
19+
public TracingRequestApiGatewayWrapper() {
20+
super();
21+
}
22+
23+
// Visible for testing
24+
TracingRequestApiGatewayWrapper(OpenTelemetrySdk openTelemetrySdk) {
25+
super(openTelemetrySdk);
26+
}
27+
}

instrumentation/aws-lambda-1.0/library/src/main/java/io/opentelemetry/instrumentation/awslambda/v1_0/TracingRequestHandler.java

+28-22
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
import com.amazonaws.services.lambda.runtime.RequestHandler;
1010
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
1111
import io.opentelemetry.api.trace.SpanKind;
12-
import io.opentelemetry.api.trace.Tracer;
1312
import io.opentelemetry.context.Scope;
13+
import io.opentelemetry.sdk.OpenTelemetrySdk;
14+
import java.time.Duration;
1415
import java.util.Collections;
1516
import java.util.Map;
17+
import java.util.concurrent.TimeUnit;
1618

1719
/**
1820
* A base class similar to {@link RequestHandler} but will automatically trace invocations of {@link
@@ -21,38 +23,39 @@
2123
*/
2224
public abstract class TracingRequestHandler<I, O> implements RequestHandler<I, O> {
2325

24-
private static final long DEFAULT_FLUSH_TIMEOUT_SECONDS = 1;
26+
protected static final Duration DEFAULT_FLUSH_TIMEOUT = Duration.ofSeconds(1);
2527

2628
private final AwsLambdaTracer tracer;
27-
private final long flushTimeout;
29+
private final OpenTelemetrySdk openTelemetrySdk;
30+
private final long flushTimeoutNanos;
2831

29-
/** Creates a new {@link TracingRequestHandler} which traces using the default {@link Tracer}. */
30-
protected TracingRequestHandler(long flushTimeout) {
31-
this.tracer = new AwsLambdaTracer();
32-
this.flushTimeout = flushTimeout;
33-
}
34-
35-
/** Creates a new {@link TracingRequestHandler} which traces using the default {@link Tracer}. */
36-
protected TracingRequestHandler() {
37-
this.tracer = new AwsLambdaTracer();
38-
this.flushTimeout = DEFAULT_FLUSH_TIMEOUT_SECONDS;
32+
/**
33+
* Creates a new {@link TracingRequestHandler} which traces using the provided {@link
34+
* OpenTelemetrySdk} and has a timeout of 1s when flushing at the end of an invocation.
35+
*/
36+
protected TracingRequestHandler(OpenTelemetrySdk openTelemetrySdk) {
37+
this(openTelemetrySdk, DEFAULT_FLUSH_TIMEOUT);
3938
}
4039

4140
/**
42-
* Creates a new {@link TracingRequestHandler} which traces using the specified {@link Tracer}.
41+
* Creates a new {@link TracingRequestHandler} which traces using the provided {@link
42+
* OpenTelemetrySdk} and has a timeout of {@code flushTimeout} when flushing at the end of an
43+
* invocation.
4344
*/
44-
protected TracingRequestHandler(Tracer tracer) {
45-
this.tracer = new AwsLambdaTracer(tracer);
46-
this.flushTimeout = DEFAULT_FLUSH_TIMEOUT_SECONDS;
45+
protected TracingRequestHandler(OpenTelemetrySdk openTelemetrySdk, Duration flushTimeout) {
46+
this(openTelemetrySdk, flushTimeout, new AwsLambdaTracer(openTelemetrySdk));
4747
}
4848

4949
/**
50-
* Creates a new {@link TracingRequestHandler} which traces using the specified {@link
51-
* AwsLambdaTracer}.
50+
* Creates a new {@link TracingRequestHandler} which flushes the provided {@link
51+
* OpenTelemetrySdk}, has a timeout of {@code flushTimeout} when flushing at the end of an
52+
* invocation, and traces using the provided {@link AwsLambdaTracer}.
5253
*/
53-
protected TracingRequestHandler(AwsLambdaTracer tracer) {
54+
protected TracingRequestHandler(
55+
OpenTelemetrySdk openTelemetrySdk, Duration flushTimeout, AwsLambdaTracer tracer) {
56+
this.openTelemetrySdk = openTelemetrySdk;
57+
this.flushTimeoutNanos = flushTimeout.toNanos();
5458
this.tracer = tracer;
55-
this.flushTimeout = DEFAULT_FLUSH_TIMEOUT_SECONDS;
5659
}
5760

5861
private Map<String, String> getHeaders(I input) {
@@ -81,7 +84,10 @@ public final O handleRequest(I input, Context context) {
8184
} else {
8285
tracer.end(otelContext);
8386
}
84-
LambdaUtils.forceFlush();
87+
openTelemetrySdk
88+
.getSdkTracerProvider()
89+
.forceFlush()
90+
.join(flushTimeoutNanos, TimeUnit.NANOSECONDS);
8591
}
8692
}
8793

0 commit comments

Comments
 (0)