Skip to content

Commit d96644e

Browse files
authored
Enable OTel API instrumentation for generating custom spans (#1058)
### Problem When using the Application Signals lambda layer for auto-instrumenting a lambda function, we found that if we want to generate custom spans using the OTel APIs, then these spans are generated with no-op context and are not available in Application Signals. ### Steps to reproduce - Create a Java lambda function (can use [this pre-build app](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-java)) with the following code ```java package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; import java.util.Map; import software.amazon.awssdk.services.lambda.LambdaClient; import software.amazon.awssdk.services.lambda.model.GetAccountSettingsResponse; import software.amazon.awssdk.services.lambda.model.LambdaException; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.SpanKind; // Handler value: example.Handler public class Handler implements RequestHandler<Map<String,String>, String> { private static final LambdaClient lambdaClient = LambdaClient.builder().build(); @OverRide public String handleRequest(Map<String,String> event, Context context) { LambdaLogger logger = context.getLogger(); logger.log("Handler invoked"); GetAccountSettingsResponse response = null; try { response = lambdaClient.getAccountSettings(); } catch(LambdaException e) { logger.log(e.getMessage()); } logger.log("=====1."); Span parentSpan = Span.current(); logger.log(parentSpan.toString()); if (GlobalOpenTelemetry.get() == null) { logger.log("----- GlobalOTelTracer is null"); } else { logger.log("----- GlobalOTelTracer is initialized"); } Tracer tracer = GlobalOpenTelemetry.getTracer("my-app"); Span span = tracer.spanBuilder("rollTheDice") .setSpanKind(SpanKind.SERVER) .setParent(io.opentelemetry.context.Context.current().with(parentSpan)) .startSpan(); span.end(); logger.log(span.toString()); logger.log("=====2."); return response != null ? "Total code size for your account is " + response.accountLimit().totalCodeSize() + " bytes" : "Error"; } } ``` - Enable Application Signals from the Lambda function console. - Invoke the function and observe the CW logs. You should see the following lines where the two spans are both no-op ``` Handler invoked -- =====1. PropagatedSpan{ImmutableSpanContext{traceId=00000000000000000000000000000000, spanId=0000000000000000, traceFlags=00, traceState=ArrayBasedTraceState{entries=[]}, remote=false, valid=false}} ----- GlobalOTelTracer is initialized PropagatedSpan{ImmutableSpanContext{traceId=00000000000000000000000000000000, spanId=0000000000000000, traceFlags=00, traceState=ArrayBasedTraceState{entries=[]}, remote=false, valid=false}} =====2. ``` ### Solution - OpenTelemetry treats the [`opentelemetry-api` just like any other library instrumentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/opentelemetry-api). When instrumented, the methods (like `startSpan`) from the OpenTelemetry API will produce spans that have proper context. - In the Application Lambda layer, [only a handful of library instrumentations are enabled by default](https://github.com/aws-observability/aws-otel-java-instrumentation/blob/43bc6bcc795749e043aee5c64f794a525139d975/lambda-layer/otel-instrument#L38-L44). This does not include the `opentelemetry-api` instrumentation. - Adding the `OTEL_INSTRUMENTATION_OPENTELEMETRY_API_ENABLED=true` environment variable will enable this instrumentation. ### Testing - Once the `OTEL_INSTRUMENTATION_OPENTELEMETRY_API_ENABLED=true` was set, the same code produced correct spans ``` Handler invoked -- =====1. ApplicationSpan{agentSpan=SdkSpan{traceId=67dc8edd575d3de05e89c56b19240ffd, spanId=d9039dec8378a88c, parentSpanContext=ImmutableSpanContext{traceId=67dc8edd575d3de05e89c56b19240ffd, spanId=796364ca3c8551b1, traceFlags=01, traceState=ArrayBasedTraceState{entries=[]}, remote=true, valid=true}, name=blank-java-function-Hs0Awjtfeqgx, kind=SERVER, attributes=AttributesMap{data={thread.name=main, cloud.resource_id=arn:aws:lambda:us-west-2:702258172533:function:blank-java-function-Hs0Awjtfeqgx, thread.id=1, cloud.account.id=702258172533, faas.invocation_id=4ca9914c-ba2b-4236-ba0d-8bc176593816}, capacity=128, totalAddedValues=5}, status=ImmutableStatusData{statusCode=UNSET, description=}, totalRecordedEvents=0, totalRecordedLinks=0, startEpochNanos=1742507745533600918, endEpochNanos=0}} ----- GlobalOTelTracer is initialized ApplicationSpan{agentSpan=SdkSpan{traceId=67dc8edd575d3de05e89c56b19240ffd, spanId=62d682028539df0b, parentSpanContext=ImmutableSpanContext{traceId=67dc8edd575d3de05e89c56b19240ffd, spanId=d9039dec8378a88c, traceFlags=01, traceState=ArrayBasedTraceState{entries=[]}, remote=false, valid=true}, name=rollTheDice, kind=SERVER, attributes=AttributesMap{data={thread.name=main, thread.id=1, aws.local.operation=blank-java-function-Hs0Awjtfeqgx/FunctionHandler}, capacity=128, totalAddedValues=3}, status=ImmutableStatusData{statusCode=UNSET, description=}, totalRecordedEvents=0, totalRecordedLinks=0, startEpochNanos=1742507746224698439, endEpochNanos=1742507746224823765}} =====2. ``` By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 43bc6bc commit d96644e

File tree

1 file changed

+1
-0
lines changed

1 file changed

+1
-0
lines changed

lambda-layer/otel-instrument

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ fi
3737

3838
# Enable default instrumentations
3939
export OTEL_INSTRUMENTATION_COMMON_DEFAULT_ENABLED=${OTEL_INSTRUMENTATION_COMMON_DEFAULT_ENABLED:-"false"}
40+
export OTEL_INSTRUMENTATION_OPENTELEMETRY_API_ENABLED=${OTEL_INSTRUMENTATION_OPENTELEMETRY_API_ENABLED:-"true"}
4041
export OTEL_INSTRUMENTATION_AWS_LAMBDA_ENABLED=${OTEL_INSTRUMENTATION_AWS_LAMBDA_ENABLED:-"true"}
4142
export OTEL_INSTRUMENTATION_AWS_SDK_ENABLED=${OTEL_INSTRUMENTATION_AWS_SDK_ENABLED:-"true"}
4243
export OTEL_INSTRUMENTATION_APACHE_HTTPCLIENT_ENABLED=${OTEL_INSTRUMENTATION_APACHE_HTTPCLIENT_ENABLED:-"true"}

0 commit comments

Comments
 (0)