Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
<module>powertools-parameters/powertools-parameters-appconfig</module>
<module>powertools-parameters/powertools-parameters-tests</module>
<module>examples</module>
<module>powertools-tracing-opentelemetry</module>
</modules>

<properties>
Expand Down Expand Up @@ -119,6 +120,7 @@
<junit-pioneer.version>2.3.0</junit-pioneer.version>
<crac.version>1.5.0</crac.version>
<native-maven-plugin.version>0.11.5</native-maven-plugin.version>
<opentelemetry-api.version>1.65.0</opentelemetry-api.version>

<!-- As we have a .mvn directory at the root of the project, this will evaluate to the root directory
regardless of where maven is run - sub-module, or root. -->
Expand Down
138 changes: 138 additions & 0 deletions powertools-tracing-opentelemetry/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<artifactId>powertools-tracing-opentelemetry</artifactId>
<packaging>jar</packaging>

<parent>
<groupId>software.amazon.lambda</groupId>
<artifactId>powertools-parent</artifactId>
<version>2.10.0</version>
</parent>

<name>Powertools for AWS Lambda (Java) - Tracing OpenTelemetry</name>
<description>
A suite of utilities for AWS Lambda Functions that makes tracing with OpenTelemetry, structured logging and creating custom metrics asynchronously easier.
</description>

<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<version>${opentelemetry-api.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>software.amazon.lambda</groupId>
<artifactId>powertools-common</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>aws-core</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>sdk-core</artifactId>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
<version>${opentelemetry-api.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-testing</artifactId>
<version>${opentelemetry-api.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>software.amazon.lambda</groupId>
<artifactId>powertools-common</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit-pioneer</groupId>
<artifactId>junit-pioneer</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<environmentVariables>
<AWS_LAMBDA_INITIALIZATION_TYPE>on-demand</AWS_LAMBDA_INITIALIZATION_TYPE>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* 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.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import java.util.Objects;
import software.amazon.lambda.powertools.tracing.opentelemetry.internal.SpanOperation;
import software.amazon.lambda.powertools.tracing.opentelemetry.internal.SpanScope;

/**
* A wrapper for OpenTelemetry's Tracer that simplifies the creation and management of spans.
* This class provides utility functions for starting and controlling spans and their contexts
* in the current execution thread.
* <p>
* This is a final class and cannot be extended.
*/
public final class TracingOpenTelemetry {

private final Tracer tracer;

private TracingOpenTelemetry(Builder builder) {
this.tracer = builder.tracer;
}

/**
* Creates a new span with the specified name and makes it the current span in the thread context.
* The span must be manually closed to properly end it and revert the thread context.
*
* @param name the name of the span to be created
* @return an instance of {@link SpanScope}, which represents the created span and its associated context
*/
public SpanScope addSpan(String name) {
return new SpanScope(tracer.spanBuilder(name).startSpan());
}

/**
* Retrieves the current active span in the execution context.
*
* @return the current {@link Span} if one is active, or a default no-op {@link Span} if none is active
*/
public Span currentSpan() {
return Span.current();
}

/**
* Executes the specified operation within the context of a new span.
* The span is automatically managed and closed when the operation completes
* or an exception is thrown.
*
* @param name the name of the span to be created
* @param operation the operation to be executed within the span's context
* @throws Exception if the provided operation throws an exception during execution
*/
public void withSpan(String name, SpanOperation operation) throws Exception {
try (SpanScope scope = addSpan(name)) {
try {
operation.execute(scope.span());
} catch (Exception e) {
scope.recordException(e);
throw e;
}
}
}

/**
* Creates and returns a new instance of the {@code Builder} class for constructing
* instances of {@code TracingOpenTelemetry}.
*
* @return a new {@code Builder} instance for configuring and building a {@code TracingOpenTelemetry} object
*/
public static Builder builder() {
return new Builder();
}

public static final class Builder {

private Tracer tracer;

public Builder tracer(Tracer tracer) {
this.tracer = tracer;
return this;
}

/**
* Builds and returns a {@code TracingOpenTelemetry} instance configured with the specified {@code Tracer}.
* The returned instance provides utilities for creating and managing spans.
*
* @return a fully constructed {@code TracingOpenTelemetry} object based on the builder's configuration
* @throws NullPointerException if the {@code tracer} has not been set
*/
public TracingOpenTelemetry build() {
Objects.requireNonNull(tracer, "tracer must not be null");
return new TracingOpenTelemetry(this);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 that encapsulates an operation to be performed
* within the context of an OpenTelemetry {@link Span}.
* <p>
* This interface provides a contract for defining custom operations that take a
* {@link Span} as input and execute within its context. It is used in conjunction
* with utilities that manage OpenTelemetry spans, such as the {@code withSpan} method
* in the {@code TracingOpenTelemetry} class.
* <p>
* Implementations of this interface enable the customization of behavior for spans,
* including adding events, setting attributes, or modifying the span's status.
* <p>
* The operation defined by the {@code execute} method can throw an exception, which
* allows for handling of error scenarios and proper recording of exceptions in the span.
*/
@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
*/
void execute(Span span) throws Exception;

Check warning on line 45 in powertools-tracing-opentelemetry/src/main/java/software/amazon/lambda/powertools/tracing/opentelemetry/internal/SpanOperation.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace generic exceptions with specific library exceptions or a custom exception.

See more on https://sonarcloud.io/project/issues?id=aws-powertools_powertools-lambda-java&issues=AZ_nRLugA1Estd7HbqKp&open=AZ_nRLugA1Estd7HbqKp&pullRequest=2607
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Scope;

/**
* A utility class that manages the lifecycle of a span and its associated context
* within a thread. It ensures that the span is properly closed and the thread context
* is restored when the scope is closed.
* <p>
* This class is primarily used to work with OpenTelemetry spans, making them current
* in the thread context and managing their lifecycle, including recording exceptions
* and handling automatic cleanup of associated resources.
* <p>
* It implements {@link AutoCloseable}, allowing it to be used in try-with-resources blocks
* to ensure proper cleanup of the span and scope.
*/
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 {@link SpanScope}.
*
* @return the {@link Span} managed by this {@link SpanScope}
*/
public Span span() {
return span;
}

/**
* Records an exception in the span and sets its status to {@code StatusCode.ERROR}.
*
* @param throwable the {@link Throwable} instance to be recorded as an event in the span.
*/
public void recordException(Throwable throwable) {
span.recordException(throwable);
span.setStatus(StatusCode.ERROR);
}

@Override
public void close() {
scope.close();
span.end();
}
}
Loading