@@ -736,7 +767,9 @@
maven-surefire-plugin
- --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED
+ --add-opens java.base/java.util=ALL-UNNAMED --add-opens
+ java.base/java.lang=ALL-UNNAMED
+
diff --git a/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/SystemWrapper.java b/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/SystemWrapper.java
index 6dc4e9d9f..cc8ea39e9 100644
--- a/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/SystemWrapper.java
+++ b/powertools-common/src/main/java/software/amazon/lambda/powertools/common/internal/SystemWrapper.java
@@ -22,6 +22,10 @@ public static String getenv(String name) {
return System.getenv(name);
}
+ public static boolean containsKey(String key) {
+ return System.getenv().containsKey(key);
+ }
+
public static String getProperty(String name) {
return System.getProperty(name);
}
diff --git a/powertools-tracing-opentelemetry/pom.xml b/powertools-tracing-opentelemetry/pom.xml
new file mode 100644
index 000000000..976d8a723
--- /dev/null
+++ b/powertools-tracing-opentelemetry/pom.xml
@@ -0,0 +1,156 @@
+
+
+
+ 4.0.0
+
+ powertools-tracing-opentelemetry
+ jar
+
+
+ software.amazon.lambda
+ powertools-parent
+ 2.10.0
+
+
+ Powertools for AWS Lambda (Java) - Tracing OpenTelemetry
+
+ A suite of utilities for AWS Lambda Functions that makes tracing with OpenTelemetry, structured logging and
+ creating custom metrics asynchronously easier.
+
+
+
+
+ io.opentelemetry
+ opentelemetry-api
+
+
+ io.opentelemetry
+ opentelemetry-sdk
+
+
+ io.opentelemetry
+ opentelemetry-exporter-otlp
+
+
+ io.opentelemetry.contrib
+ opentelemetry-aws-xray-propagator
+
+
+ org.aspectj
+ aspectjrt
+ provided
+
+
+ software.amazon.lambda
+ powertools-common
+
+
+ software.amazon.awssdk
+ aws-core
+
+
+ software.amazon.awssdk
+ sdk-core
+
+
+ com.amazonaws
+ aws-lambda-java-core
+
+
+ com.amazonaws
+ aws-lambda-java-events
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
+ io.opentelemetry
+ opentelemetry-sdk-testing
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ software.amazon.lambda
+ powertools-common
+ ${project.version}
+ test-jar
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
+
+ org.junit-pioneer
+ junit-pioneer
+ test
+
+
+ org.apache.commons
+ commons-lang3
+ test
+
+
+ org.aspectj
+ aspectjweaver
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ on-demand
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/CaptureMode.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/CaptureMode.java
new file mode 100644
index 000000000..40ad84307
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/CaptureMode.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry;
+
+/**
+ * Defines how method responses and errors are captured by tracing.
+ */
+public enum CaptureMode {
+
+ /**
+ * Capture response and errors according to environment variables.
+ */
+ ENVIRONMENT_VAR,
+
+ /**
+ * Capture the method response.
+ */
+ RESPONSE,
+
+ /**
+ * Capture errors thrown by the method.
+ */
+ ERROR,
+
+ /**
+ * Capture both the method response and errors.
+ */
+ RESPONSE_AND_ERROR,
+
+ /**
+ * Disable response and error capture.
+ */
+ DISABLED
+}
\ No newline at end of file
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/Tracing.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/Tracing.java
new file mode 100644
index 000000000..820026cc2
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/Tracing.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to enable OpenTelemetry tracing for the annotated method.
+ * Automatically creates and manages an OpenTelemetry span for the method invocation.
+ *
+ * This annotation allows configuration of the namespace, span name, and capture mode
+ * for tracing purposes. If no explicit configuration is provided, default values are used.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Tracing {
+ /**
+ * The namespace associated with the span.
+ *
+ *
If empty, the default Powertools service name is used.
+ *
+ * @return the namespace
+ */
+ String namespace() default "";
+
+ /**
+ * The name of the span.
+ *
+ *
If empty, the annotated method name is used.
+ *
+ * @return the span name
+ */
+ String spanName() default "";
+
+ /**
+ * Controls whether the method response and/or errors are captured
+ * as span data.
+ *
+ * @return the capture mode
+ */
+ CaptureMode captureMode() default CaptureMode.ENVIRONMENT_VAR;
+}
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/TracingOpenTelemetry.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/TracingOpenTelemetry.java
new file mode 100644
index 000000000..9585ca03f
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/TracingOpenTelemetry.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry;
+
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanBuilder;
+import io.opentelemetry.api.trace.SpanContext;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.propagation.TextMapGetter;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+import io.opentelemetry.context.propagation.TextMapSetter;
+import io.opentelemetry.sdk.common.CompletableResultCode;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import software.amazon.lambda.powertools.tracing.opentelemetry.context.LambdaEventContextExtractorResolver;
+import software.amazon.lambda.powertools.tracing.opentelemetry.internal.SpanOperation;
+import software.amazon.lambda.powertools.tracing.opentelemetry.internal.SpanScope;
+import software.amazon.lambda.powertools.tracing.opentelemetry.provider.OpenTelemetryProvider;
+
+/**
+ * A utility class responsible for managing OpenTelemetry tracing functionality,
+ * including creating and managing spans, handling context propagation, and facilitating
+ * relevant operations for distributed tracing.
+ *
+ * This class provides methods to manage the life cycle of spans, propagate and extract
+ * context, flush telemetry data, and execute operations within spans. It also supports
+ * configuration via a builder pattern.
+ *
+ * The class is designed to be thread-safe and offers a default singleton instance
+ * for convenience.
+ */
+public final class TracingOpenTelemetry {
+
+ private static final TracingOpenTelemetry DEFAULT_INSTANCE = new TracingOpenTelemetry();
+ private final Tracer tracer;
+ private final TextMapPropagator propagator;
+ private final LambdaEventContextExtractorResolver eventContextExtractorResolver;
+
+ private TracingOpenTelemetry(Builder builder) {
+ this.tracer = Objects.requireNonNull(builder.tracer, "tracer must not be null");
+ this.propagator = Objects.requireNonNull(builder.propagator, "propagator must not be null");
+ this.eventContextExtractorResolver = Objects.requireNonNull(
+ builder.eventContextExtractorResolver,
+ "eventContextExtractorResolver must not be null"
+ );
+ }
+
+ public TracingOpenTelemetry() {
+ this(OpenTelemetryProvider.tracer());
+ }
+
+
+ public TracingOpenTelemetry(Tracer tracer) {
+ this(tracer, createDefaultPropagator(), createDefaultEventContextExtractorResolver());
+ }
+
+
+ public TracingOpenTelemetry(
+ Tracer tracer,
+ TextMapPropagator propagator,
+ LambdaEventContextExtractorResolver eventContextExtractorResolver
+ ) {
+
+ this.tracer = Objects.requireNonNull(tracer, "tracer must not be null");
+ this.propagator = Objects.requireNonNull(propagator, "propagator must not be null");
+ this.eventContextExtractorResolver = Objects.requireNonNull(
+ eventContextExtractorResolver,
+ "eventContextExtractorResolver must not be null"
+ );
+ }
+
+ /**
+ * Provides access to the current Tracer instance.
+ *
+ * @return the Tracer instance associated with the current context
+ */
+ public Tracer tracer() {
+ return tracer;
+ }
+
+ /**
+ * Provides the current TextMapPropagator instance.
+ *
+ * @return the TextMapPropagator instance used for propagating context information.
+ */
+ public TextMapPropagator propagator() {
+ return propagator;
+ }
+
+ /**
+ * Retrieves the instance of LambdaEventContextExtractorResolver.
+ *
+ * @return the resolver used to extract context from Lambda events.
+ */
+ public LambdaEventContextExtractorResolver eventContextExtractorResolver() {
+ return eventContextExtractorResolver;
+ }
+
+ /**
+ * Retrieves the current active span within the context.
+ *
+ * @return the currently active span, or null if there is no active span
+ */
+ public Span currentSpan() {
+ return Span.current();
+ }
+
+ /**
+ * Forces all pending spans and related telemetry data to be processed and exported.
+ * This method sends the pending data using the default timeout period.
+ *
+ * @return a {@code CompletableResultCode} indicating the success or failure of the flush operation
+ */
+ public CompletableResultCode flush() {
+ return flush(5, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Forces all pending spans and related telemetry data to be processed and exported
+ * within a specified timeout period.
+ *
+ * @param timeout the maximum duration to wait for the flush operation to complete
+ * @param unit the time unit of the {@code timeout} parameter
+ * @return a {@code CompletableResultCode} indicating the success or failure of the flush operation
+ */
+ public CompletableResultCode flush(long timeout, TimeUnit unit) {
+ return OpenTelemetryProvider.forceFlush().join(timeout, unit);
+ }
+
+ /**
+ * Starts a new OpenTelemetry span with the given name and a default {@link SpanKind#INTERNAL} kind.
+ *
+ * @param name the name of the span to be created
+ * @return a {@link SpanScope} instance that manages the lifecycle of the span and its associated context
+ */
+ public SpanScope addSpan(String name) {
+ return addSpan(name, SpanKind.INTERNAL);
+ }
+
+ /**
+ * Starts a new OpenTelemetry span with the given name, kind, and default attributes.
+ *
+ * @param name the name of the span to be created
+ * @param kind the kind of the span, e.g., {@link SpanKind#INTERNAL}, {@link SpanKind#CLIENT}, etc.
+ * @return a {@link SpanScope} instance that manages the lifecycle of the span and its associated context
+ */
+ public SpanScope addSpan(String name, SpanKind kind) {
+
+ return addSpan(name, kind, Attributes.empty());
+ }
+
+ /**
+ * Starts a new OpenTelemetry span with the given name, kind, and attributes,
+ * using the current thread context as the parent context.
+ *
+ * @param name the name of the span to be created
+ * @param kind the kind of the span, such as {@code SpanKind.INTERNAL}, {@code SpanKind.CLIENT}, etc.
+ * @param attributes the attributes to associate with the span
+ * @return a {@code SpanScope} instance that manages the lifecycle of the span and its associated context
+ */
+ public SpanScope addSpan(String name, SpanKind kind, Attributes attributes) {
+
+ return addSpan(name, kind, attributes, Context.current());
+ }
+
+ /**
+ * Starts a new OpenTelemetry span with the given name, kind, attributes, and parent context.
+ * The span is returned encapsulated in a {@code SpanScope}, which manages the lifecycle
+ * of the span and its associated context.
+ *
+ * @param name the name of the span to be created
+ * @param kind the type of the span, such as {@code SpanKind.INTERNAL}, {@code SpanKind.CLIENT}, etc.
+ * @param attributes the attributes to associate with the span
+ * @param parentContext the parent context to use for the span
+ * @return a {@code SpanScope} instance that manages the lifecycle of the span and its related context
+ */
+ public SpanScope addSpan(String name, SpanKind kind, Attributes attributes, Context parentContext) {
+
+ return addSpan(name, kind, attributes, parentContext, Collections.emptyList());
+ }
+
+ /**
+ * Starts a new OpenTelemetry span with the given configuration, including name, kind, attributes,
+ * parent context, and links to other spans represented by their {@code SpanContext}s.
+ * The resulting span is encapsulated within a {@code SpanScope} for proper lifecycle management.
+ *
+ * @param name the name of the span to be created; must not be null
+ * @param kind the type of the span, such as {@code SpanKind.INTERNAL}, {@code SpanKind.CLIENT}, etc.;
+ * must not be null
+ * @param attributes the attributes to associate with the span; must not be null
+ * @param parentContext the parent context to use for the span; must not be null
+ * @param spanContexts the list of {@code SpanContext} instances to link to the created span; must not be null
+ * @return a {@code SpanScope} instance that manages the lifecycle of the span and its associated context
+ * @throws NullPointerException if any of the parameters are null
+ */
+ public SpanScope addSpan(
+ String name,
+ SpanKind kind,
+ Attributes attributes,
+ Context parentContext,
+ List spanContexts
+ ) {
+
+ Objects.requireNonNull(name, "name must not be null");
+ Objects.requireNonNull(kind, "kind must not be null");
+ Objects.requireNonNull(attributes, "attributes must not be null");
+ Objects.requireNonNull(parentContext, "parentContext must not be null");
+ Objects.requireNonNull(spanContexts, "spanContexts must not be null");
+
+ SpanBuilder spanBuilder = tracer
+ .spanBuilder(name)
+ .setSpanKind(kind)
+ .setParent(parentContext)
+ .setAllAttributes(attributes);
+
+ spanContexts.forEach(spanBuilder::addLink);
+
+ return new SpanScope(spanBuilder.startSpan());
+ }
+
+ /**
+ * Executes a given operation within the context of an OpenTelemetry span with the specified name.
+ * The span is created with the default {@link SpanKind#INTERNAL} and no additional attributes.
+ * Any exceptions thrown during the operation will be recorded in the span.
+ *
+ * @param the type of result returned by the operation
+ * @param name the name of the span to be created; must not be null
+ * @param operation the operation to execute within the span context; must not be null
+ * @return the result of the operation
+ * @throws Exception if an error occurs during the execution of the operation
+ */
+ public T withSpan(String name, SpanOperation operation) throws Exception {
+
+ return withSpan(name, SpanKind.INTERNAL, Attributes.empty(), operation);
+ }
+
+ /**
+ * Executes a given operation within the context of an OpenTelemetry span
+ * with the specified name, kind, and attributes. The span is created and
+ * managed within the method. Any exceptions thrown during the operation
+ * are recorded in the span before being propagated.
+ *
+ * @param the type of result returned by the operation
+ * @param name the name of the span to be created; must not be null
+ * @param kind the kind of the span, such as {@code SpanKind.INTERNAL}
+ * or {@code SpanKind.CLIENT}; must not be null
+ * @param attributes the attributes to associate with the span; must not be null
+ * @param operation the operation to execute within the span context; must not be null
+ * @return the result of the operation
+ * @throws Exception if an error occurs during the execution of the operation
+ */
+ public T withSpan(
+ String name,
+ SpanKind kind,
+ Attributes attributes,
+ SpanOperation operation
+ ) throws Exception {
+ Objects.requireNonNull(operation, "operation must not be null");
+
+ try (SpanScope scope = addSpan(name, kind, attributes)) {
+ try {
+ return operation.execute(scope.span());
+ } catch (Exception exception) {
+ scope.recordException(exception);
+ throw exception;
+ }
+ }
+ }
+
+ /**
+ * Extracts a {@code Context} from the given carrier using the specified {@link TextMapGetter}.
+ *
+ * @param the type of the carrier from which the context is extracted
+ * @param carrier the carrier object that holds context propagation data; must not be null
+ * @param getter the {@link TextMapGetter} used to read propagation fields from the carrier; must not be null
+ * @return the extracted {@code Context}, or the current context if no context could be extracted
+ * @throws NullPointerException if the carrier or getter is null
+ */
+ public Context extractContext(T carrier, TextMapGetter getter) {
+
+ return extractContext(Context.current(), carrier, getter);
+ }
+
+ /**
+ * Extracts a {@link Context} from the given carrier using the specified {@link TextMapGetter}.
+ *
+ * @param context the initial {@link Context} used as the baseline for extraction; must not be null
+ * @param carrier the carrier of the propagation fields; must not be null
+ * @param getter the {@link TextMapGetter} used to read propagation fields from the carrier; must not be null
+ * @return the extracted {@link Context} containing the propagated values
+ */
+ public Context extractContext(Context context, T carrier, TextMapGetter getter) {
+
+ Objects.requireNonNull(context, "context must not be null");
+ Objects.requireNonNull(carrier, "carrier must not be null");
+ Objects.requireNonNull(getter, "getter must not be null");
+
+ return propagator.extract(context, carrier, getter);
+ }
+
+ /**
+ * Injects the current context into the specified carrier using the provided TextMapSetter.
+ *
+ * @param The type of the carrier into which the context will be injected.
+ * @param carrier The carrier object that will hold the injected context.
+ * @param setter The TextMapSetter implementation used to set the context into the carrier.
+ */
+ public void injectContext(T carrier, TextMapSetter setter) {
+
+ injectContext(Context.current(), carrier, setter);
+ }
+
+ /**
+ * Injects the provided {@code Context} into the specified carrier using the given {@code TextMapSetter}.
+ *
+ * @param context the context to inject; must not be null
+ * @param carrier the carrier into which the context will be injected; must not be null
+ * @param setter the {@code TextMapSetter} used to define how the context is set on the carrier; must not be null
+ * @param the type of the carrier
+ */
+ public void injectContext(Context context, T carrier, TextMapSetter setter) {
+
+ Objects.requireNonNull(context, "context must not be null");
+ Objects.requireNonNull(carrier, "carrier must not be null");
+ Objects.requireNonNull(setter, "setter must not be null");
+
+ propagator.inject(context, carrier, setter);
+ }
+
+ private static TextMapPropagator createDefaultPropagator() {
+ return OpenTelemetryProvider.propagator();
+ }
+
+ private static LambdaEventContextExtractorResolver createDefaultEventContextExtractorResolver() {
+ return LambdaEventContextExtractorResolver.create();
+ }
+
+ /**
+ * Creates and returns the default instance of the TracingOpenTelemetry.
+ *
+ * @return The default instance of TracingOpenTelemetry.
+ */
+ public static TracingOpenTelemetry create() {
+ return DEFAULT_INSTANCE;
+ }
+
+ /**
+ * Creates and returns a new instance of the Builder.
+ *
+ * @return a new Builder instance
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Builder class for creating instances of TracingOpenTelemetry.
+ * This class provides a fluent API for configuring and constructing
+ * a TracingOpenTelemetry object.
+ *
+ * The Builder allows customization of the following components:
+ * - Tracer: A tracer instance used for tracing operations.
+ * - TextMapPropagator: A propagator responsible for context propagation.
+ * - LambdaEventContextExtractorResolver: A resolver for extracting context from Lambda events.
+ */
+ public static final class Builder {
+
+ private Tracer tracer;
+ private TextMapPropagator propagator = createDefaultPropagator();
+ private LambdaEventContextExtractorResolver eventContextExtractorResolver =
+ createDefaultEventContextExtractorResolver();
+
+ /**
+ * Sets the tracer instance to be used for tracing operations.
+ * This method allows specifying a custom tracer, which will
+ * be used to create and manage spans in tracing contexts.
+ *
+ * @param tracer the tracer instance to be used for tracing
+ * @return the updated Builder instance for method chaining
+ */
+ public Builder tracer(Tracer tracer) {
+ this.tracer = tracer;
+ return this;
+ }
+
+ /**
+ * Sets the {@link TextMapPropagator} to be used for context propagation.
+ * This allows specifying a custom propagator to handle the injection and extraction
+ * of context data across process boundaries.
+ *
+ * @param propagator the {@link TextMapPropagator} instance to be used for context propagation
+ * @return the updated Builder instance for method chaining
+ */
+ public Builder propagator(TextMapPropagator propagator) {
+ this.propagator = propagator;
+ return this;
+ }
+
+ /**
+ * Sets the {@link LambdaEventContextExtractorResolver} to be used for extracting
+ * context from AWS Lambda events. This allows specifying a custom resolver
+ * to handle the extraction of trace context from various types of AWS Lambda
+ * event sources.
+ *
+ * @param eventContextExtractorResolver the {@link LambdaEventContextExtractorResolver} instance
+ * to be used for extracting trace context from Lambda events
+ * @return the updated Builder instance for method chaining
+ */
+ public Builder eventContextExtractorResolver(
+ LambdaEventContextExtractorResolver eventContextExtractorResolver) {
+ this.eventContextExtractorResolver = eventContextExtractorResolver;
+ return this;
+ }
+
+ /**
+ * Constructs a new instance of TracingOpenTelemetry using the current state of the Builder.
+ * This method finalizes the configuration and returns the configured TracingOpenTelemetry instance.
+ *
+ * @return a fully configured TracingOpenTelemetry instance
+ */
+ public TracingOpenTelemetry build() {
+ return new TracingOpenTelemetry(this);
+ }
+ }
+}
\ No newline at end of file
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/ApiGatewayTraceContextExtractor.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/ApiGatewayTraceContextExtractor.java
new file mode 100644
index 000000000..a6aa98917
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/ApiGatewayTraceContextExtractor.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.context;
+
+import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import software.amazon.lambda.powertools.tracing.opentelemetry.provider.OpenTelemetryProvider;
+
+/**
+ * An implementation of {@link LambdaEventContextExtractor} that extracts and enriches tracing context
+ * information from API Gateway events. This class supports distributed tracing by leveraging OpenTelemetry
+ * to propagate and enrich trace data from API Gateway-provided HTTP headers and metadata.
+ *
+ * This extractor handles events of type {@link APIGatewayProxyRequestEvent}.
+ */
+public final class ApiGatewayTraceContextExtractor implements LambdaEventContextExtractor {
+
+
+ @Override
+ public boolean supports(Object event) {
+ return event instanceof APIGatewayProxyRequestEvent;
+ }
+
+ @Override
+ public ExtractedTraceContext extract(Object event, Context parentContext, TextMapPropagator propagator) {
+
+ APIGatewayProxyRequestEvent apiGatewayEvent = (APIGatewayProxyRequestEvent) event;
+
+ Map headers = apiGatewayEvent.getHeaders();
+
+ if (headers == null || headers.isEmpty()) {
+ return new ExtractedTraceContext(parentContext, List.of(), SpanKind.SERVER);
+ }
+
+ Context context = propagator.extract(
+ parentContext,
+ headers,
+ OpenTelemetryProvider.textMapGetter()
+ );
+
+ return new ExtractedTraceContext(context, List.of(), SpanKind.SERVER);
+ }
+
+ @Override
+ public void enrichSpan(Object event, Span span) {
+
+ APIGatewayProxyRequestEvent apiGatewayEvent = (APIGatewayProxyRequestEvent) event;
+
+ if (apiGatewayEvent.getHttpMethod() != null) {
+ span.setAttribute("http.request.method", apiGatewayEvent.getHttpMethod());
+ }
+
+ if (apiGatewayEvent.getPath() != null) {
+ span.setAttribute("url.path", apiGatewayEvent.getPath());
+ }
+
+ if (apiGatewayEvent.getQueryStringParameters() != null) {
+
+ String queryString = apiGatewayEvent.getQueryStringParameters()
+ .entrySet()
+ .stream()
+ .map(entry -> entry.getKey() + "=" + entry.getValue())
+ .collect(Collectors.joining("&"));
+
+ span.setAttribute("url.query", queryString);
+ }
+
+ if (apiGatewayEvent.getHeaders() != null) {
+
+ apiGatewayEvent.getHeaders()
+ .entrySet()
+ .stream()
+ .filter(entry -> "user-agent".equalsIgnoreCase(entry.getKey()))
+ .map(Map.Entry::getValue)
+ .findFirst()
+ .ifPresent(userAgent -> span.setAttribute("user_agent.original", userAgent));
+ }
+
+ if (apiGatewayEvent.getRequestContext() != null) {
+
+ APIGatewayProxyRequestEvent.ProxyRequestContext requestContext =
+ apiGatewayEvent.getRequestContext();
+
+ if (requestContext.getRequestId() != null) {
+ span.setAttribute("aws.request_id", requestContext.getRequestId());
+ }
+
+ if (requestContext.getStage() != null) {
+ span.setAttribute("aws.apigateway.stage", requestContext.getStage());
+ }
+
+ if (requestContext.getResourceId() != null) {
+ span.setAttribute("aws.apigateway.resource_id", requestContext.getResourceId());
+ }
+
+ if (requestContext.getResourcePath() != null) {
+ span.setAttribute("aws.apigateway.resource_path", requestContext.getResourcePath());
+ }
+ }
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/DynamoDbTraceContextExtractor.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/DynamoDbTraceContextExtractor.java
new file mode 100644
index 000000000..acdbe1bab
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/DynamoDbTraceContextExtractor.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.context;
+
+import com.amazonaws.services.lambda.runtime.events.DynamodbEvent;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A specialized implementation of {@link LambdaEventContextExtractor} for handling AWS DynamoDB Streams events.
+ * This class enables extraction of tracing context, enrichment of OpenTelemetry spans, and determination of
+ * compatibility with DynamoDB Streams events for distributed tracing purposes.
+ *
+ * Instances of this class focus on the following:
+ * - Verifying if an event is a DynamoDB Streams event.
+ * - Extracting trace context information in scenarios where trace context propagation is applicable.
+ * - Enriching OpenTelemetry spans with metadata derived from DynamoDB Streams events, such as stream names
+ * and record batch sizes.
+ *
+ * Note: Due to limitations in DynamoDB Streams metadata, W3C trace context propagation (e.g., `traceparent`)
+ * is not supported by default. Future enhancements for dedicated propagation strategies may be required.
+ */
+public final class DynamoDbTraceContextExtractor implements LambdaEventContextExtractor {
+
+ @Override
+ public boolean supports(Object event) {
+ return event instanceof DynamodbEvent;
+ }
+
+ @Override
+ public ExtractedTraceContext extract(Object event, Context parentContext, TextMapPropagator propagator) {
+
+ /*
+ * DynamoDB Streams records do not expose message attributes
+ * that can be used for W3C trace context propagation.
+ *
+ * Do not assume that traceparent is stored inside the DynamoDB
+ * record payload. Propagation through DynamoDB Streams should be
+ * defined by a dedicated propagation strategy if supported in
+ * the future.
+ */
+ return new ExtractedTraceContext(parentContext, List.of(), SpanKind.CONSUMER);
+ }
+
+ @Override
+ public void enrichSpan(Object event, Span span) {
+
+ DynamodbEvent dynamoDBEvent = (DynamodbEvent) event;
+
+ if (dynamoDBEvent.getRecords() == null || dynamoDBEvent.getRecords().isEmpty()) {
+ return;
+ }
+
+ DynamodbEvent.DynamodbStreamRecord record = dynamoDBEvent.getRecords()
+ .stream()
+ .filter(Objects::nonNull)
+ .findFirst()
+ .orElse(null);
+
+ if (record == null) {
+ return;
+ }
+
+ span.setAttribute("messaging.system", "aws.dynamodb");
+
+ span.setAttribute("messaging.batch.message_count", dynamoDBEvent.getRecords().size());
+ if (record.getEventSourceARN() != null) {
+ span.setAttribute("messaging.destination.name", extractStreamName(record.getEventSourceARN()));
+ }
+ }
+
+ private String extractStreamName(String streamArn) {
+ int separator = streamArn.lastIndexOf('/');
+
+ return separator >= 0
+ ? streamArn.substring(separator + 1)
+ : streamArn;
+ }
+}
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/ExtractedTraceContext.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/ExtractedTraceContext.java
new file mode 100644
index 000000000..3a7abd2e7
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/ExtractedTraceContext.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.context;
+
+import io.opentelemetry.api.trace.SpanContext;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import java.util.List;
+
+/**
+ * Represents the trace context extracted during event processing in an OpenTelemetry-based tracing system.
+ * This class encapsulates the parent context, a collection of span contexts, and the span kind associated
+ * with the extracted trace.
+ *
+ * Instances of this class are immutable, ensuring thread-safety when utilized in multi-threaded environments.
+ */
+public final class ExtractedTraceContext {
+
+ private final Context parentContext;
+ private final List spanContexts;
+ private final SpanKind spanKind;
+
+ public ExtractedTraceContext(Context parentContext, List spanContexts, SpanKind spanKind) {
+ this.parentContext = parentContext;
+ this.spanContexts = spanContexts;
+ this.spanKind = spanKind;
+ }
+
+ public ExtractedTraceContext(Context parentContext, List spanContexts) {
+ this.parentContext = parentContext;
+ this.spanContexts = spanContexts;
+ this.spanKind = SpanKind.SERVER;
+ }
+
+ /**
+ * Returns the parent context associated with this extracted trace context.
+ * The parent context provides the linkage to the pre-existing context
+ * in the OpenTelemetry system, enabling context propagation.
+ *
+ * @return the parent {@link Context} of this extracted trace context
+ */
+ public Context context() {
+ return parentContext;
+ }
+
+ /**
+ * Returns the collection of {@link SpanContext} instances associated with this extracted trace context.
+ * Span contexts represent individual trace spans, enabling correlation and telemetry processing
+ * across distributed systems.
+ *
+ * @return a list of {@link SpanContext} instances associated with this trace context
+ */
+ public List spanContexts() {
+ return spanContexts;
+ }
+
+ /**
+ * Returns the span kind associated with this extracted trace context.
+ * The span kind indicates the role of the span in a distributed trace,
+ * such as SERVER, CLIENT, PRODUCER, or CONSUMER.
+ *
+ * @return the {@link SpanKind} of this extracted trace context
+ */
+ public SpanKind spanKind() {
+ return spanKind;
+ }
+}
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/KinesisTraceContextExtractor.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/KinesisTraceContextExtractor.java
new file mode 100644
index 000000000..739fcb9a7
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/KinesisTraceContextExtractor.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.context;
+
+import com.amazonaws.services.lambda.runtime.events.KinesisEvent;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+import java.util.List;
+
+/**
+ * An implementation of the {@link LambdaEventContextExtractor} interface designed
+ * for AWS Lambda functions that are triggered by Kinesis events. This class
+ * provides methods for extracting trace context, determining support for
+ * Kinesis events, and enriching spans with metadata specific to Kinesis.
+ *
+ * Trace propagation for Kinesis is limited, as Kinesis records do not inherently
+ * include W3C trace context propagation attributes. As such, this implementation
+ * assumes trace context is not present in the payload and instead defines how
+ * future propagation strategies could be supported.
+ *
+ * This class primarily handles the following responsibilities:
+ * - Identifies whether a given event is a Kinesis event.
+ * - Extracts minimal trace context from a Kinesis event, returning a consumer
+ * span kind without assuming additional trace attributes.
+ * - Enriches spans with Kinesis-specific attributes, such as partition key,
+ * sequence number, approximate arrival timestamp, and stream name.
+ *
+ * It is intended for use in distributed tracing scenarios within AWS Lambda
+ * functions, ensuring that spans generated for Kinesis events are annotated
+ * with meaningful metadata.
+ */
+public final class KinesisTraceContextExtractor
+ implements LambdaEventContextExtractor {
+
+ @Override
+ public boolean supports(Object event) {
+ return event instanceof KinesisEvent;
+ }
+
+ @Override
+ public ExtractedTraceContext extract(Object event, Context parentContext, TextMapPropagator propagator) {
+
+ /*
+ * Kinesis records do not expose message attributes
+ * that can be used for W3C trace context propagation.
+ *
+ * Do not assume that traceparent is stored inside the Kinesis
+ * record payload. Propagation through Kinesis should be
+ * defined by a dedicated propagation strategy if supported in
+ * the future.
+ */
+
+ return new ExtractedTraceContext(parentContext, List.of(), SpanKind.CONSUMER);
+ }
+
+ @Override
+ public void enrichSpan(Object event, Span span) {
+
+ KinesisEvent kinesisEvent = (KinesisEvent) event;
+
+ if (kinesisEvent.getRecords() == null || kinesisEvent.getRecords().isEmpty()) {
+ return;
+ }
+
+ KinesisEvent.KinesisEventRecord firstRecord = kinesisEvent.getRecords().get(0);
+
+ if (firstRecord == null || firstRecord.getKinesis() == null) {
+ return;
+ }
+
+ KinesisEvent.Record kinesis = firstRecord.getKinesis();
+
+ span.setAttribute("messaging.system", "aws.kinesis");
+
+ if (kinesis.getPartitionKey() != null) {
+ span.setAttribute("messaging.partition_key", kinesis.getPartitionKey());
+ }
+
+ if (kinesis.getSequenceNumber() != null) {
+ span.setAttribute("messaging.message.id", kinesis.getSequenceNumber());
+ }
+
+ if (kinesis.getApproximateArrivalTimestamp() != null) {
+ span.setAttribute("messaging.message.receive.timestamp",
+ kinesis.getApproximateArrivalTimestamp().getTime());
+ }
+
+ if (firstRecord.getEventSourceARN() != null) {
+ span.setAttribute("messaging.destination.name", extractStreamName(firstRecord.getEventSourceARN()));
+ }
+ }
+
+
+ private String extractStreamName(String arn) {
+ int separator = arn.lastIndexOf('/');
+
+ return separator >= 0
+ ? arn.substring(separator + 1)
+ : arn;
+ }
+}
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/LambdaEventContextExtractor.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/LambdaEventContextExtractor.java
new file mode 100644
index 000000000..8bc2c9741
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/LambdaEventContextExtractor.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.context;
+
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+
+/**
+ * Defines a contract for extracting, enriching, and validating tracing context information
+ * from AWS Lambda event objects in order to support distributed tracing.
+ *
+ * Implementations of this interface are intended to handle specific types of AWS Lambda
+ * event sources, such as SQS, SNS, DynamoDB, Kinesis, or API Gateway events. The methods
+ * within this interface facilitate propagating and enriching trace information within
+ * OpenTelemetry spans and contexts.
+ */
+public interface LambdaEventContextExtractor {
+
+ /**
+ * Determines whether the provided event is supported by this context extractor.
+ *
+ * @param event The AWS Lambda event to check for compatibility. Typically, this would
+ * be an event source object such as SQS, SNS, DynamoDB, Kinesis, API
+ * Gateway, or other supported AWS Lambda event types.
+ * @return true if the given event type is supported by this extractor;
+ * false otherwise.
+ */
+ boolean supports(Object event);
+
+ /**
+ * Enriches the provided OpenTelemetry span with metadata extracted from the given AWS Lambda event.
+ * This method is intended to populate the span with attributes that are specific to the event type,
+ * such as metadata about the source, destination, or other relevant contextual information.
+ *
+ * @param event The AWS Lambda event object containing the data from which span attributes are derived.
+ * This could be an event-specific object, such as an S3Event, SQS event, or API Gateway event.
+ * @param span The OpenTelemetry {@link Span} to be enriched with attributes based on the provided event.
+ */
+ void enrichSpan(Object event, Span span);
+
+ /**
+ * Extracts trace context information from the given AWS Lambda event to facilitate distributed tracing.
+ * This method utilizes the provided `TextMapPropagator` to extract trace context information and creates
+ * an {@link ExtractedTraceContext} object containing the extracted data.
+ *
+ * @param event The AWS Lambda event object from which trace context should be extracted. This could be
+ * an event-specific object like S3Event, SQS event, or API Gateway event.
+ * @param parentContext The parent OpenTelemetry {@link Context} that serves as the starting point for
+ * trace extraction. This is typically passed from the Lambda function's invocation.
+ * @param propagator A {@link TextMapPropagator} instance used to extract trace context from the event
+ * metadata or headers.
+ * @return An {@link ExtractedTraceContext} containing the extracted trace data, including the parent context,
+ * span contexts, and span kind. If no trace information is found, an {@link ExtractedTraceContext}
+ * with an empty list of span contexts is returned.
+ */
+ ExtractedTraceContext extract(Object event, Context parentContext, TextMapPropagator propagator);
+}
\ No newline at end of file
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/LambdaEventContextExtractorResolver.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/LambdaEventContextExtractorResolver.java
new file mode 100644
index 000000000..a020207ff
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/LambdaEventContextExtractorResolver.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.context;
+
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+import java.util.List;
+
+/**
+ * Resolves and delegates processing of Lambda-specific event contexts to the appropriate
+ * {@link LambdaEventContextExtractor} implementation based on the event type.
+ * This resolver allows for dynamic extraction and span enrichment tailored to
+ * various AWS Lambda event sources (e.g., API Gateway, SQS, SNS, etc.).
+ *
+ * This class is immutable and thread-safe.
+ */
+public final class LambdaEventContextExtractorResolver {
+
+ private final List extractors;
+
+ public LambdaEventContextExtractorResolver(List extractors) {
+
+ this.extractors = List.copyOf(extractors);
+ }
+
+ /**
+ * Creates and returns an instance of {@link LambdaEventContextExtractorResolver} configured with
+ * a predefined set of {@link LambdaEventContextExtractor} implementations. These extractors are specialized in
+ * processing different types of AWS Lambda event sources, such as API Gateway, SQS, SNS, Kinesis, DynamoDB, and S3.
+ *
+ * @return a new instance of {@link LambdaEventContextExtractorResolver} with predefined extractors for
+ * handling various AWS Lambda event contexts.
+ */
+ public static LambdaEventContextExtractorResolver create() {
+ return new LambdaEventContextExtractorResolver(
+ List.of(
+ new ApiGatewayTraceContextExtractor(),
+ new SqsTraceContextExtractor(),
+ new SnsTraceContextExtractor(),
+ new KinesisTraceContextExtractor(),
+ new DynamoDbTraceContextExtractor(),
+ new S3TraceContextExtractor()
+ )
+ );
+ }
+
+ /**
+ * Extracts trace context information from a Lambda event using the appropriate
+ * {@link LambdaEventContextExtractor} implementation that supports the event type.
+ * This method delegates the extraction to the first extractor in the configured list
+ * that supports the provided event type. If no suitable extractor is found, a default
+ * {@link ExtractedTraceContext} is returned using the provided parent context.
+ *
+ * @param event the Lambda event from which to extract the trace context
+ * @param parentContext the parent {@link Context} to be used as the base for the extraction
+ * @param propagator the {@link TextMapPropagator} used to extract propagation information from the event
+ * @return an {@link ExtractedTraceContext} containing the extracted trace context or a default one
+ * if no supporting extractor is found
+ */
+ public ExtractedTraceContext extract(Object event, Context parentContext, TextMapPropagator propagator) {
+
+ return extractors.stream()
+ .filter(extractor -> extractor.supports(event))
+ .findFirst()
+ .map(extractor ->
+ extractor.extract(
+ event,
+ parentContext,
+ propagator))
+ .orElse(new ExtractedTraceContext(parentContext, List.of()));
+ }
+
+ /**
+ * Enriches a given {@link Span} with contextual information extracted from
+ * the specified event. This method evaluates a list of configured extractors
+ * and delegates the enrichment process to the first extractor that supports
+ * the provided event type.
+ *
+ * @param event the event object containing context information to be added to the span
+ * @param span the {@link Span} instance to be enriched with extracted information
+ */
+ public void enrichSpan(Object event, Span span) {
+ extractors.stream()
+ .filter(extractor -> extractor.supports(event))
+ .findFirst()
+ .ifPresent(extractor -> extractor.enrichSpan(event, span));
+ }
+}
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/S3TraceContextExtractor.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/S3TraceContextExtractor.java
new file mode 100644
index 000000000..f6e314f5a
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/S3TraceContextExtractor.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.context;
+
+import com.amazonaws.services.lambda.runtime.events.S3Event;
+import com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A context extractor implementation for handling AWS S3 event notifications within an AWS Lambda environment.
+ * This extractor is responsible for determining if an event can be processed, extracting trace context
+ * information, and enriching spans with metadata related to the S3 event.
+ *
+ * This implementation assumes that S3 event payloads do not contain trace context attributes (e.g.,
+ * traceparent or tracestate) and handles them accordingly.
+ */
+public final class S3TraceContextExtractor implements LambdaEventContextExtractor {
+
+ @Override
+ public boolean supports(Object event) {
+ return event instanceof S3Event;
+ }
+
+ @Override
+ public ExtractedTraceContext extract(Object event, Context parentContext, TextMapPropagator propagator) {
+
+ /*
+ * S3 event notifications do not expose message attributes
+ * equivalent to SQS/SNS that can be passed directly to a
+ * TextMapPropagator.
+ *
+ * Do not assume that traceparent/tracestate are embedded
+ * inside the S3 event payload.
+ */
+ return new ExtractedTraceContext(parentContext, List.of(), SpanKind.CONSUMER);
+ }
+
+ @Override
+ public void enrichSpan(Object event, Span span) {
+
+ S3Event s3Event = (S3Event) event;
+
+ if (s3Event.getRecords() == null || s3Event.getRecords().isEmpty()) {
+ return;
+ }
+
+ span.setAttribute("messaging.system", "aws.s3");
+
+ span.setAttribute("messaging.batch.message_count", s3Event.getRecords().size());
+
+ S3EventNotification.S3EventNotificationRecord record =
+ s3Event.getRecords()
+ .stream()
+ .filter(Objects::nonNull)
+ .findFirst()
+ .orElse(null);
+
+ if (record == null || record.getS3() == null) {
+ return;
+ }
+
+ if (record.getS3().getBucket() != null
+ && record.getS3().getBucket().getName() != null) {
+
+ span.setAttribute("messaging.destination.name", record.getS3().getBucket().getName());
+ }
+
+ if (record.getEventName() != null) {
+ span.setAttribute("messaging.event.type", record.getEventName());
+ }
+ }
+}
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/SnsTraceContextExtractor.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/SnsTraceContextExtractor.java
new file mode 100644
index 000000000..3bd260554
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/SnsTraceContextExtractor.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.context;
+
+import com.amazonaws.services.lambda.runtime.events.SNSEvent;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanContext;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import software.amazon.lambda.powertools.tracing.opentelemetry.provider.OpenTelemetryProvider;
+
+/**
+ * An implementation of {@link LambdaEventContextExtractor} specifically designed to handle AWS Simple Notification
+ * Service (SNS) events.
+ * This class provides mechanisms to extract trace context from SNS event records and enrich spans with relevant
+ * messaging attributes.
+ * It supports processing instances of {@code SNSEvent}.
+ *
+ *
+ * - {@code supports}: Determines if the given event is an instance of SNS event.
+ * - {@code extract}: Extracts trace context data from message attributes of the SNS event records and generates
+ * an {@link ExtractedTraceContext}.
+ * - {@code enrichSpan}: Enriches the span with attributes pertaining to the SNS messaging system, such as the
+ * topic name and messaging system specific values.
+ *
+ *
+ * This class also ensures trace propagation by parsing SNS message attributes and converting them into OpenTelemetry
+ * context.
+ * It supports multi-record SNS events and handles cases where certain records or attributes are invalid.
+ */
+public final class SnsTraceContextExtractor implements LambdaEventContextExtractor {
+
+ @Override
+ public boolean supports(Object event) {
+ return event instanceof SNSEvent;
+ }
+
+ @Override
+ public ExtractedTraceContext extract(Object event, Context parentContext, TextMapPropagator propagator) {
+
+ SNSEvent snsEvent = (SNSEvent) event;
+
+ if (snsEvent.getRecords() == null || snsEvent.getRecords().isEmpty()) {
+ return new ExtractedTraceContext(parentContext, List.of(), SpanKind.CONSUMER);
+ }
+
+ List spanContexts = new ArrayList<>();
+
+ for (SNSEvent.SNSRecord record : snsEvent.getRecords()) {
+
+ if (record == null || record.getSNS() == null) {
+ continue;
+ }
+
+ Map attributes = record.getSNS().getMessageAttributes();
+
+ if (attributes == null || attributes.isEmpty()) {
+ continue;
+ }
+
+ Map propagationAttributes = attributes.entrySet()
+ .stream()
+ .filter(entry -> entry.getValue() != null)
+ .filter(entry -> entry.getValue().getValue() != null)
+ .collect(Collectors.toMap(
+ Map.Entry::getKey,
+ entry -> entry.getValue().getValue()
+ ));
+
+ if (propagationAttributes.isEmpty()) {
+ continue;
+ }
+
+ Context extractedContext = propagator.extract(
+ Context.root(),
+ propagationAttributes,
+ OpenTelemetryProvider.textMapGetter()
+ );
+
+ SpanContext spanContext = Span.fromContext(extractedContext).getSpanContext();
+
+ if (spanContext.isValid()) {
+ spanContexts.add(spanContext);
+ }
+ }
+
+ Context parent = spanContexts.isEmpty()
+ ? parentContext
+ : Context.root().with(Span.wrap(spanContexts.get(0)));
+
+ return new ExtractedTraceContext(parent, spanContexts, SpanKind.CONSUMER);
+ }
+
+ @Override
+ public void enrichSpan(Object event, Span span) {
+
+ SNSEvent snsEvent = (SNSEvent) event;
+
+ if (snsEvent.getRecords() == null || snsEvent.getRecords().isEmpty()) {
+ return;
+ }
+
+ SNSEvent.SNSRecord record = snsEvent.getRecords()
+ .stream()
+ .filter(r -> r != null && r.getSNS() != null)
+ .findFirst()
+ .orElse(null);
+
+ if (record == null) {
+ return;
+ }
+
+ span.setAttribute("messaging.system", "aws.sns");
+
+ if (record.getSNS().getTopicArn() != null) {
+ span.setAttribute("messaging.destination.name", extractTopicName(record.getSNS().getTopicArn()));
+ }
+ }
+
+ private String extractTopicName(String topicArn) {
+ int separator = topicArn.lastIndexOf(':');
+
+ return separator >= 0
+ ? topicArn.substring(separator + 1)
+ : topicArn;
+ }
+}
\ No newline at end of file
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/SqsTraceContextExtractor.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/SqsTraceContextExtractor.java
new file mode 100644
index 000000000..d8427e5f8
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/SqsTraceContextExtractor.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.context;
+
+import com.amazonaws.services.lambda.runtime.events.SQSEvent;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanContext;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import software.amazon.lambda.powertools.tracing.opentelemetry.provider.OpenTelemetryProvider;
+
+/**
+ * SqsTraceContextExtractor is responsible for extracting and enriching trace context
+ * information from AWS SQS events in the context of AWS Lambda functions. It implements
+ * the {@code LambdaEventContextExtractor} interface, providing functionality to determine
+ * support for an event, extract trace context, and enrich spans with additional attributes.
+ *
+ * The class processes SQS events by iterating through the batch of SQS messages, extracting
+ * propagation headers from message attributes, and building trace context information to be
+ * propagated and used by OpenTelemetry.
+ *
+ * Key functionalities include:
+ * - Determining if the extractor supports the provided event.
+ * - Extracting trace context from propagation headers present in SQS message attributes.
+ * - Enriching spans with messaging system details, including the number of messages in a batch
+ * and the queue name from the event source.
+ *
+ * This class is intended for use with AWS Lambda functions processing SQS events for tracing
+ * distributed systems.
+ *
+ * Thread-safety: This class is immutable and thread-safe.
+ */
+public final class SqsTraceContextExtractor implements LambdaEventContextExtractor {
+
+ @Override
+ public boolean supports(Object event) {
+ return event instanceof SQSEvent;
+ }
+
+ @Override
+ public ExtractedTraceContext extract(Object event, Context parentContext, TextMapPropagator propagator) {
+
+ SQSEvent sqsEvent = (SQSEvent) event;
+
+ if (sqsEvent.getRecords() == null || sqsEvent.getRecords().isEmpty()) {
+ return new ExtractedTraceContext(parentContext, List.of(), SpanKind.CONSUMER);
+ }
+
+ List spanContexts = new ArrayList<>();
+
+ for (SQSEvent.SQSMessage message : sqsEvent.getRecords()) {
+
+ if (message == null || message.getMessageAttributes() == null) {
+ continue;
+ }
+
+ Map attributes = message.getMessageAttributes();
+
+ if (attributes.isEmpty()) {
+ continue;
+ }
+
+ Map propagationAttributes = attributes.entrySet()
+ .stream()
+ .filter(entry -> entry.getValue() != null)
+ .filter(entry -> entry.getValue().getStringValue() != null)
+ .collect(Collectors.toMap(
+ Map.Entry::getKey,
+ entry -> entry.getValue().getStringValue()
+ ));
+
+ Context extractedContext = propagator.extract(
+ Context.root(),
+ propagationAttributes,
+ OpenTelemetryProvider.textMapGetter()
+ );
+
+ SpanContext spanContext = Span.fromContext(extractedContext).getSpanContext();
+
+ if (spanContext.isValid()) {
+ spanContexts.add(spanContext);
+ }
+ }
+
+ Context parent = spanContexts.isEmpty()
+ ? parentContext
+ : Context.root().with(Span.wrap(spanContexts.get(0)));
+
+ return new ExtractedTraceContext(parent, spanContexts, SpanKind.CONSUMER);
+ }
+
+ @Override
+ public void enrichSpan(Object event, Span span) {
+ SQSEvent sqsEvent = (SQSEvent) event;
+
+ if (sqsEvent.getRecords() == null || sqsEvent.getRecords().isEmpty()) {
+ return;
+ }
+
+ span.setAttribute("messaging.system", "aws.sqs");
+
+ span.setAttribute("messaging.batch.message_count", sqsEvent.getRecords().size());
+
+ SQSEvent.SQSMessage message = sqsEvent.getRecords().get(0);
+
+ if (message.getEventSourceArn() != null) {
+ span.setAttribute("messaging.destination.name", extractQueueName(message.getEventSourceArn()));
+ }
+ }
+
+ private String extractQueueName(String arn) {
+ int separator = arn.lastIndexOf(':');
+
+ return separator >= 0
+ ? arn.substring(separator + 1)
+ : arn;
+ }
+}
\ No newline at end of file
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/TraceContextPropagationMode.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/TraceContextPropagationMode.java
new file mode 100644
index 000000000..407ff58c9
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/context/TraceContextPropagationMode.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.context;
+
+/**
+ * Enum representing different modes of trace context propagation.
+ *
+ * Trace context propagation defines how tracing information is passed
+ * between distributed systems to capture the relationship between trace spans.
+ */
+public enum TraceContextPropagationMode {
+ PARENT,
+ LINK
+}
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/AttributesConstants.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/AttributesConstants.java
new file mode 100644
index 000000000..d299b2b78
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/AttributesConstants.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.internal;
+
+/**
+ * A utility class that holds constant values for various attribute names and configurations
+ * used in AWS Lambda and Powertools for AWS Lambda. These constants are mainly used for
+ * telemetry, tracing, and environment variable configuration within the application.
+ *
+ * This class is designed as a final class with a private constructor to prevent instantiation
+ * and ensure it acts solely as a container for constants.
+ */
+public final class AttributesConstants {
+
+ private AttributesConstants() {
+ // Constant holder class
+ }
+
+ public static final String AWS_LAMBDA_FUNCTION_NAME = "AWS_LAMBDA_FUNCTION_NAME";
+
+ public static final String AWS_LAMBDA_FUNCTION_VERSION = "AWS_LAMBDA_FUNCTION_VERSION";
+
+ public static final String AWS_LAMBDA_FUNCTION_MEMORY_SIZE = "AWS_LAMBDA_FUNCTION_MEMORY_SIZE";
+
+ public static final String AWS_LAMBDA_LOG_STREAM_NAME = "AWS_LAMBDA_LOG_STREAM_NAME";
+
+ public static final String AWS_REGION = "AWS_REGION";
+
+ public static final String AWS_LAMBDA_FUNCTION_ARN = "AWS_LAMBDA_FUNCTION_ARN";
+
+ public static final String TELEMETRY_DISTRO_NAME = "powertools-for-aws-lambda";
+
+ public static final String FAAS_COLDSTART = "faas.coldstart";
+
+ public static final String FAAS_INVOCATION_ID = "faas.invocation_id";
+
+ public static final String RESPONSE_ATTRIBUTE = "aws.lambda.powertools.response";
+
+ public static final String CAPTURE_RESPONSE_ENV = "POWERTOOLS_TRACER_CAPTURE_RESPONSE";
+
+ public static final String CAPTURE_ERROR_ENV = "POWERTOOLS_TRACER_CAPTURE_ERROR";
+
+ public static final String TRACEPARENT = "traceparent";
+
+ public static final String TRACESTATE = "tracestate";
+}
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/LambdaResource.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/LambdaResource.java
new file mode 100644
index 000000000..1f8646377
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/LambdaResource.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.internal;
+
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.common.AttributesBuilder;
+import io.opentelemetry.sdk.resources.Resource;
+import software.amazon.lambda.powertools.common.internal.SystemWrapper;
+
+/**
+ * The {@code LambdaResource} class is a utility for creating a representation of
+ * an AWS Lambda execution environment in the form of a {@code Resource} object.
+ * It extracts and structures metadata about the Lambda function's runtime environment,
+ * which is useful for telemetry and observability purposes.
+ *
+ *
Responsibilities:
+ *
+ * - Populates resource attributes based on AWS Lambda-specific environment variables.
+ * - Includes attributes related to the cloud provider, service, function details, and
+ * OpenTelemetry metadata.
+ * - Processes function execution context such as memory size and account ID from the
+ * AWS Lambda environment.
+ * - Ensures only relevant and non-empty values are added as attributes.
+ *
+ * This class is designed to be final and non-instantiable, serving purely as a
+ * container for a static method.
+ */
+public final class LambdaResource {
+
+ private LambdaResource() {
+ }
+
+ /**
+ * Creates a Resource instance populated with attributes derived from the
+ * AWS Lambda environment. The attributes include cloud provider information,
+ * service details, function memory size, account ID, and OpenTelemetry metadata.
+ *
+ * It retrieves environment variables specific to AWS Lambda and processes
+ * them to build a comprehensive resource description.
+ *
+ * @return a Resource object containing attributes about the AWS Lambda environment
+ */
+ public static Resource create() {
+ AttributesBuilder attributes = Attributes.builder();
+
+ putIfPresent(
+ attributes,
+ "cloud.provider",
+ "aws"
+ );
+
+ putIfPresent(
+ attributes,
+ "cloud.region",
+ SystemWrapper.getenv(AttributesConstants.AWS_REGION)
+ );
+
+ putIfPresent(
+ attributes,
+ "service.name",
+ SystemWrapper.getenv(AttributesConstants.AWS_LAMBDA_FUNCTION_NAME)
+ );
+
+ putIfPresent(
+ attributes,
+ "service.version",
+ SystemWrapper.getenv(AttributesConstants.AWS_LAMBDA_FUNCTION_VERSION)
+ );
+
+ putIfPresent(
+ attributes,
+ "faas.name",
+ SystemWrapper.getenv(AttributesConstants.AWS_LAMBDA_FUNCTION_NAME)
+ );
+
+ putIfPresent(
+ attributes,
+ "faas.version",
+ SystemWrapper.getenv(AttributesConstants.AWS_LAMBDA_FUNCTION_VERSION)
+ );
+
+ putIfPresent(
+ attributes,
+ "faas.instance",
+ SystemWrapper.getenv(AttributesConstants.AWS_LAMBDA_LOG_STREAM_NAME)
+ );
+
+ String memory = SystemWrapper.getenv(AttributesConstants.AWS_LAMBDA_FUNCTION_MEMORY_SIZE);
+
+ if (memory != null) {
+ attributes.put(
+ "faas.max_memory",
+ Long.parseLong(memory)
+ );
+ }
+
+ String functionArn = SystemWrapper.getenv(AttributesConstants.AWS_LAMBDA_FUNCTION_ARN);
+
+ if (functionArn != null) {
+ String accountId = extractAccountId(functionArn);
+
+ if (accountId != null) {
+ attributes.put(
+ "cloud.account.id",
+ accountId
+ );
+ }
+ }
+
+ attributes.put(
+ "telemetry.sdk.name",
+ "opentelemetry"
+ );
+
+ attributes.put(
+ "telemetry.distro.name",
+ AttributesConstants.TELEMETRY_DISTRO_NAME
+ );
+
+ attributes.put(
+ "telemetry.sdk.language",
+ "java"
+ );
+
+ return Resource.create(attributes.build());
+ }
+
+ private static void putIfPresent(
+ AttributesBuilder attributes,
+ String key,
+ String value) {
+
+ if (value != null && !value.isBlank()) {
+ attributes.put(key, value);
+ }
+ }
+
+ private static String extractAccountId(String arn) {
+ String[] parts = arn.split(":");
+
+ return parts.length > 4
+ ? parts[4]
+ : null;
+ }
+}
\ No newline at end of file
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/SpanOperation.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/SpanOperation.java
new file mode 100644
index 000000000..174829d5a
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/SpanOperation.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.internal;
+
+import io.opentelemetry.api.trace.Span;
+
+/**
+ * Represents a functional interface used to execute a custom operation within
+ * the context of a given {@link Span}. This interface requires implementing a
+ * single method that performs an operation with the span and optionally
+ * returns a result.
+ *
+ *
+ * The {@code SpanOperation} interface enables tracing and manipulation of
+ * a span during its lifecycle, such as setting attributes, adding events,
+ * or updating status codes. It can be used alongside frameworks that support
+ * OpenTelemetry for distributed tracing.
+ *
+ * @param the type of result returned by the custom span operation
+ */
+@FunctionalInterface
+public interface SpanOperation {
+
+ /**
+ * Executes a custom operation within the context of the provided {@link Span}.
+ * This method allows for interaction with the span, such as adding events,
+ * setting attributes, or manipulating its status during the operation.
+ *
+ * @param span the {@link Span} within whose context the operation will be executed
+ * @throws Exception if an error occurs during the execution of the operation
+ */
+ T execute(Span span) throws Exception;
+}
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/SpanScope.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/SpanScope.java
new file mode 100644
index 000000000..944927af5
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/SpanScope.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.internal;
+
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.StatusCode;
+import io.opentelemetry.context.Scope;
+
+/**
+ * A utility class that combines a {@link Span} and its associated {@link Scope},
+ * managing the lifecycle of both. This class ensures that the span is properly ended and the scope is
+ * closed when the {@code SpanScope} is no longer needed.
+ *
+ *
+ * The {@code SpanScope} class facilitates interaction with the {@link Span} during its lifecycle by
+ * providing methods to set its status, add events, and record exceptions. Upon closing, the span is
+ * finalized, and the associated scope is released.
+ *
+ *
+ * Thread Safety
+ * This class is not thread-safe and must be used only within the thread it was created.
+ *
+ * Usage
+ * Instances of this class should be used in a try-with-resources block to ensure proper cleanup.
+ *
+ * Important Notes
+ * - The {@link Span} should be created and managed by an OpenTelemetry tracer or similar system.
+ * - Always close the {@code SpanScope} to release resources and end the span.
+ */
+public final class SpanScope implements AutoCloseable {
+
+ private final Span span;
+ private final Scope scope;
+
+ public SpanScope(Span span) {
+ this.span = span;
+ this.scope = span.makeCurrent();
+ }
+
+ /**
+ * Retrieves the {@link Span} associated with this {@code SpanScope}.
+ *
+ * @return the {@link Span} managed by this {@code SpanScope}.
+ */
+ public Span span() {
+ return span;
+ }
+
+ /**
+ * Updates the status of the associated span.
+ *
+ * @param status the {@link StatusCode} to set for the span
+ * @return the current {@code SpanScope} instance for method chaining
+ */
+ public SpanScope setStatus(StatusCode status) {
+ span.setStatus(status);
+ return this;
+ }
+
+ /**
+ * Adds an event to the associated {@link Span} with the specified name.
+ *
+ * @param name the name of the event to be added to the span
+ * @return the current {@code SpanScope} instance for method chaining
+ */
+ public SpanScope addEvent(String name) {
+ span.addEvent(name);
+ return this;
+ }
+
+ /**
+ * Adds an event with the specified name and attributes to the associated {@link Span}.
+ *
+ * @param name the name of the event to add
+ * @param attributes the attributes associated with the event
+ * @return the current {@code SpanScope} instance for method chaining
+ */
+ public SpanScope addEvent(String name, Attributes attributes) {
+ span.addEvent(name, attributes);
+ return this;
+ }
+
+ /**
+ * Records an exception in the associated {@link Span} and sets its status to {@code ERROR}.
+ * This method is used to log and signal the occurrence of an error condition within the span.
+ *
+ * @param throwable the {@link Throwable} instance representing the exception to record
+ */
+ public void recordException(Throwable throwable) {
+ span.recordException(throwable);
+ span.setStatus(StatusCode.ERROR);
+ }
+
+ /**
+ * Closes the underlying resources associated with this {@code SpanScope}.
+ * This method ensures that the {@code scope} is closed to release any associated
+ * context and marks the end of the {@code span}'s lifecycle by calling its {@code end()} method.
+ *
+ * This method should be invoked to properly clean up resources and signal the end
+ * of the tracing span when the scope is no longer needed.
+ */
+ @Override
+ public void close() {
+ scope.close();
+ span.end();
+ }
+}
\ No newline at end of file
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/TracingOpenTelemetryAspect.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/TracingOpenTelemetryAspect.java
new file mode 100644
index 000000000..7a7458924
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/TracingOpenTelemetryAspect.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.internal;
+
+import static software.amazon.lambda.powertools.common.internal.LambdaHandlerProcessor.coldStartDone;
+import static software.amazon.lambda.powertools.common.internal.LambdaHandlerProcessor.isColdStart;
+import static software.amazon.lambda.powertools.common.internal.LambdaHandlerProcessor.isHandlerMethod;
+
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.context.Context;
+import java.util.Objects;
+import java.util.Optional;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import software.amazon.lambda.powertools.common.internal.LambdaHandlerProcessor;
+import software.amazon.lambda.powertools.common.internal.SystemWrapper;
+import software.amazon.lambda.powertools.tracing.opentelemetry.Tracing;
+import software.amazon.lambda.powertools.tracing.opentelemetry.TracingOpenTelemetry;
+import software.amazon.lambda.powertools.tracing.opentelemetry.context.ExtractedTraceContext;
+import software.amazon.lambda.powertools.tracing.opentelemetry.context.TraceContextPropagationMode;
+import software.amazon.lambda.powertools.tracing.opentelemetry.provider.OpenTelemetryProvider;
+
+/**
+ * TracingOpenTelemetryAspect is an AspectJ aspect that facilitates tracing for methods annotated
+ * with the {@link Tracing} annotation. It integrates with OpenTelemetry to automatically create and
+ * manage spans for annotated methods, capturing execution context, responses, and errors.
+ *
+ *
Functional Overview:
+ * - Creates and manages OpenTelemetry spans around methods annotated with {@link Tracing}.
+ * - Supports both handler and internal method spans.
+ * - Extracts contextual information if available to enrich spans.
+ * - Captures response data and errors based on configurable capture modes.
+ * - Flushes telemetry data upon span completion.
+ *
+ * Key Methods:
+ *
+ * - configure - Sets a custom {@link TracingOpenTelemetry} instance to be used.
+ * - callAt - Defines the pointcut for methods annotated with {@link Tracing}.
+ * - around - Core functionality that wraps the target method execution with a span.
+ *
+ *
+ * Trace Context Handling:
+ * - Extracts trace context for handler methods for more seamless propagation.
+ * - Supports linking spans or connecting to existing parent spans based on configuration.
+ *
+ * Capture Modes:
+ * - The capture modes ({@link Tracing.CaptureMode}) dictate whether and how responses and errors are
+ * recorded in spans:
+ * - RESPONSE_AND_ERROR: Captures both responses and errors.
+ * - RESPONSE: Captures only responses.
+ * - ERROR: Captures only errors.
+ * - DISABLED: Disables any capture.
+ * - ENVIRONMENT_VAR: Determines capture based on environment variables.
+ *
+ * Span Creation:
+ * - Handler spans include additional AWS Lambda-related metadata if applicable.
+ * - Internal method spans are marked with a default {@link SpanKind#INTERNAL}.
+ *
+ * Error Handling:
+ * - Ensures exceptions are propagated while recording them in the span if enabled.
+ *
+ * Thread Safety:
+ * - The class ensures thread safety for span management in concurrent environments.
+ *
+ * Note: This class requires OpenTelemetry to be properly configured in the application context.
+ */
+@Aspect
+public final class TracingOpenTelemetryAspect {
+
+ // Cannot be final for testing purposes
+ private static TracingOpenTelemetry tracingOtel = TracingOpenTelemetry.create();
+
+ public static void configure(TracingOpenTelemetry tracing) {
+ tracingOtel = Objects.requireNonNull(tracing);
+ }
+
+ @SuppressWarnings("EmptyMethod")
+ @Pointcut("@annotation(tracing)")
+ public void callAt(Tracing tracing) {
+ }
+
+ @Around(
+ value = "callAt(tracing) && execution(@Tracing * *.*(..))",
+ argNames = "pjp,tracing"
+ )
+ public Object around(ProceedingJoinPoint pjp, Tracing tracing) throws Throwable {
+
+ String spanName = tracing.spanName().isEmpty()
+ ? pjp.getSignature().getName()
+ : tracing.spanName();
+
+ if (isHandlerMethod(pjp)) {
+ return traceHandler(pjp, tracing, spanName);
+ }
+
+ return traceMethod(pjp, tracing, spanName);
+ }
+
+ private Object traceHandler(ProceedingJoinPoint pjp, Tracing tracing, String spanName) throws Throwable {
+
+ ExtractedTraceContext extractedTraceContext = extractTraceContext(pjp);
+
+ try (SpanScope scope = addHandlerSpan(spanName, extractedTraceContext)) {
+
+ Span span = scope.span();
+
+ tracingOtel.eventContextExtractorResolver().enrichSpan(pjp.getArgs()[0], span);
+
+ addLambdaInvocationAttributes(pjp, span);
+
+ try {
+
+ Object result = pjp.proceed(pjp.getArgs());
+
+ captureResponse(span, tracing, result);
+
+ coldStartDone();
+
+ return result;
+
+ } catch (Throwable throwable) {
+
+ captureError(scope, tracing, throwable);
+
+ throw throwable;
+ }
+ } finally {
+ tracingOtel.flush();
+ }
+ }
+
+ private SpanScope addHandlerSpan(String spanName, ExtractedTraceContext extractedTraceContext) {
+
+ if (shouldUseSpanLinks(extractedTraceContext)) {
+ return tracingOtel.addSpan(
+ spanName,
+ extractedTraceContext.spanKind(),
+ handlerAttributes(),
+ Context.current(),
+ extractedTraceContext.spanContexts()
+ );
+ }
+
+ return tracingOtel.addSpan(
+ spanName,
+ extractedTraceContext.spanKind(),
+ handlerAttributes(),
+ extractedTraceContext.context()
+ );
+ }
+
+ private boolean shouldUseSpanLinks(ExtractedTraceContext extractedTraceContext) {
+
+ return OpenTelemetryProvider.traceContextPropagationMode() == TraceContextPropagationMode.LINK
+ && !extractedTraceContext.spanContexts().isEmpty();
+ }
+
+ private Object traceMethod(ProceedingJoinPoint pjp, Tracing tracing, String spanName) throws Throwable {
+
+ try (SpanScope scope = tracingOtel.addSpan(spanName, SpanKind.INTERNAL, Attributes.empty(),
+ Context.current())) {
+
+ Span span = scope.span();
+
+ try {
+ Object result = pjp.proceed(pjp.getArgs());
+
+ captureResponse(span, tracing, result);
+
+ return result;
+
+ } catch (Throwable throwable) {
+
+ captureError(scope, tracing, throwable);
+
+ throw throwable;
+ }
+ }
+ }
+
+ private ExtractedTraceContext extractTraceContext(ProceedingJoinPoint pjp) {
+
+ return tracingOtel.eventContextExtractorResolver().extract(
+ pjp.getArgs()[0],
+ Context.current(),
+ tracingOtel.propagator()
+ );
+ }
+
+ private Attributes handlerAttributes() {
+ return Attributes.builder()
+ .put(AttributesConstants.FAAS_COLDSTART, isColdStart())
+ .build();
+ }
+
+ private void addLambdaInvocationAttributes(ProceedingJoinPoint pjp, Span span) {
+
+ Optional.ofNullable(LambdaHandlerProcessor.extractContext(pjp))
+ .ifPresent(
+ context -> span.setAttribute(AttributesConstants.FAAS_INVOCATION_ID, context.getAwsRequestId()
+ )
+ );
+ }
+
+ private void captureResponse(Span span, Tracing tracing, Object response) throws Exception {
+
+ if (!isCaptureResponseEnabled(tracing)) {
+ return;
+ }
+
+ span.setAttribute(
+ AttributesConstants.RESPONSE_ATTRIBUTE,
+ OpenTelemetryProvider.objectMapper().writeValueAsString(response)
+ );
+ }
+
+ private void captureError(SpanScope scope, Tracing tracing, Throwable throwable) {
+
+ if (isCaptureErrorEnabled(tracing)) {
+ scope.recordException(throwable);
+ }
+ }
+
+ private boolean isCaptureResponseEnabled(Tracing tracing) {
+ switch (tracing.captureMode()) {
+ case ENVIRONMENT_VAR:
+ return isEnvironmentVariableSet(
+ AttributesConstants.CAPTURE_RESPONSE_ENV)
+ && environmentVariable(
+ AttributesConstants.CAPTURE_RESPONSE_ENV);
+
+ case RESPONSE:
+ case RESPONSE_AND_ERROR:
+ return true;
+
+ case DISABLED:
+ case ERROR:
+ default:
+ return false;
+ }
+ }
+
+ private boolean isCaptureErrorEnabled(Tracing tracing) {
+ switch (tracing.captureMode()) {
+ case ENVIRONMENT_VAR:
+ return isEnvironmentVariableSet(
+ AttributesConstants.CAPTURE_ERROR_ENV)
+ && environmentVariable(
+ AttributesConstants.CAPTURE_ERROR_ENV);
+
+ case ERROR:
+ case RESPONSE_AND_ERROR:
+ return true;
+
+ case DISABLED:
+ case RESPONSE:
+ default:
+ return false;
+ }
+ }
+
+ private boolean environmentVariable(String key) {
+ return Boolean.parseBoolean(SystemWrapper.getenv(key));
+ }
+
+ private boolean isEnvironmentVariableSet(String key) {
+ return SystemWrapper.containsKey(key);
+ }
+}
\ No newline at end of file
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/TracingUserAgentInterceptor.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/TracingUserAgentInterceptor.java
new file mode 100644
index 000000000..b2f58a699
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/TracingUserAgentInterceptor.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.internal;
+
+import software.amazon.awssdk.core.SdkRequest;
+import software.amazon.awssdk.core.interceptor.Context;
+import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
+import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
+import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator;
+
+/**
+ * Global interceptor that configures the User-Agent for all AWS SDK clients
+ * when the powertools-tracing module is on the classpath.
+ */
+public final class TracingUserAgentInterceptor implements ExecutionInterceptor {
+ static {
+ UserAgentConfigurator.configureUserAgent("tracing-opentelemetry");
+ }
+
+ @Override
+ public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
+ // This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is
+ // loaded by AWS SDK Global Interceptors.
+ return context.request();
+ }
+}
diff --git a/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/provider/OpenTelemetryProvider.java b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/provider/OpenTelemetryProvider.java
new file mode 100644
index 000000000..b9b5b3903
--- /dev/null
+++ b/powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/provider/OpenTelemetryProvider.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates.
+ * 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 software.amazon.lambda.powertools.tracing.opentelemetry.provider;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
+import io.opentelemetry.context.propagation.ContextPropagators;
+import io.opentelemetry.context.propagation.TextMapGetter;
+import io.opentelemetry.context.propagation.TextMapPropagator;
+import io.opentelemetry.contrib.awsxray.propagator.AwsXrayPropagator;
+import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
+import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder;
+import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
+import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
+import io.opentelemetry.sdk.common.CompletableResultCode;
+import io.opentelemetry.sdk.trace.SdkTracerProvider;
+import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
+import io.opentelemetry.sdk.trace.export.SpanExporter;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import software.amazon.lambda.powertools.common.internal.SystemWrapper;
+import software.amazon.lambda.powertools.tracing.opentelemetry.context.TraceContextPropagationMode;
+import software.amazon.lambda.powertools.tracing.opentelemetry.internal.LambdaResource;
+
+/**
+ * Provides a managed OpenTelemetry instance tailored for AWS Lambda Powertools.
+ * This class enables easy integration of tracing capabilities using OpenTelemetry
+ * for AWS Lambda function monitoring.
+ *
+ * It supports automatic instrumentation configuration through environment variables
+ * and enables customized configurations for propagators, tracing mode, exporter,
+ * and tracer provider.
+ *
+ * OpenTelemetryProvider ensures compatibility with the ADOT Lambda layer and javaagent,
+ * using the configured global OpenTelemetry instance when available. If no global
+ * configuration exists, it creates and uses a Lambda-optimized configuration.
+ *
+ * Key functionalities include:
+ * - Access to a pre-configured {@code Tracer}.
+ * - Support for multiple propagation formats (e.g., W3C Trace Context, AWS X-Ray).
+ * - Batch span processing with configurable export batch size, queue size, and timeouts.
+ * - Lambda-optimized default resource configuration.
+ * - Parsing environment variables for OTLP configuration (e.g., protocol, endpoint).
+ *
+ * This class cannot be instantiated directly and provides its functionalities
+ * through static methods.
+ */
+public final class OpenTelemetryProvider {
+
+ private static final String INSTRUMENTATION_NAME = "aws-lambda-powertools";
+ private static final String OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL";
+ private static final String OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT";
+ private static final String OTEL_EXPORTER_OTLP_TRACES_HEADERS = "OTEL_EXPORTER_OTLP_TRACES_HEADERS";
+ private static final String TRACE_CONTEXT_PROPAGATION_MODE_ENV = "POWERTOOLS_TRACE_CONTEXT_PROPAGATION_MODE";
+
+ private static final int MAX_EXPORT_BATCH_SIZE = 10;
+ private static final int MAX_QUEUE_SIZE = 100;
+ private static final long SCHEDULE_DELAY_MILLIS = 1_000;
+ private static final long EXPORT_TIMEOUT_MILLIS = 3_000;
+
+ private static final TextMapPropagator PROPAGATOR = createPropagator();
+
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+ private static final TextMapGetter