Let AWS Lambda SQS handlers report partial batch failures (#14468)
This commit is contained in:
parent
c04b8fc492
commit
fd74eb8a98
|
|
@ -346,6 +346,12 @@ targets:
|
|||
- type: gradle
|
||||
path: ./
|
||||
target: ':instrumentation:aws-lambda:aws-lambda-events-2.2:library'
|
||||
- type: gradle
|
||||
path: ./
|
||||
target: ':instrumentation:aws-lambda:aws-lambda-events-3.11:library'
|
||||
- type: gradle
|
||||
path: ./
|
||||
target: ':instrumentation:aws-lambda:aws-lambda-events-common-2.2:library'
|
||||
- type: gradle
|
||||
path: ./
|
||||
target: ':instrumentation:aws-sdk:aws-sdk-1.11:javaagent'
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ These are the supported libraries and frameworks:
|
|||
| [Armeria gRPC](https://armeria.dev) | 1.14+ | | [RPC Client Spans], [RPC Client Metrics], [RPC Server Spans], [RPC Server Metrics] |
|
||||
| [AsyncHttpClient](https://github.com/AsyncHttpClient/async-http-client) | 1.9+ | N/A | [HTTP Client Spans], [HTTP Client Metrics] |
|
||||
| [Avaje Jex](https://avaje.io/jex/) | 3.0+ | N/A | Provides `http.route` [2] |
|
||||
| [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html) | 1.0+ | [opentelemetry-aws-lambda-core-1.0](../instrumentation/aws-lambda/aws-lambda-core-1.0/library),<br>[opentelemetry-aws-lambda-events-2.2](../instrumentation/aws-lambda/aws-lambda-events-2.2/library) | [FaaS Server Spans] |
|
||||
| [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html) | 1.0+ | [opentelemetry-aws-lambda-core-1.0](../instrumentation/aws-lambda/aws-lambda-core-1.0/library),<br>[opentelemetry-aws-lambda-events-3.11](../instrumentation/aws-lambda/aws-lambda-events-3.11/library) | [FaaS Server Spans] |
|
||||
| [AWS SDK](https://aws.amazon.com/sdk-for-java/) | 1.11 - 1.12.583,<br>2.2+ | [opentelemetry-aws-sdk-1.11](../instrumentation/aws-sdk/aws-sdk-1.11/library),<br>[opentelemetry-aws-sdk-1.11-autoconfigure](../instrumentation/aws-sdk/aws-sdk-1.11/library-autoconfigure),<br>[opentelemetry-aws-sdk-2.2](../instrumentation/aws-sdk/aws-sdk-2.2/library),<br>[opentelemetry-aws-sdk-2.2-autoconfigure](../instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure) | [Messaging Spans], [Database Client Spans], [Database Client Metrics] [6], [HTTP Client Spans], [GenAI Client Spans], [GenAI Client Metrics] |
|
||||
| [Azure Core](https://docs.microsoft.com/en-us/java/api/overview/azure/core-readme) | 1.14+ | N/A | Context propagation |
|
||||
| [Cassandra Driver](https://github.com/datastax/java-driver) | 3.0+ | [opentelemetry-cassandra-4.4](../instrumentation/cassandra/cassandra-4.4/library) | [Database Client Spans], [Database Client Metrics] [6] |
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ dependencies {
|
|||
|
||||
implementation(project(":instrumentation:aws-lambda:aws-lambda-core-1.0:library"))
|
||||
|
||||
implementation(project(":instrumentation:aws-lambda:aws-lambda-events-2.2:library")) {
|
||||
implementation(project(":instrumentation:aws-lambda:aws-lambda-events-common-2.2:library")) {
|
||||
// Only needed by wrappers, not the javaagent. Muzzle will catch if we accidentally change this.
|
||||
exclude("com.fasterxml.jackson.core", "jackson-databind")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,19 +10,21 @@ import io.opentelemetry.api.GlobalOpenTelemetry;
|
|||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.AwsLambdaFunctionInstrumenter;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrapperConfiguration;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal.AwsLambdaEventsInstrumenterFactory;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal.AwsLambdaSqsInstrumenterFactory;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.AwsLambdaEventsInstrumenterFactory;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.AwsLambdaSqsInstrumenterFactory;
|
||||
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig;
|
||||
import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig;
|
||||
import java.time.Duration;
|
||||
|
||||
public final class AwsLambdaSingletons {
|
||||
|
||||
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.aws-lambda-events-2.2";
|
||||
private static final AwsLambdaFunctionInstrumenter FUNCTION_INSTRUMENTER =
|
||||
AwsLambdaEventsInstrumenterFactory.createInstrumenter(
|
||||
GlobalOpenTelemetry.get(), AgentCommonConfig.get().getKnownHttpRequestMethods());
|
||||
GlobalOpenTelemetry.get(),
|
||||
INSTRUMENTATION_NAME,
|
||||
AgentCommonConfig.get().getKnownHttpRequestMethods());
|
||||
private static final Instrumenter<SQSEvent, Void> MESSAGE_TRACER =
|
||||
AwsLambdaSqsInstrumenterFactory.forEvent(GlobalOpenTelemetry.get());
|
||||
AwsLambdaSqsInstrumenterFactory.forEvent(GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME);
|
||||
private static final Duration FLUSH_TIMEOUT =
|
||||
Duration.ofMillis(
|
||||
AgentInstrumentationConfig.get()
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@ plugins {
|
|||
|
||||
dependencies {
|
||||
api(project(":instrumentation:aws-lambda:aws-lambda-core-1.0:library"))
|
||||
implementation(project(":instrumentation:aws-lambda:aws-lambda-events-common-2.2:library"))
|
||||
compileOnly(project(":instrumentation:aws-lambda:aws-lambda-events-3.11:library"))
|
||||
|
||||
compileOnly("io.opentelemetry:opentelemetry-sdk")
|
||||
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
|
||||
|
||||
compileOnly("com.google.auto.value:auto-value-annotations")
|
||||
annotationProcessor("com.google.auto.value:auto-value")
|
||||
|
||||
library("com.amazonaws:aws-lambda-java-core:1.0.0")
|
||||
// First version to includes support for SQSEvent, currently the most popular message queue used
|
||||
// with lambda.
|
||||
|
|
@ -25,13 +24,6 @@ dependencies {
|
|||
// So that is the reason that why we add it as compile only dependency.
|
||||
compileOnly("com.amazonaws:aws-lambda-java-serialization:1.1.5")
|
||||
|
||||
// We need Jackson for wrappers to reproduce the serialization does when Lambda invokes a RequestHandler with event
|
||||
// since Lambda will only be able to invoke the wrapper itself with a generic Object.
|
||||
// Note that Lambda itself uses Jackson, but does not expose it to the function so we need to include it here.
|
||||
// TODO: Switch to aws-lambda-java-serialization to more robustly follow Lambda's serialization logic.
|
||||
implementation("com.fasterxml.jackson.core:jackson-databind")
|
||||
implementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator")
|
||||
|
||||
// allows to get the function ARN
|
||||
testLibrary("com.amazonaws:aws-lambda-java-core:1.2.1")
|
||||
// allows to get the default events
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import com.amazonaws.services.lambda.runtime.Context;
|
|||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
|
||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal.SerializationUtil;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.SerializationUtil;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
|
|
@ -17,7 +17,12 @@ import java.util.function.BiFunction;
|
|||
* Wrapper for {@link io.opentelemetry.instrumentation.awslambdacore.v1_0.TracingRequestHandler}.
|
||||
* Allows for wrapping a lambda proxied through API Gateway, enabling single span tracing and HTTP
|
||||
* context propagation.
|
||||
*
|
||||
* @deprecated use {@link
|
||||
* io.opentelemetry.instrumentation.awslambdaevents.v3_11.TracingRequestApiGatewayWrapper}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class TracingRequestApiGatewayWrapper
|
||||
extends TracingRequestWrapperBase<APIGatewayProxyRequestEvent, Object> {
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ import io.opentelemetry.instrumentation.awslambdacore.v1_0.TracingRequestStreamW
|
|||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.ApiGatewayProxyRequest;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.MapUtils;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal.SerializationUtil;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.LambdaParameters;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.SerializationUtil;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
|
@ -26,7 +27,11 @@ import java.util.Map;
|
|||
|
||||
/**
|
||||
* Wrapper for {@link com.amazonaws.services.lambda.runtime.RequestHandler} based Lambda handlers.
|
||||
*
|
||||
* @deprecated use {@link
|
||||
* io.opentelemetry.instrumentation.awslambdaevents.v3_11.TracingRequestWrapper} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class TracingRequestWrapper extends TracingRequestStreamWrapper {
|
||||
public TracingRequestWrapper() {
|
||||
super();
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ import io.opentelemetry.instrumentation.awslambdacore.v1_0.TracingRequestHandler
|
|||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.MapUtils;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrapperConfiguration;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal.AwsLambdaEventsInstrumenterFactory;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.AwsLambdaEventsInstrumenterFactory;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.LambdaParameters;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
|
@ -26,6 +27,7 @@ import java.util.function.BiFunction;
|
|||
* env property OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER in package.ClassName::methodName format
|
||||
*/
|
||||
abstract class TracingRequestWrapperBase<I, O> extends TracingRequestHandler<I, O> {
|
||||
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.aws-lambda-events-2.2";
|
||||
|
||||
private final WrappedLambda wrappedLambda;
|
||||
private final Method targetMethod;
|
||||
|
|
@ -47,7 +49,7 @@ abstract class TracingRequestWrapperBase<I, O> extends TracingRequestHandler<I,
|
|||
openTelemetrySdk,
|
||||
WrapperConfiguration.flushTimeout(),
|
||||
AwsLambdaEventsInstrumenterFactory.createInstrumenter(
|
||||
openTelemetrySdk, HttpConstants.KNOWN_METHODS));
|
||||
openTelemetrySdk, INSTRUMENTATION_NAME, HttpConstants.KNOWN_METHODS));
|
||||
this.wrappedLambda = wrappedLambda;
|
||||
this.targetMethod = wrappedLambda.getRequestTargetMethod();
|
||||
this.parameterMapper = parameterMapper;
|
||||
|
|
|
|||
|
|
@ -10,11 +10,17 @@ import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
|||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.TracingRequestHandler;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal.AwsLambdaSqsInstrumenterFactory;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.AwsLambdaSqsInstrumenterFactory;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* @deprecated use {@link
|
||||
* io.opentelemetry.instrumentation.awslambdaevents.v3_11.TracingSqsEventHandler} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class TracingSqsEventHandler extends TracingRequestHandler<SQSEvent, Void> {
|
||||
static final String INSTRUMENTATION_NAME = "io.opentelemetry.aws-lambda-events-2.2";
|
||||
|
||||
private final Instrumenter<SQSEvent, Void> instrumenter;
|
||||
|
||||
|
|
@ -33,7 +39,9 @@ public abstract class TracingSqsEventHandler extends TracingRequestHandler<SQSEv
|
|||
*/
|
||||
protected TracingSqsEventHandler(OpenTelemetrySdk openTelemetrySdk, Duration flushTimeout) {
|
||||
this(
|
||||
openTelemetrySdk, flushTimeout, AwsLambdaSqsInstrumenterFactory.forEvent(openTelemetrySdk));
|
||||
openTelemetrySdk,
|
||||
flushTimeout,
|
||||
AwsLambdaSqsInstrumenterFactory.forEvent(openTelemetrySdk, INSTRUMENTATION_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -9,11 +9,17 @@ import com.amazonaws.services.lambda.runtime.Context;
|
|||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrapperConfiguration;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.LambdaParameters;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @deprecated use {@link
|
||||
* io.opentelemetry.instrumentation.awslambdaevents.v3_11.TracingSqsEventWrapper} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class TracingSqsEventWrapper extends TracingSqsEventHandler {
|
||||
|
||||
private final WrappedLambda wrappedLambda;
|
||||
|
|
|
|||
|
|
@ -10,10 +10,15 @@ import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
|||
import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal.AwsLambdaSqsInstrumenterFactory;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.AwsLambdaSqsInstrumenterFactory;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* @deprecated use {@link
|
||||
* io.opentelemetry.instrumentation.awslambdaevents.v3_11.TracingSqsMessageHandler} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class TracingSqsMessageHandler extends TracingSqsEventHandler {
|
||||
|
||||
private final Instrumenter<SQSMessage, Void> messageInstrumenter;
|
||||
|
|
@ -33,7 +38,9 @@ public abstract class TracingSqsMessageHandler extends TracingSqsEventHandler {
|
|||
*/
|
||||
protected TracingSqsMessageHandler(OpenTelemetrySdk openTelemetrySdk, Duration flushTimeout) {
|
||||
this(
|
||||
openTelemetrySdk, flushTimeout, AwsLambdaSqsInstrumenterFactory.forEvent(openTelemetrySdk));
|
||||
openTelemetrySdk,
|
||||
flushTimeout,
|
||||
AwsLambdaSqsInstrumenterFactory.forEvent(openTelemetrySdk, INSTRUMENTATION_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -50,7 +57,7 @@ public abstract class TracingSqsMessageHandler extends TracingSqsEventHandler {
|
|||
openTelemetrySdk,
|
||||
flushTimeout,
|
||||
eventInstrumenter,
|
||||
AwsLambdaSqsInstrumenterFactory.forMessage(openTelemetrySdk));
|
||||
AwsLambdaSqsInstrumenterFactory.forMessage(openTelemetrySdk, INSTRUMENTATION_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
|||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
@SuppressWarnings("deprecation") // testing deprecated class
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class AwsLambdaApiGatewayWrapperTest {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExte
|
|||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@SuppressWarnings("deprecation") // testing deprecated class
|
||||
class AwsLambdaSqsEventHandlerTest extends AbstractAwsLambdaSqsEventHandlerTest {
|
||||
|
||||
@RegisterExtension
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import org.junitpioneer.jupiter.SetEnvironmentVariable;
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@SuppressWarnings("deprecation") // testing deprecated class
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@SetEnvironmentVariable(
|
||||
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@SuppressWarnings("deprecation") // testing deprecated class
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AwsLambdaSqsMessageHandlerTest {
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import org.junitpioneer.jupiter.SetEnvironmentVariable;
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@SuppressWarnings("deprecation") // testing deprecated class
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AwsLambdaWrapperTest {
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import com.amazonaws.services.lambda.runtime.events.SNSEvent;
|
|||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import com.amazonaws.services.lambda.runtime.events.ScheduledEvent;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal.SerializationUtil;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.SerializationUtil;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -24,6 +24,7 @@ import java.util.Map;
|
|||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
@SuppressWarnings("deprecation") // testing deprecated class
|
||||
class TracingRequestWrapperStandardEventsTest {
|
||||
private static final Map<Class<?>, EventInfo> EVENTS_JSON = buildEventExamples();
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public abstract class AbstractAwsLambdaSqsEventHandlerTest {
|
|||
private static final String AWS_TRACE_HEADER =
|
||||
"Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1";
|
||||
|
||||
protected abstract RequestHandler<SQSEvent, Void> handler();
|
||||
protected abstract RequestHandler<SQSEvent, ?> handler();
|
||||
|
||||
protected abstract InstrumentationExtension testing();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
# AWS Lambda Instrumentation
|
||||
|
||||
This package contains libraries to help instrument AWS lambda functions in your code.
|
||||
|
||||
## Using wrappers
|
||||
|
||||
To use the instrumentation, configure `OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER` env property to your lambda handler method in following format `package.ClassName::methodName`
|
||||
and use one of wrappers as your lambda `Handler`.
|
||||
|
||||
In order to configure a span flush timeout (default is set to 10 seconds), please configure `OTEL_INSTRUMENTATION_AWS_LAMBDA_FLUSH_TIMEOUT` env property. The value is in milliseconds.
|
||||
|
||||
Available wrappers:
|
||||
|
||||
- `io.opentelemetry.instrumentation.awslambdaevents.v3_11.TracingRequestWrapper` - for wrapping regular handlers (implementing `RequestHandler`)
|
||||
- `io.opentelemetry.instrumentation.awslambdaevents.v3_11.TracingRequestApiGatewayWrapper` - for wrapping regular handlers (implementing `RequestHandler`) proxied through API Gateway, enabling HTTP context propagation
|
||||
- `io.opentelemetry.instrumentation.awslambdacore.v1_0.TracingRequestStreamWrapper` - for wrapping streaming handlers (implementing `RequestStreamHandler`), enabling HTTP context propagation for HTTP requests
|
||||
|
||||
If you are only using `TracingRequestStreamWrapper`, consider using [aws-lambda-core-1.0](../../aws-lambda-core-1.0/library) instead to reduce the size of
|
||||
your compiled function.
|
||||
|
||||
## Using handlers
|
||||
|
||||
To use the instrumentation, replace your function classes that implement `RequestHandler` (or `RequestStreamHandler`) with those
|
||||
that extend `TracingRequestHandler` (or `TracingRequestStreamHandler`). You will need to change the method name to `doHandleRequest`
|
||||
and pass an initialized `OpenTelemetrySdk` to the base class.
|
||||
|
||||
```java
|
||||
public class MyRequestHandler extends TracingRequestHandler<String, String> {
|
||||
|
||||
private static final OpenTelemetrySdk SDK = OpenTelemetrySdk.builder()
|
||||
.addSpanProcessor(spanProcessor)
|
||||
.buildAndRegisterGlobal();
|
||||
|
||||
public MyRequestHandler() {
|
||||
super(SDK);
|
||||
}
|
||||
|
||||
// Note the method is named doHandleRequest instead of handleRequest.
|
||||
@Override
|
||||
protected String doHandleRequest(String input, Context context) {
|
||||
if (input.equals("hello")) {
|
||||
return "world";
|
||||
}
|
||||
return "goodbye";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A `SERVER` span will be created with the name you specify for the function when deploying it.
|
||||
|
||||
In addition, it is recommended to set up X-Ray trace propagation to be able to
|
||||
link to tracing information provided by Lambda itself. To do so, add a dependency on
|
||||
`opentelemetry-extension-tracepropagators`. Make sure the version matches the version of the SDK
|
||||
you use.
|
||||
|
||||
Gradle:
|
||||
|
||||
```kotlin
|
||||
dependencies {
|
||||
implementation("io.opentelemetry:opentelemetry-extension-trace-propagators:0.8.0")
|
||||
}
|
||||
```
|
||||
|
||||
Maven:
|
||||
|
||||
```xml
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.opentelemetry</groupId>
|
||||
<artifactId>opentelemetry-extension-trace-propagators</artifactId>
|
||||
<version>0.8.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
## SQS Handler
|
||||
|
||||
This package provides a special handler for SQS-triggered functions to include messaging data.
|
||||
If using SQS, it is recommended to use them instead of `TracingRequestHandler`.
|
||||
|
||||
If your application processes one message at a time, each independently, it is recommended to extend
|
||||
`TracingSQSMessageHandler`. This will create a single span corresponding to a received batch of
|
||||
messages along with one span for each of the messages as you process them.
|
||||
|
||||
```java
|
||||
public class MyMessageHandler extends TracingSQSMessageHandler {
|
||||
@Override
|
||||
protected boolean handleMessage(SQSMessage message, Context context) {
|
||||
System.out.println(message.getBody());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you handle a batch of messages together, for example by aggregating them into a single unit,
|
||||
extend `TracingSQSEventHandler` to process a batch at a time.
|
||||
|
||||
```java
|
||||
public class MyBatchHandler extends TracingSQSEventHandler {
|
||||
@Override
|
||||
protected SQSBatchResponse handleEvent(SQSEvent event, Context context) {
|
||||
System.out.println(event.getRecords().size());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Trace propagation
|
||||
|
||||
Context propagation for this instrumentation can be done either with X-Ray propagation or regular HTTP propagation. If X-Ray is enabled for instrumented lambda, it will be preferred. If X-Ray is disabled, HTTP propagation will be tried (that is HTTP headers will be read to check for a valid trace context).
|
||||
|
||||
### X-Ray propagation
|
||||
|
||||
This instrumentation supports propagating traces using the `X-Amzn-Trace-Id` format for both normal
|
||||
requests and SQS requests. X-Ray propagation is always enabled, there is no need to configure it explicitly.
|
||||
|
||||
### HTTP headers based propagation
|
||||
|
||||
For API Gateway (HTTP) requests instrumented by using one of following methods:
|
||||
|
||||
- extending `TracingRequestStreamHandler` or `TracingRequestHandler`
|
||||
- wrapping with `TracingRequestStreamWrapper` or `TracingRequestApiGatewayWrapper`
|
||||
traces can be propagated with supported HTTP headers (see <https://github.com/open-telemetry/opentelemetry-java/tree/main/extensions/trace-propagators>).
|
||||
|
||||
In order to enable requested propagation for a handler, configure it on the SDK you build.
|
||||
|
||||
```java
|
||||
static {
|
||||
OpenTelemetrySdk.builder()
|
||||
...
|
||||
.setPropagators(ContextPropagators.create(B3Propagator.injectingSingleHeader()))
|
||||
.buildAndRegisterGlobal();
|
||||
}
|
||||
```
|
||||
|
||||
If using the wrappers, set the `OTEL_PROPAGATORS` environment variable as described [here](https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#propagator).
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
plugins {
|
||||
id("otel.library-instrumentation")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":instrumentation:aws-lambda:aws-lambda-events-common-2.2:library"))
|
||||
|
||||
compileOnly("io.opentelemetry:opentelemetry-sdk")
|
||||
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
|
||||
|
||||
library("com.amazonaws:aws-lambda-java-core:1.0.0")
|
||||
library("com.amazonaws:aws-lambda-java-events:3.11.0")
|
||||
|
||||
// allows to get the function ARN
|
||||
testLibrary("com.amazonaws:aws-lambda-java-core:1.2.1")
|
||||
|
||||
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
|
||||
testImplementation("io.opentelemetry:opentelemetry-extension-trace-propagators")
|
||||
testImplementation("com.amazonaws:aws-lambda-java-serialization:1.1.5")
|
||||
|
||||
testImplementation(project(":instrumentation:aws-lambda:aws-lambda-events-2.2:testing"))
|
||||
testImplementation("uk.org.webcompere:system-stubs-jupiter")
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
// required on jdk17
|
||||
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
|
||||
jvmArgs("--add-opens=java.base/java.util=ALL-UNNAMED")
|
||||
jvmArgs("-XX:+IgnoreUnrecognizedVMOptions")
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
|
||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.SerializationUtil;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Wrapper for {@link io.opentelemetry.instrumentation.awslambdacore.v1_0.TracingRequestHandler}.
|
||||
* Allows for wrapping a lambda proxied through API Gateway, enabling single span tracing and HTTP
|
||||
* context propagation.
|
||||
*/
|
||||
public class TracingRequestApiGatewayWrapper
|
||||
extends TracingRequestWrapperBase<APIGatewayProxyRequestEvent, Object> {
|
||||
|
||||
public TracingRequestApiGatewayWrapper() {
|
||||
super(TracingRequestApiGatewayWrapper::map);
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
TracingRequestApiGatewayWrapper(
|
||||
OpenTelemetrySdk openTelemetrySdk,
|
||||
WrappedLambda wrappedLambda,
|
||||
BiFunction<APIGatewayProxyRequestEvent, Class<?>, Object> mapper) {
|
||||
super(openTelemetrySdk, wrappedLambda, mapper);
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
static <T> T map(APIGatewayProxyRequestEvent event, Class<T> clazz) {
|
||||
return SerializationUtil.fromJson(event.getBody(), clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected APIGatewayProxyResponseEvent doHandleRequest(
|
||||
APIGatewayProxyRequestEvent input, Context context) {
|
||||
Object result = super.doHandleRequest(input, context);
|
||||
APIGatewayProxyResponseEvent event;
|
||||
// map to response event if needed
|
||||
if (result instanceof APIGatewayProxyResponseEvent) {
|
||||
event = (APIGatewayProxyResponseEvent) result;
|
||||
} else {
|
||||
event = new APIGatewayProxyResponseEvent();
|
||||
event.setBody(SerializationUtil.toJson(result));
|
||||
}
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.AwsLambdaRequest;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.TracingRequestStreamWrapper;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.ApiGatewayProxyRequest;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.MapUtils;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.LambdaParameters;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.SerializationUtil;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Wrapper for {@link com.amazonaws.services.lambda.runtime.RequestHandler} based Lambda handlers.
|
||||
*/
|
||||
public class TracingRequestWrapper extends TracingRequestStreamWrapper {
|
||||
public TracingRequestWrapper() {
|
||||
super();
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
TracingRequestWrapper(OpenTelemetrySdk openTelemetrySdk, WrappedLambda wrappedLambda) {
|
||||
super(openTelemetrySdk, wrappedLambda);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final AwsLambdaRequest createRequest(
|
||||
InputStream inputStream, Context context, ApiGatewayProxyRequest proxyRequest) {
|
||||
Method targetMethod = wrappedLambda.getRequestTargetMethod();
|
||||
Object input = LambdaParameters.toInput(targetMethod, inputStream, TracingRequestWrapper::map);
|
||||
return AwsLambdaRequest.create(context, input, extractHeaders(input));
|
||||
}
|
||||
|
||||
protected Map<String, String> extractHeaders(Object input) {
|
||||
if (input instanceof APIGatewayProxyRequestEvent) {
|
||||
return MapUtils.emptyIfNull(((APIGatewayProxyRequestEvent) input).getHeaders());
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void doHandleRequest(
|
||||
InputStream input, OutputStream output, Context context, AwsLambdaRequest request) {
|
||||
Method targetMethod = wrappedLambda.getRequestTargetMethod();
|
||||
Object[] parameters = LambdaParameters.toParameters(targetMethod, request.getInput(), context);
|
||||
try {
|
||||
Object result = targetMethod.invoke(wrappedLambda.getTargetObject(), parameters);
|
||||
SerializationUtil.toJson(output, result);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Method is inaccessible", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw (e.getCause() instanceof RuntimeException
|
||||
? (RuntimeException) e.getCause()
|
||||
: new IllegalStateException(e.getTargetException()));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
|
||||
// Used for testing
|
||||
<INPUT, OUTPUT> OUTPUT handleRequest(INPUT input, Context context) throws IOException {
|
||||
byte[] inputJsonData = SerializationUtil.toJsonData(input);
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(inputJsonData);
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
||||
super.handleRequest(inputStream, outputStream, context);
|
||||
|
||||
byte[] outputJsonData = outputStream.toByteArray();
|
||||
return (OUTPUT)
|
||||
SerializationUtil.fromJson(
|
||||
new ByteArrayInputStream(outputJsonData),
|
||||
wrappedLambda.getRequestTargetMethod().getReturnType());
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
static <T> T map(InputStream inputStream, Class<T> clazz) {
|
||||
try {
|
||||
return SerializationUtil.fromJson(inputStream, clazz);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalStateException(
|
||||
"Could not map input to requested parameter type: " + clazz, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
|
||||
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.TracingRequestHandler;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.MapUtils;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrapperConfiguration;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.AwsLambdaEventsInstrumenterFactory;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.LambdaParameters;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Base abstract wrapper for {@link TracingRequestHandler}. Provides: - delegation to a lambda via
|
||||
* env property OTEL_INSTRUMENTATION_AWS_LAMBDA_HANDLER in package.ClassName::methodName format
|
||||
*/
|
||||
abstract class TracingRequestWrapperBase<I, O> extends TracingRequestHandler<I, O> {
|
||||
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.aws-lambda-events-3.11";
|
||||
|
||||
private final WrappedLambda wrappedLambda;
|
||||
private final Method targetMethod;
|
||||
private final BiFunction<I, Class<?>, Object> parameterMapper;
|
||||
|
||||
protected TracingRequestWrapperBase(BiFunction<I, Class<?>, Object> parameterMapper) {
|
||||
this(
|
||||
AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(),
|
||||
WrappedLambda.fromConfiguration(),
|
||||
parameterMapper);
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
TracingRequestWrapperBase(
|
||||
OpenTelemetrySdk openTelemetrySdk,
|
||||
WrappedLambda wrappedLambda,
|
||||
BiFunction<I, Class<?>, Object> parameterMapper) {
|
||||
super(
|
||||
openTelemetrySdk,
|
||||
WrapperConfiguration.flushTimeout(),
|
||||
AwsLambdaEventsInstrumenterFactory.createInstrumenter(
|
||||
openTelemetrySdk, INSTRUMENTATION_NAME, HttpConstants.KNOWN_METHODS));
|
||||
this.wrappedLambda = wrappedLambda;
|
||||
this.targetMethod = wrappedLambda.getRequestTargetMethod();
|
||||
this.parameterMapper = parameterMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected O doHandleRequest(I input, Context context) {
|
||||
Object[] parameters = LambdaParameters.toArray(targetMethod, input, context, parameterMapper);
|
||||
O result;
|
||||
try {
|
||||
result = (O) targetMethod.invoke(wrappedLambda.getTargetObject(), parameters);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Method is inaccessible", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw (e.getCause() instanceof RuntimeException
|
||||
? (RuntimeException) e.getCause()
|
||||
: new IllegalStateException(e.getTargetException()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final Map<String, String> extractHttpHeaders(I input) {
|
||||
if (input instanceof APIGatewayProxyRequestEvent) {
|
||||
return MapUtils.emptyIfNull(((APIGatewayProxyRequestEvent) input).getHeaders());
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSBatchResponse;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.TracingRequestHandler;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.AwsLambdaSqsInstrumenterFactory;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import java.time.Duration;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class TracingSqsEventHandler
|
||||
extends TracingRequestHandler<SQSEvent, SQSBatchResponse> {
|
||||
static final String INSTRUMENTATION_NAME = "io.opentelemetry.aws-lambda-events-3.11";
|
||||
|
||||
private final Instrumenter<SQSEvent, Void> instrumenter;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TracingSqsEventHandler} which traces using the provided {@link
|
||||
* OpenTelemetrySdk} and has a timeout of 1s when flushing at the end of an invocation.
|
||||
*/
|
||||
protected TracingSqsEventHandler(OpenTelemetrySdk openTelemetrySdk) {
|
||||
this(openTelemetrySdk, DEFAULT_FLUSH_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TracingSqsEventHandler} which traces using the provided {@link
|
||||
* OpenTelemetrySdk} and has a timeout of {@code flushTimeout} when flushing at the end of an
|
||||
* invocation.
|
||||
*/
|
||||
protected TracingSqsEventHandler(OpenTelemetrySdk openTelemetrySdk, Duration flushTimeout) {
|
||||
this(
|
||||
openTelemetrySdk,
|
||||
flushTimeout,
|
||||
AwsLambdaSqsInstrumenterFactory.forEvent(openTelemetrySdk, INSTRUMENTATION_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TracingSqsEventHandler} which flushes the provided {@link
|
||||
* OpenTelemetrySdk}, has a timeout of {@code flushTimeout} when flushing at the end of an
|
||||
* invocation, and traces using the provided {@link
|
||||
* io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.AwsLambdaFunctionInstrumenter}.
|
||||
*/
|
||||
protected TracingSqsEventHandler(
|
||||
OpenTelemetrySdk openTelemetrySdk,
|
||||
Duration flushTimeout,
|
||||
Instrumenter<SQSEvent, Void> instrumenter) {
|
||||
super(openTelemetrySdk, flushTimeout);
|
||||
this.instrumenter = instrumenter;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public SQSBatchResponse doHandleRequest(SQSEvent event, Context context) {
|
||||
io.opentelemetry.context.Context parentContext = io.opentelemetry.context.Context.current();
|
||||
if (instrumenter.shouldStart(parentContext, event)) {
|
||||
io.opentelemetry.context.Context otelContext = instrumenter.start(parentContext, event);
|
||||
Throwable error = null;
|
||||
try (Scope ignored = otelContext.makeCurrent()) {
|
||||
return handleEvent(event, context);
|
||||
} catch (Throwable t) {
|
||||
error = t;
|
||||
throw t;
|
||||
} finally {
|
||||
instrumenter.end(otelContext, event, null, error);
|
||||
}
|
||||
} else {
|
||||
return handleEvent(event, context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a {@linkplain SQSEvent batch of messages}. Implement this class to do the actual
|
||||
* processing of incoming SQS messages.
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract SQSBatchResponse handleEvent(SQSEvent event, Context context);
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSBatchResponse;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrapperConfiguration;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.LambdaParameters;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class TracingSqsEventWrapper extends TracingSqsEventHandler {
|
||||
|
||||
private final WrappedLambda wrappedLambda;
|
||||
private final Method targetMethod;
|
||||
|
||||
public TracingSqsEventWrapper() {
|
||||
this(
|
||||
AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(),
|
||||
WrappedLambda.fromConfiguration());
|
||||
}
|
||||
|
||||
// Visible for testing
|
||||
TracingSqsEventWrapper(OpenTelemetrySdk openTelemetrySdk, WrappedLambda wrappedLambda) {
|
||||
super(openTelemetrySdk, WrapperConfiguration.flushTimeout());
|
||||
this.wrappedLambda = wrappedLambda;
|
||||
this.targetMethod = wrappedLambda.getRequestTargetMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQSBatchResponse handleEvent(SQSEvent sqsEvent, Context context) {
|
||||
Object[] parameters =
|
||||
LambdaParameters.toArray(targetMethod, sqsEvent, context, (event, clazz) -> event);
|
||||
try {
|
||||
Object result = targetMethod.invoke(wrappedLambda.getTargetObject(), parameters);
|
||||
return result instanceof SQSBatchResponse ? (SQSBatchResponse) result : null;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Method is inaccessible", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw (e.getCause() instanceof RuntimeException
|
||||
? (RuntimeException) e.getCause()
|
||||
: new IllegalStateException(e.getTargetException()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSBatchResponse;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.AwsLambdaSqsInstrumenterFactory;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class TracingSqsMessageHandler extends TracingSqsEventHandler {
|
||||
|
||||
private final Instrumenter<SQSMessage, Void> messageInstrumenter;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TracingSqsMessageHandler} which traces using the provided {@link
|
||||
* OpenTelemetrySdk} and has a timeout of 1s when flushing at the end of an invocation.
|
||||
*/
|
||||
protected TracingSqsMessageHandler(OpenTelemetrySdk openTelemetrySdk) {
|
||||
this(openTelemetrySdk, DEFAULT_FLUSH_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TracingSqsMessageHandler} which traces using the provided {@link
|
||||
* OpenTelemetrySdk} and has a timeout of {@code flushTimeout} when flushing at the end of an
|
||||
* invocation.
|
||||
*/
|
||||
protected TracingSqsMessageHandler(OpenTelemetrySdk openTelemetrySdk, Duration flushTimeout) {
|
||||
this(
|
||||
openTelemetrySdk,
|
||||
flushTimeout,
|
||||
AwsLambdaSqsInstrumenterFactory.forEvent(openTelemetrySdk, INSTRUMENTATION_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TracingSqsMessageHandler} which flushes the provided {@link
|
||||
* OpenTelemetrySdk}, has a timeout of {@code flushTimeout} when flushing at the end of an
|
||||
* invocation, and instruments {@link SQSEvent} using the provided {@code Instrumenter<SQSEvent,
|
||||
* Void>}.
|
||||
*/
|
||||
protected TracingSqsMessageHandler(
|
||||
OpenTelemetrySdk openTelemetrySdk,
|
||||
Duration flushTimeout,
|
||||
Instrumenter<SQSEvent, Void> eventInstrumenter) {
|
||||
this(
|
||||
openTelemetrySdk,
|
||||
flushTimeout,
|
||||
eventInstrumenter,
|
||||
AwsLambdaSqsInstrumenterFactory.forMessage(openTelemetrySdk, INSTRUMENTATION_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TracingSqsMessageHandler} which flushes the provided {@link
|
||||
* OpenTelemetrySdk}, has a timeout of {@code flushTimeout} when flushing at the end of an
|
||||
* invocation, and traces using the provided {@code Instrumenter<SQSEvent, Void>} and {@code
|
||||
* Instrumenter<SQSMessage, Void>}.
|
||||
*/
|
||||
protected TracingSqsMessageHandler(
|
||||
OpenTelemetrySdk openTelemetrySdk,
|
||||
Duration flushTimeout,
|
||||
Instrumenter<SQSEvent, Void> eventInstrumenter,
|
||||
Instrumenter<SQSMessage, Void> messageInstrumenter) {
|
||||
super(openTelemetrySdk, flushTimeout, eventInstrumenter);
|
||||
this.messageInstrumenter = messageInstrumenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final SQSBatchResponse handleEvent(SQSEvent event, Context context) {
|
||||
List<SQSBatchResponse.BatchItemFailure> batchItemFailures = new ArrayList<>();
|
||||
io.opentelemetry.context.Context parentContext = io.opentelemetry.context.Context.current();
|
||||
for (SQSMessage message : event.getRecords()) {
|
||||
if (messageInstrumenter.shouldStart(parentContext, message)) {
|
||||
io.opentelemetry.context.Context otelContext =
|
||||
messageInstrumenter.start(parentContext, message);
|
||||
Throwable error = null;
|
||||
try (Scope ignored = otelContext.makeCurrent()) {
|
||||
handleMessage(message, context, batchItemFailures);
|
||||
} catch (Throwable t) {
|
||||
error = t;
|
||||
throw t;
|
||||
} finally {
|
||||
messageInstrumenter.end(otelContext, message, null, error);
|
||||
}
|
||||
} else {
|
||||
handleMessage(message, context, batchItemFailures);
|
||||
}
|
||||
}
|
||||
|
||||
return new SQSBatchResponse(batchItemFailures);
|
||||
}
|
||||
|
||||
private void handleMessage(
|
||||
SQSMessage message,
|
||||
Context context,
|
||||
List<SQSBatchResponse.BatchItemFailure> batchItemFailures) {
|
||||
if (!handleMessage(message, context)) {
|
||||
batchItemFailures.add(new SQSBatchResponse.BatchItemFailure(message.getMessageId()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a {@linkplain SQSMessage message}. Implement this class to do the actual processing of
|
||||
* incoming SQS messages.
|
||||
*
|
||||
* @return {@code true} when message was processed successfully, {@code false} when it should be
|
||||
* reported as a failed batch item.
|
||||
*/
|
||||
protected abstract boolean handleMessage(SQSMessage message, Context context);
|
||||
}
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||
import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD;
|
||||
import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE;
|
||||
import static io.opentelemetry.semconv.UrlAttributes.URL_FULL;
|
||||
import static io.opentelemetry.semconv.UserAgentAttributes.USER_AGENT_ORIGINAL;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.RequestHandler;
|
||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
|
||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||
import io.opentelemetry.semconv.incubating.CloudIncubatingAttributes;
|
||||
import io.opentelemetry.semconv.incubating.FaasIncubatingAttributes;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junitpioneer.jupiter.SetEnvironmentVariable;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class AwsLambdaApiGatewayWrapperTest {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
|
||||
|
||||
@Mock private Context context;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
when(context.getFunctionName()).thenReturn("my_function");
|
||||
when(context.getAwsRequestId()).thenReturn("1-22-333");
|
||||
when(context.getInvokedFunctionArn())
|
||||
.thenReturn("arn:aws:lambda:us-east-1:123456789:function:test");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
assertThat(testing.forceFlushCalled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SetEnvironmentVariable(
|
||||
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||
value =
|
||||
"io.opentelemetry.instrumentation.awslambdaevents.v3_11.AwsLambdaApiGatewayWrapperTest$TestRequestHandlerApiGateway::handleRequest")
|
||||
void tracedWithHttpPropagation() {
|
||||
TracingRequestApiGatewayWrapper wrapper =
|
||||
new TracingRequestApiGatewayWrapper(
|
||||
testing.getOpenTelemetrySdk(),
|
||||
WrappedLambda.fromConfiguration(),
|
||||
TracingRequestApiGatewayWrapper::map);
|
||||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("traceparent", "00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01");
|
||||
headers.put("User-Agent", "Test Client");
|
||||
headers.put("host", "localhost:123");
|
||||
headers.put("X-FORWARDED-PROTO", "http");
|
||||
Map<String, String> query = new HashMap<>();
|
||||
query.put("a", "b");
|
||||
query.put("c", "d");
|
||||
APIGatewayProxyRequestEvent input =
|
||||
new APIGatewayProxyRequestEvent()
|
||||
.withHttpMethod("GET")
|
||||
.withResource("/hello/{param}")
|
||||
.withPath("/hello/world")
|
||||
.withBody("hello")
|
||||
.withQueryStringParameters(query)
|
||||
.withHeaders(headers);
|
||||
|
||||
APIGatewayProxyResponseEvent result =
|
||||
(APIGatewayProxyResponseEvent) wrapper.handleRequest(input, context);
|
||||
|
||||
assertThat(result.getBody()).isEqualTo("world");
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("GET /hello/{param}")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasTraceId("4fd0b6131f19f39af59518d127b0cafe")
|
||||
.hasParentSpanId("0000000000000456")
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
CloudIncubatingAttributes.CLOUD_RESOURCE_ID,
|
||||
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||
equalTo(CloudIncubatingAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_INVOCATION_ID, "1-22-333"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_TRIGGER, "http"),
|
||||
equalTo(HTTP_REQUEST_METHOD, "GET"),
|
||||
equalTo(USER_AGENT_ORIGINAL, "Test Client"),
|
||||
equalTo(URL_FULL, "http://localhost:123/hello/world?a=b&c=d"),
|
||||
equalTo(HTTP_RESPONSE_STATUS_CODE, 200L))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SetEnvironmentVariable(
|
||||
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||
value =
|
||||
"io.opentelemetry.instrumentation.awslambdaevents.v3_11.AwsLambdaApiGatewayWrapperTest$TestRequestHandlerApiGateway::handleRequest")
|
||||
void handlerTraced_empty() {
|
||||
TracingRequestApiGatewayWrapper wrapper =
|
||||
new TracingRequestApiGatewayWrapper(
|
||||
testing.getOpenTelemetrySdk(),
|
||||
WrappedLambda.fromConfiguration(),
|
||||
TracingRequestApiGatewayWrapper::map);
|
||||
APIGatewayProxyResponseEvent result =
|
||||
(APIGatewayProxyResponseEvent)
|
||||
wrapper.handleRequest(new APIGatewayProxyRequestEvent().withBody("empty"), context);
|
||||
|
||||
assertThat(result.getBody()).isNull();
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("my_function")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
CloudIncubatingAttributes.CLOUD_RESOURCE_ID,
|
||||
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||
equalTo(CloudIncubatingAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_INVOCATION_ID, "1-22-333"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_TRIGGER, "http"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SetEnvironmentVariable(
|
||||
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||
value =
|
||||
"io.opentelemetry.instrumentation.awslambdaevents.v3_11.AwsLambdaApiGatewayWrapperTest$TestRequestHandlerString::handleRequest")
|
||||
void handlerTraced_string() {
|
||||
TracingRequestApiGatewayWrapper wrapper =
|
||||
new TracingRequestApiGatewayWrapper(
|
||||
testing.getOpenTelemetrySdk(),
|
||||
WrappedLambda.fromConfiguration(),
|
||||
TracingRequestApiGatewayWrapper::map);
|
||||
APIGatewayProxyResponseEvent result =
|
||||
(APIGatewayProxyResponseEvent)
|
||||
wrapper.handleRequest(new APIGatewayProxyRequestEvent().withBody("\"hello\""), context);
|
||||
|
||||
assertThat(result.getBody()).isEqualTo("\"world\"");
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("my_function")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
CloudIncubatingAttributes.CLOUD_RESOURCE_ID,
|
||||
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||
equalTo(CloudIncubatingAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_INVOCATION_ID, "1-22-333"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_TRIGGER, "http"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SetEnvironmentVariable(
|
||||
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||
value =
|
||||
"io.opentelemetry.instrumentation.awslambdaevents.v3_11.AwsLambdaApiGatewayWrapperTest$TestRequestHandlerInteger::handleRequest")
|
||||
void handlerTraced_integer() {
|
||||
TracingRequestApiGatewayWrapper wrapper =
|
||||
new TracingRequestApiGatewayWrapper(
|
||||
testing.getOpenTelemetrySdk(),
|
||||
WrappedLambda.fromConfiguration(),
|
||||
TracingRequestApiGatewayWrapper::map);
|
||||
APIGatewayProxyResponseEvent result =
|
||||
(APIGatewayProxyResponseEvent)
|
||||
wrapper.handleRequest(new APIGatewayProxyRequestEvent().withBody("1"), context);
|
||||
|
||||
assertThat(result.getBody()).isEqualTo("\"world\"");
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("my_function")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
CloudIncubatingAttributes.CLOUD_RESOURCE_ID,
|
||||
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||
equalTo(CloudIncubatingAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_INVOCATION_ID, "1-22-333"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_TRIGGER, "http"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SetEnvironmentVariable(
|
||||
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||
value =
|
||||
"io.opentelemetry.instrumentation.awslambdaevents.v3_11.AwsLambdaApiGatewayWrapperTest$TestRequestHandlerCustomType::handleRequest")
|
||||
void handlerTraced_customType() {
|
||||
TracingRequestApiGatewayWrapper wrapper =
|
||||
new TracingRequestApiGatewayWrapper(
|
||||
testing.getOpenTelemetrySdk(),
|
||||
WrappedLambda.fromConfiguration(),
|
||||
TracingRequestApiGatewayWrapper::map);
|
||||
APIGatewayProxyResponseEvent result =
|
||||
(APIGatewayProxyResponseEvent)
|
||||
wrapper.handleRequest(
|
||||
new APIGatewayProxyRequestEvent()
|
||||
.withBody("{\"key\":\"hello\", \"value\":\"General Kenobi\"}"),
|
||||
context);
|
||||
|
||||
assertThat(result.getBody()).isEqualTo("\"General Kenobi\"");
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("my_function")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
CloudIncubatingAttributes.CLOUD_RESOURCE_ID,
|
||||
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||
equalTo(CloudIncubatingAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_INVOCATION_ID, "1-22-333"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_TRIGGER, "http"))));
|
||||
}
|
||||
|
||||
public static class TestRequestHandlerApiGateway
|
||||
implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
|
||||
|
||||
@Override
|
||||
public APIGatewayProxyResponseEvent handleRequest(
|
||||
APIGatewayProxyRequestEvent input, Context context) {
|
||||
if (input.getBody().equals("hello")) {
|
||||
return new APIGatewayProxyResponseEvent().withStatusCode(200).withBody("world");
|
||||
} else if (input.getBody().equals("empty")) {
|
||||
return new APIGatewayProxyResponseEvent();
|
||||
}
|
||||
throw new IllegalStateException("bad request");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TestRequestHandlerString implements RequestHandler<String, String> {
|
||||
|
||||
@Override
|
||||
public String handleRequest(String input, Context context) {
|
||||
if (input.equals("hello")) {
|
||||
return "world";
|
||||
}
|
||||
throw new IllegalArgumentException("bad argument");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TestRequestHandlerInteger implements RequestHandler<Integer, String> {
|
||||
|
||||
@Override
|
||||
public String handleRequest(Integer input, Context context) {
|
||||
if (input == 1) {
|
||||
return "world";
|
||||
}
|
||||
throw new IllegalArgumentException("bad argument");
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomType {
|
||||
public String key;
|
||||
public String value;
|
||||
}
|
||||
|
||||
public static final class TestRequestHandlerCustomType
|
||||
implements RequestHandler<CustomType, String> {
|
||||
|
||||
@Override
|
||||
public String handleRequest(CustomType input, Context context) {
|
||||
if (input.key.equals("hello")) {
|
||||
return input.value;
|
||||
}
|
||||
throw new IllegalArgumentException("bad argument");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.RequestHandler;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSBatchResponse;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.AbstractAwsLambdaSqsEventHandlerTest;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
class AwsLambdaSqsEventHandlerTest extends AbstractAwsLambdaSqsEventHandlerTest {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
|
||||
|
||||
@Override
|
||||
protected RequestHandler<SQSEvent, SQSBatchResponse> handler() {
|
||||
return new TestHandler(testing.getOpenTelemetrySdk());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstrumentationExtension testing() {
|
||||
return testing;
|
||||
}
|
||||
|
||||
private static final class TestHandler extends TracingSqsEventHandler {
|
||||
|
||||
TestHandler(OpenTelemetrySdk openTelemetrySdk) {
|
||||
super(openTelemetrySdk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQSBatchResponse handleEvent(SQSEvent event, Context context) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION;
|
||||
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_SYSTEM;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.RequestHandler;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSBatchResponse;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||
import io.opentelemetry.semconv.incubating.CloudIncubatingAttributes;
|
||||
import io.opentelemetry.semconv.incubating.FaasIncubatingAttributes;
|
||||
import io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Collections;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junitpioneer.jupiter.SetEnvironmentVariable;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@SetEnvironmentVariable(
|
||||
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||
value =
|
||||
"io.opentelemetry.instrumentation.awslambdaevents.v3_11.AwsLambdaSqsEventWrapperTest$TestRequestHandler::handleRequest")
|
||||
class AwsLambdaSqsEventWrapperTest {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
|
||||
|
||||
@Mock private Context context;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
when(context.getFunctionName()).thenReturn("my_function");
|
||||
when(context.getAwsRequestId()).thenReturn("1-22-333");
|
||||
when(context.getInvokedFunctionArn())
|
||||
.thenReturn("arn:aws:lambda:us-east-1:123456789:function:test");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
assertThat(testing.forceFlushCalled()).isTrue();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // using deprecated semconv
|
||||
@Test
|
||||
void eventTraced() {
|
||||
SQSEvent event = new SQSEvent();
|
||||
SQSEvent.SQSMessage record = newMessage();
|
||||
record.setEventSource("otel");
|
||||
record.setAttributes(Collections.emptyMap());
|
||||
event.setRecords(Collections.singletonList(record));
|
||||
|
||||
TracingSqsEventWrapper wrapper =
|
||||
new TracingSqsEventWrapper(
|
||||
testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
|
||||
wrapper.handleRequest(event, context);
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("my_function")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
CloudIncubatingAttributes.CLOUD_RESOURCE_ID,
|
||||
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||
equalTo(CloudIncubatingAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_INVOCATION_ID, "1-22-333")),
|
||||
span ->
|
||||
span.hasName("otel process")
|
||||
.hasKind(SpanKind.CONSUMER)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
MESSAGING_SYSTEM,
|
||||
MessagingIncubatingAttributes.MessagingSystemIncubatingValues
|
||||
.AWS_SQS),
|
||||
equalTo(MESSAGING_OPERATION, "process"))));
|
||||
}
|
||||
|
||||
public static final class TestRequestHandler
|
||||
implements RequestHandler<SQSEvent, SQSBatchResponse> {
|
||||
@Override
|
||||
public SQSBatchResponse handleRequest(SQSEvent input, Context context) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor private in early versions.
|
||||
private static SQSEvent.SQSMessage newMessage() {
|
||||
try {
|
||||
Constructor<SQSEvent.SQSMessage> ctor = SQSEvent.SQSMessage.class.getDeclaredConstructor();
|
||||
return ctor.newInstance();
|
||||
} catch (Throwable t) {
|
||||
throw new AssertionError(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME;
|
||||
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID;
|
||||
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION;
|
||||
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_SYSTEM;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSBatchResponse;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import io.opentelemetry.api.trace.SpanContext;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.TraceFlags;
|
||||
import io.opentelemetry.api.trace.TraceState;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.trace.data.LinkData;
|
||||
import io.opentelemetry.semconv.incubating.FaasIncubatingAttributes;
|
||||
import io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AwsLambdaSqsMessageHandlerTest {
|
||||
|
||||
private static final String AWS_TRACE_HEADER1 =
|
||||
"Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1";
|
||||
private static final String AWS_TRACE_HEADER2 =
|
||||
"Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad9;Sampled=1";
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
|
||||
|
||||
@Mock private Context context;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
when(context.getFunctionName()).thenReturn("my_function");
|
||||
when(context.getAwsRequestId()).thenReturn("1-22-333");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
assertThat(testing.forceFlushCalled()).isTrue();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // using deprecated semconv
|
||||
@Test
|
||||
void processSpans() {
|
||||
SQSEvent.SQSMessage message1 = newMessage();
|
||||
message1.setAttributes(Collections.singletonMap("AWSTraceHeader", AWS_TRACE_HEADER1));
|
||||
message1.setMessageId("message1");
|
||||
message1.setEventSource("queue1");
|
||||
|
||||
SQSEvent.SQSMessage message2 = newMessage();
|
||||
message2.setAttributes(Collections.singletonMap("AWSTraceHeader", AWS_TRACE_HEADER2));
|
||||
message2.setMessageId("message2");
|
||||
message2.setEventSource("queue1");
|
||||
|
||||
SQSEvent event = new SQSEvent();
|
||||
event.setRecords(Arrays.asList(message1, message2));
|
||||
|
||||
SQSBatchResponse response =
|
||||
new TestHandler(testing.getOpenTelemetrySdk()).handleRequest(event, context);
|
||||
assertThat(response.getBatchItemFailures())
|
||||
.satisfiesExactly(item -> assertThat(item.getItemIdentifier()).isEqualTo("message2"));
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("my_function")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(FaasIncubatingAttributes.FAAS_INVOCATION_ID, "1-22-333")),
|
||||
span ->
|
||||
span.hasName("queue1 process")
|
||||
.hasKind(SpanKind.CONSUMER)
|
||||
.hasParentSpanId(trace.getSpan(0).getSpanId())
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
MESSAGING_SYSTEM,
|
||||
MessagingIncubatingAttributes.MessagingSystemIncubatingValues
|
||||
.AWS_SQS),
|
||||
equalTo(MESSAGING_OPERATION, "process"))
|
||||
.hasLinks(
|
||||
LinkData.create(
|
||||
SpanContext.createFromRemoteParent(
|
||||
"5759e988bd862e3fe1be46a994272793",
|
||||
"53995c3f42cd8ad8",
|
||||
TraceFlags.getSampled(),
|
||||
TraceState.getDefault())),
|
||||
LinkData.create(
|
||||
SpanContext.createFromRemoteParent(
|
||||
"5759e988bd862e3fe1be46a994272793",
|
||||
"53995c3f42cd8ad9",
|
||||
TraceFlags.getSampled(),
|
||||
TraceState.getDefault()))),
|
||||
span ->
|
||||
span.hasName("queue1 process")
|
||||
.hasKind(SpanKind.CONSUMER)
|
||||
.hasParentSpanId(trace.getSpan(1).getSpanId())
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
MESSAGING_SYSTEM,
|
||||
MessagingIncubatingAttributes.MessagingSystemIncubatingValues
|
||||
.AWS_SQS),
|
||||
equalTo(MESSAGING_OPERATION, "process"),
|
||||
equalTo(MESSAGING_MESSAGE_ID, "message1"),
|
||||
equalTo(MESSAGING_DESTINATION_NAME, "queue1"))
|
||||
.hasLinks(
|
||||
LinkData.create(
|
||||
SpanContext.createFromRemoteParent(
|
||||
"5759e988bd862e3fe1be46a994272793",
|
||||
"53995c3f42cd8ad8",
|
||||
TraceFlags.getSampled(),
|
||||
TraceState.getDefault()))),
|
||||
span ->
|
||||
span.hasName("queue1 process")
|
||||
.hasKind(SpanKind.CONSUMER)
|
||||
.hasParentSpanId(trace.getSpan(1).getSpanId())
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
MESSAGING_SYSTEM,
|
||||
MessagingIncubatingAttributes.MessagingSystemIncubatingValues
|
||||
.AWS_SQS),
|
||||
equalTo(MESSAGING_OPERATION, "process"),
|
||||
equalTo(MESSAGING_MESSAGE_ID, "message2"),
|
||||
equalTo(MESSAGING_DESTINATION_NAME, "queue1"))
|
||||
.hasLinks(
|
||||
LinkData.create(
|
||||
SpanContext.createFromRemoteParent(
|
||||
"5759e988bd862e3fe1be46a994272793",
|
||||
"53995c3f42cd8ad9",
|
||||
TraceFlags.getSampled(),
|
||||
TraceState.getDefault())))));
|
||||
}
|
||||
|
||||
// Constructor private in early versions.
|
||||
private static SQSEvent.SQSMessage newMessage() {
|
||||
try {
|
||||
Constructor<SQSEvent.SQSMessage> ctor = SQSEvent.SQSMessage.class.getDeclaredConstructor();
|
||||
return ctor.newInstance();
|
||||
} catch (Throwable t) {
|
||||
throw new AssertionError(t);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TestHandler extends TracingSqsMessageHandler {
|
||||
|
||||
TestHandler(OpenTelemetrySdk openTelemetrySdk) {
|
||||
super(openTelemetrySdk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handleMessage(SQSEvent.SQSMessage message, Context context) {
|
||||
return "message1".equals(message.getMessageId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.RequestHandler;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||
import io.opentelemetry.semconv.incubating.CloudIncubatingAttributes;
|
||||
import io.opentelemetry.semconv.incubating.FaasIncubatingAttributes;
|
||||
import java.io.IOException;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junitpioneer.jupiter.SetEnvironmentVariable;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AwsLambdaWrapperTest {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
|
||||
|
||||
@Mock private Context context;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
when(context.getFunctionName()).thenReturn("my_function");
|
||||
when(context.getAwsRequestId()).thenReturn("1-22-333");
|
||||
when(context.getInvokedFunctionArn())
|
||||
.thenReturn("arn:aws:lambda:us-east-1:123456789:function:test");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
assertThat(testing.forceFlushCalled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SetEnvironmentVariable(
|
||||
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||
value =
|
||||
"io.opentelemetry.instrumentation.awslambdaevents.v3_11.AwsLambdaWrapperTest$TestRequestHandlerString::handleRequest")
|
||||
void handlerTraced() throws IOException {
|
||||
TracingRequestWrapper wrapper =
|
||||
new TracingRequestWrapper(testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
|
||||
Object result = wrapper.handleRequest("hello", context);
|
||||
|
||||
assertThat(result).isEqualTo("world");
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("my_function")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
CloudIncubatingAttributes.CLOUD_RESOURCE_ID,
|
||||
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||
equalTo(CloudIncubatingAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_INVOCATION_ID, "1-22-333"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SetEnvironmentVariable(
|
||||
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||
value =
|
||||
"io.opentelemetry.instrumentation.awslambdaevents.v3_11.AwsLambdaWrapperTest$TestRequestHandlerString::handleRequest")
|
||||
void handlerTracedWithException() {
|
||||
TracingRequestWrapper wrapper =
|
||||
new TracingRequestWrapper(testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
|
||||
Throwable thrown = catchThrowable(() -> wrapper.handleRequest("goodbye", context));
|
||||
|
||||
assertThat(thrown).isInstanceOf(IllegalArgumentException.class);
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("my_function")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasStatus(StatusData.error())
|
||||
.hasException(thrown)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
CloudIncubatingAttributes.CLOUD_RESOURCE_ID,
|
||||
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||
equalTo(CloudIncubatingAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_INVOCATION_ID, "1-22-333"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SetEnvironmentVariable(
|
||||
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||
value =
|
||||
"io.opentelemetry.instrumentation.awslambdaevents.v3_11.AwsLambdaWrapperTest$TestRequestHandlerInteger::handleRequest")
|
||||
void handlerTraced_integer() throws IOException {
|
||||
TracingRequestWrapper wrapper =
|
||||
new TracingRequestWrapper(testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
|
||||
Object result = wrapper.handleRequest(1, context);
|
||||
|
||||
assertThat(result).isEqualTo("world");
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("my_function")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
CloudIncubatingAttributes.CLOUD_RESOURCE_ID,
|
||||
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||
equalTo(CloudIncubatingAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_INVOCATION_ID, "1-22-333"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SetEnvironmentVariable(
|
||||
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||
value =
|
||||
"io.opentelemetry.instrumentation.awslambdaevents.v3_11.AwsLambdaWrapperTest$TestRequestHandlerCustomType::handleRequest")
|
||||
void handlerTraced_custom() throws IOException {
|
||||
TracingRequestWrapper wrapper =
|
||||
new TracingRequestWrapper(testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
|
||||
CustomType ct = new CustomType();
|
||||
ct.key = "hello there";
|
||||
ct.value = "General Kenobi";
|
||||
Object result = wrapper.handleRequest(ct, context);
|
||||
|
||||
assertThat(result).isEqualTo("General Kenobi");
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("my_function")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
equalTo(
|
||||
CloudIncubatingAttributes.CLOUD_RESOURCE_ID,
|
||||
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||
equalTo(CloudIncubatingAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||
equalTo(FaasIncubatingAttributes.FAAS_INVOCATION_ID, "1-22-333"))));
|
||||
}
|
||||
|
||||
public static final class TestRequestHandlerString implements RequestHandler<String, String> {
|
||||
|
||||
@Override
|
||||
public String handleRequest(String input, Context context) {
|
||||
if (input.equals("hello")) {
|
||||
return "world";
|
||||
}
|
||||
throw new IllegalArgumentException("bad argument");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TestRequestHandlerInteger implements RequestHandler<Integer, String> {
|
||||
|
||||
@Override
|
||||
public String handleRequest(Integer input, Context context) {
|
||||
if (input == 1) {
|
||||
return "world";
|
||||
}
|
||||
throw new IllegalArgumentException("bad argument");
|
||||
}
|
||||
}
|
||||
|
||||
static class CustomType {
|
||||
String key;
|
||||
String value;
|
||||
|
||||
// Need getter/setter of all the attributes for serialization/deserialization
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TestRequestHandlerCustomType
|
||||
implements RequestHandler<CustomType, String> {
|
||||
|
||||
@Override
|
||||
public String handleRequest(CustomType input, Context context) {
|
||||
if (input.key.equals("hello there")) {
|
||||
return input.value;
|
||||
}
|
||||
throw new IllegalArgumentException("bad argument");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v3_11;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.RequestHandler;
|
||||
import com.amazonaws.services.lambda.runtime.events.KinesisEvent;
|
||||
import com.amazonaws.services.lambda.runtime.events.S3Event;
|
||||
import com.amazonaws.services.lambda.runtime.events.SNSEvent;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import com.amazonaws.services.lambda.runtime.events.ScheduledEvent;
|
||||
import io.opentelemetry.instrumentation.awslambdacore.v1_0.internal.WrappedLambda;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal.SerializationUtil;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
class TracingRequestWrapperStandardEventsTest {
|
||||
private static final Map<Class<?>, EventInfo> EVENTS_JSON = buildEventExamples();
|
||||
|
||||
private final OpenTelemetrySdk sdk = OpenTelemetrySdk.builder().build();
|
||||
private final Context context = mock(Context.class);
|
||||
private TracingRequestWrapper wrapper;
|
||||
|
||||
static final class EventInfo {
|
||||
final Class<?> eventType;
|
||||
final String eventBody;
|
||||
|
||||
EventInfo(Class<?> eventType, String eventBody) {
|
||||
this.eventType = eventType;
|
||||
this.eventBody = eventBody;
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<Class<?>, EventInfo> buildEventExamples() {
|
||||
Map<Class<?>, EventInfo> events = new HashMap<>();
|
||||
events.put(
|
||||
ScheduledEventRequestHandler.class,
|
||||
new EventInfo(
|
||||
ScheduledEvent.class,
|
||||
"{\n"
|
||||
+ " \"version\": \"0\",\n"
|
||||
+ " \"id\": \"53dc4d37-cffa-4f76-80c9-8b7d4a4d2eaa\",\n"
|
||||
+ " \"detail-type\": \"Scheduled Event\",\n"
|
||||
+ " \"source\": \"aws.events\",\n"
|
||||
+ " \"account\": \"123456789012\",\n"
|
||||
+ " \"time\": \"2015-10-08T16:53:06Z\",\n"
|
||||
+ " \"region\": \"us-east-1\",\n"
|
||||
+ " \"resources\": [\n"
|
||||
+ " \"arn:aws:events:us-east-1:123456789012:rule/my-scheduled-rule\"\n"
|
||||
+ " ],\n"
|
||||
+ " \"detail\": {}\n"
|
||||
+ "}"));
|
||||
events.put(
|
||||
KinesisEventRequestHandler.class,
|
||||
new EventInfo(
|
||||
KinesisEvent.class,
|
||||
"{\n"
|
||||
+ " \"Records\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"kinesis\": {\n"
|
||||
+ " \"kinesisSchemaVersion\": \"1.0\",\n"
|
||||
+ " \"partitionKey\": \"1\",\n"
|
||||
+ " \"sequenceNumber\": \"49590338271490256608559692538361571095921575989136588898\",\n"
|
||||
+ " \"data\": \"SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==\",\n"
|
||||
+ " \"approximateArrivalTimestamp\": 1545084650.987\n"
|
||||
+ " },\n"
|
||||
+ " \"eventSource\": \"aws:kinesis\",\n"
|
||||
+ " \"eventVersion\": \"1.0\",\n"
|
||||
+ " \"eventID\": \"shardId-000000000006:49590338271490256608559692538361571095921575989136588898\",\n"
|
||||
+ " \"eventName\": \"aws:kinesis:record\",\n"
|
||||
+ " \"invokeIdentityArn\": \"arn:aws:iam::123456789012:role/lambda-role\",\n"
|
||||
+ " \"awsRegion\": \"us-east-2\",\n"
|
||||
+ " \"eventSourceARN\": \"arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream\"\n"
|
||||
+ " },\n"
|
||||
+ " {\n"
|
||||
+ " \"kinesis\": {\n"
|
||||
+ " \"kinesisSchemaVersion\": \"1.0\",\n"
|
||||
+ " \"partitionKey\": \"1\",\n"
|
||||
+ " \"sequenceNumber\": \"49590338271490256608559692540925702759324208523137515618\",\n"
|
||||
+ " \"data\": \"VGhpcyBpcyBvbmx5IGEgdGVzdC4=\",\n"
|
||||
+ " \"approximateArrivalTimestamp\": 1545084711.166\n"
|
||||
+ " },\n"
|
||||
+ " \"eventSource\": \"aws:kinesis\",\n"
|
||||
+ " \"eventVersion\": \"1.0\",\n"
|
||||
+ " \"eventID\": \"shardId-000000000006:49590338271490256608559692540925702759324208523137515618\",\n"
|
||||
+ " \"eventName\": \"aws:kinesis:record\",\n"
|
||||
+ " \"invokeIdentityArn\": \"arn:aws:iam::123456789012:role/lambda-role\",\n"
|
||||
+ " \"awsRegion\": \"us-east-2\",\n"
|
||||
+ " \"eventSourceARN\": \"arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream\"\n"
|
||||
+ " }\n"
|
||||
+ " ]\n"
|
||||
+ "}"));
|
||||
events.put(
|
||||
SqsEventRequestHandler.class,
|
||||
new EventInfo(
|
||||
SQSEvent.class,
|
||||
"{\n"
|
||||
+ " \"Records\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"messageId\": \"059f36b4-87a3-44ab-83d2-661975830a7d\",\n"
|
||||
+ " \"receiptHandle\": \"AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...\",\n"
|
||||
+ " \"body\": \"Test message.\",\n"
|
||||
+ " \"attributes\": {\n"
|
||||
+ " \"ApproximateReceiveCount\": \"1\",\n"
|
||||
+ " \"SentTimestamp\": \"1545082649183\",\n"
|
||||
+ " \"SenderId\": \"AIDAIENQZJOLO23YVJ4VO\",\n"
|
||||
+ " \"ApproximateFirstReceiveTimestamp\": \"1545082649185\"\n"
|
||||
+ " },\n"
|
||||
+ " \"messageAttributes\": {},\n"
|
||||
+ " \"md5OfBody\": \"e4e68fb7bd0e697a0ae8f1bb342846b3\",\n"
|
||||
+ " \"eventSource\": \"aws:sqs\",\n"
|
||||
+ " \"eventSourceARN\": \"arn:aws:sqs:us-east-2:123456789012:my-queue\",\n"
|
||||
+ " \"awsRegion\": \"us-east-2\"\n"
|
||||
+ " },\n"
|
||||
+ " {\n"
|
||||
+ " \"messageId\": \"2e1424d4-f796-459a-8184-9c92662be6da\",\n"
|
||||
+ " \"receiptHandle\": \"AQEBzWwaftRI0KuVm4tP+/7q1rGgNqicHq...\",\n"
|
||||
+ " \"body\": \"Test message.\",\n"
|
||||
+ " \"attributes\": {\n"
|
||||
+ " \"ApproximateReceiveCount\": \"1\",\n"
|
||||
+ " \"SentTimestamp\": \"1545082650636\",\n"
|
||||
+ " \"SenderId\": \"AIDAIENQZJOLO23YVJ4VO\",\n"
|
||||
+ " \"ApproximateFirstReceiveTimestamp\": \"1545082650649\"\n"
|
||||
+ " },\n"
|
||||
+ " \"messageAttributes\": {},\n"
|
||||
+ " \"md5OfBody\": \"e4e68fb7bd0e697a0ae8f1bb342846b3\",\n"
|
||||
+ " \"eventSource\": \"aws:sqs\",\n"
|
||||
+ " \"eventSourceARN\": \"arn:aws:sqs:us-east-2:123456789012:my-queue\",\n"
|
||||
+ " \"awsRegion\": \"us-east-2\"\n"
|
||||
+ " }\n"
|
||||
+ " ]\n"
|
||||
+ "}"));
|
||||
events.put(
|
||||
S3EventRequestHandler.class,
|
||||
new EventInfo(
|
||||
S3Event.class,
|
||||
"{\n"
|
||||
+ " \"Records\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"eventVersion\": \"2.1\",\n"
|
||||
+ " \"eventSource\": \"aws:s3\",\n"
|
||||
+ " \"awsRegion\": \"us-east-2\",\n"
|
||||
+ " \"eventTime\": \"2019-09-03T19:37:27.192Z\",\n"
|
||||
+ " \"eventName\": \"ObjectCreated:Put\",\n"
|
||||
+ " \"userIdentity\": {\n"
|
||||
+ " \"principalId\": \"AWS:AIDAINPONIXQXHT3IKHL2\"\n"
|
||||
+ " },\n"
|
||||
+ " \"requestParameters\": {\n"
|
||||
+ " \"sourceIPAddress\": \"205.255.255.255\"\n"
|
||||
+ " },\n"
|
||||
+ " \"responseElements\": {\n"
|
||||
+ " \"x-amz-request-id\": \"D82B88E5F771F645\",\n"
|
||||
+ " \"x-amz-id-2\": \"vlR7PnpV2Ce81l0PRw6jlUpck7Jo5ZsQjryTjKlc5aLWGVHPZLj5NeC6qMa0emYBDXOo6QBU0Wo=\"\n"
|
||||
+ " },\n"
|
||||
+ " \"s3\": {\n"
|
||||
+ " \"s3SchemaVersion\": \"1.0\",\n"
|
||||
+ " \"configurationId\": \"828aa6fc-f7b5-4305-8584-487c791949c1\",\n"
|
||||
+ " \"bucket\": {\n"
|
||||
+ " \"name\": \"DOC-EXAMPLE-BUCKET\",\n"
|
||||
+ " \"ownerIdentity\": {\n"
|
||||
+ " \"principalId\": \"A3I5XTEXAMAI3E\"\n"
|
||||
+ " },\n"
|
||||
+ " \"arn\": \"arn:aws:s3:::lambda-artifacts-deafc19498e3f2df\"\n"
|
||||
+ " },\n"
|
||||
+ " \"object\": {\n"
|
||||
+ " \"key\": \"b21b84d653bb07b05b1e6b33684dc11b\",\n"
|
||||
+ " \"size\": 1305107,\n"
|
||||
+ " \"eTag\": \"b21b84d653bb07b05b1e6b33684dc11b\",\n"
|
||||
+ " \"sequencer\": \"0C0F6F405D6ED209E1\"\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ " ]\n"
|
||||
+ "}"));
|
||||
events.put(
|
||||
SnsEventRequestHandler.class,
|
||||
new EventInfo(
|
||||
SNSEvent.class,
|
||||
"{\n"
|
||||
+ " \"Records\": [\n"
|
||||
+ " {\n"
|
||||
+ " \"EventVersion\": \"1.0\",\n"
|
||||
+ " \"EventSubscriptionArn\": \"arn:aws:sns:us-east-2:123456789012:sns-lambda:21be56ed-a058-49f5-8c98-aedd2564c486\",\n"
|
||||
+ " \"EventSource\": \"aws:sns\",\n"
|
||||
+ " \"Sns\": {\n"
|
||||
+ " \"SignatureVersion\": \"1\",\n"
|
||||
+ " \"Timestamp\": \"2019-01-02T12:45:07.000Z\",\n"
|
||||
+ " \"Signature\": \"tcc6faL2yUC6dgZdmrwh1Y4cGa/ebXEkAi6RibDsvpi+tE/1+82j...65r==\",\n"
|
||||
+ " \"SigningCertUrl\": \"https://sns.us-east-2.amazonaws.com/SimpleNotificationService-ac565b8b1a6c5d002d285f9598aa1d9b.pem\",\n"
|
||||
+ " \"MessageId\": \"95df01b4-ee98-5cb9-9903-4c221d41eb5e\",\n"
|
||||
+ " \"Message\": \"Hello from SNS!\",\n"
|
||||
+ " \"MessageAttributes\": {\n"
|
||||
+ " \"Test\": {\n"
|
||||
+ " \"Type\": \"String\",\n"
|
||||
+ " \"Value\": \"TestString\"\n"
|
||||
+ " },\n"
|
||||
+ " \"TestBinary\": {\n"
|
||||
+ " \"Type\": \"Binary\",\n"
|
||||
+ " \"Value\": \"TestBinary\"\n"
|
||||
+ " }\n"
|
||||
+ " },\n"
|
||||
+ " \"Type\": \"Notification\",\n"
|
||||
+ " \"UnsubscribeUrl\": \"https://sns.us-east-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-2:123456789012:test-lambda:21be56ed-a058-49f5-8c98-aedd2564c486\",\n"
|
||||
+ " \"TopicArn\":\"arn:aws:sns:us-east-2:123456789012:sns-lambda\",\n"
|
||||
+ " \"Subject\": \"TestInvoke\"\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ " ]\n"
|
||||
+ "}"));
|
||||
return events;
|
||||
}
|
||||
|
||||
private TracingRequestWrapper buildWrapper(Class<?> targetClass) {
|
||||
WrappedLambda wrappedLambda = new WrappedLambda(targetClass, "handleRequest");
|
||||
|
||||
return new TracingRequestWrapper(sdk, wrappedLambda);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(
|
||||
classes = {
|
||||
ScheduledEventRequestHandler.class,
|
||||
KinesisEventRequestHandler.class,
|
||||
SqsEventRequestHandler.class,
|
||||
S3EventRequestHandler.class,
|
||||
SnsEventRequestHandler.class
|
||||
})
|
||||
void handleLambdaEvent(Class<?> targetClass) throws IOException {
|
||||
wrapper = buildWrapper(targetClass);
|
||||
EventInfo eventInfo = EVENTS_JSON.get(targetClass);
|
||||
|
||||
Object input = SerializationUtil.fromJson(eventInfo.eventBody, eventInfo.eventType);
|
||||
|
||||
// Call to object based "O handleRequest(I input, Context context)" method
|
||||
// delegates to the stream based
|
||||
// "handleRequest(InputStream input, OutputStream output, Context context)" method.
|
||||
// So serialization/deserialization of both input and outputs are triggered to be verified here.
|
||||
Object output = wrapper.handleRequest(input, context);
|
||||
|
||||
assertThat(input.getClass()).isEqualTo(output.getClass());
|
||||
|
||||
// "equals" methods are not properly implemented of Lambda events,
|
||||
// so we are comparing them over their serialized json data
|
||||
String inputJson = SerializationUtil.toJson(input);
|
||||
String outputJson = SerializationUtil.toJson(output);
|
||||
assertThat(inputJson).isEqualTo(outputJson);
|
||||
}
|
||||
|
||||
public static class ScheduledEventRequestHandler
|
||||
implements RequestHandler<ScheduledEvent, ScheduledEvent> {
|
||||
@Override
|
||||
public ScheduledEvent handleRequest(ScheduledEvent i, Context cntxt) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
public static class KinesisEventRequestHandler
|
||||
implements RequestHandler<KinesisEvent, KinesisEvent> {
|
||||
@Override
|
||||
public KinesisEvent handleRequest(KinesisEvent i, Context cntxt) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SqsEventRequestHandler implements RequestHandler<SQSEvent, SQSEvent> {
|
||||
@Override
|
||||
public SQSEvent handleRequest(SQSEvent i, Context cntxt) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
public static class S3EventRequestHandler implements RequestHandler<S3Event, S3Event> {
|
||||
@Override
|
||||
public S3Event handleRequest(S3Event i, Context cntxt) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SnsEventRequestHandler implements RequestHandler<SNSEvent, SNSEvent> {
|
||||
@Override
|
||||
public SNSEvent handleRequest(SNSEvent i, Context cntxt) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
plugins {
|
||||
id("otel.library-instrumentation")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":instrumentation:aws-lambda:aws-lambda-core-1.0:library"))
|
||||
|
||||
compileOnly("io.opentelemetry:opentelemetry-sdk")
|
||||
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
|
||||
|
||||
library("com.amazonaws:aws-lambda-java-core:1.0.0")
|
||||
// First version to includes support for SQSEvent, currently the most popular message queue used
|
||||
// with lambda.
|
||||
// NB: 2.2.0 includes a class called SQSEvent but isn't usable due to it returning private classes
|
||||
// in public API.
|
||||
library("com.amazonaws:aws-lambda-java-events:2.2.1")
|
||||
|
||||
// By default, "aws-lambda-java-serialization" library is enabled in the classpath
|
||||
// at the AWS Lambda environment except "java8" runtime which is deprecated.
|
||||
// But it is available at "java8.al2" runtime, so it is still can be used
|
||||
// by Java 8 based Lambda functions.
|
||||
// So that is the reason that why we add it as compile only dependency.
|
||||
library("com.amazonaws:aws-lambda-java-serialization:1.1.5")
|
||||
|
||||
// We need Jackson for wrappers to reproduce the serialization does when Lambda invokes a RequestHandler with event
|
||||
// since Lambda will only be able to invoke the wrapper itself with a generic Object.
|
||||
// Note that Lambda itself uses Jackson, but does not expose it to the function so we need to include it here.
|
||||
// TODO: Switch to aws-lambda-java-serialization to more robustly follow Lambda's serialization logic.
|
||||
implementation("com.fasterxml.jackson.core:jackson-databind")
|
||||
implementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator")
|
||||
|
||||
// allows to get the default events
|
||||
testLibrary("com.amazonaws:aws-lambda-java-events:3.10.0")
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
// required on jdk17
|
||||
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
|
||||
jvmArgs("--add-opens=java.base/java.util=ALL-UNNAMED")
|
||||
jvmArgs("-XX:+IgnoreUnrecognizedVMOptions")
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import static io.opentelemetry.instrumentation.api.internal.AttributesExtractorUtil.internalSet;
|
||||
import static io.opentelemetry.instrumentation.api.internal.HttpConstants._OTHER;
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
|
|
@ -21,13 +21,11 @@ import java.util.Set;
|
|||
public final class AwsLambdaEventsInstrumenterFactory {
|
||||
|
||||
public static AwsLambdaFunctionInstrumenter createInstrumenter(
|
||||
OpenTelemetry openTelemetry, Set<String> knownMethods) {
|
||||
OpenTelemetry openTelemetry, String instrumentationName, Set<String> knownMethods) {
|
||||
return new AwsLambdaFunctionInstrumenter(
|
||||
openTelemetry,
|
||||
Instrumenter.builder(
|
||||
openTelemetry,
|
||||
"io.opentelemetry.aws-lambda-events-2.2",
|
||||
AwsLambdaEventsInstrumenterFactory::spanName)
|
||||
openTelemetry, instrumentationName, AwsLambdaEventsInstrumenterFactory::spanName)
|
||||
.addAttributesExtractor(new AwsLambdaFunctionAttributesExtractor())
|
||||
.addAttributesExtractor(new ApiGatewayProxyAttributesExtractor(knownMethods))
|
||||
.buildInstrumenter(SpanKindExtractor.alwaysServer()));
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage;
|
||||
|
|
@ -18,21 +18,19 @@ import java.util.List;
|
|||
*/
|
||||
public final class AwsLambdaSqsInstrumenterFactory {
|
||||
|
||||
public static Instrumenter<SQSEvent, Void> forEvent(OpenTelemetry openTelemetry) {
|
||||
public static Instrumenter<SQSEvent, Void> forEvent(
|
||||
OpenTelemetry openTelemetry, String instrumentationName) {
|
||||
return Instrumenter.<SQSEvent, Void>builder(
|
||||
openTelemetry,
|
||||
"io.opentelemetry.aws-lambda-events-2.2",
|
||||
AwsLambdaSqsInstrumenterFactory::spanName)
|
||||
openTelemetry, instrumentationName, AwsLambdaSqsInstrumenterFactory::spanName)
|
||||
.addAttributesExtractor(new SqsEventAttributesExtractor())
|
||||
.addSpanLinksExtractor(new SqsEventSpanLinksExtractor())
|
||||
.buildInstrumenter(SpanKindExtractor.alwaysConsumer());
|
||||
}
|
||||
|
||||
public static Instrumenter<SQSMessage, Void> forMessage(OpenTelemetry openTelemetry) {
|
||||
public static Instrumenter<SQSMessage, Void> forMessage(
|
||||
OpenTelemetry openTelemetry, String instrumentationName) {
|
||||
return Instrumenter.<SQSMessage, Void>builder(
|
||||
openTelemetry,
|
||||
"io.opentelemetry.aws-lambda-events-2.2",
|
||||
message -> message.getEventSource() + " process")
|
||||
openTelemetry, instrumentationName, message -> message.getEventSource() + " process")
|
||||
.addAttributesExtractor(new SqsMessageAttributesExtractor())
|
||||
.addSpanLinksExtractor(new SqsMessageSpanLinksExtractor())
|
||||
.buildInstrumenter(SpanKindExtractor.alwaysConsumer());
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
|
|
@ -34,7 +34,6 @@ class CustomJodaModule extends SimpleModule {
|
|||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CustomJodaModule() {
|
||||
super();
|
||||
addDeserializer(DateTime.class, new DateTimeDeserialiser());
|
||||
}
|
||||
|
||||
|
|
@ -3,16 +3,20 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
final class LambdaParameters {
|
||||
/**
|
||||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
|
||||
* any time.
|
||||
*/
|
||||
public final class LambdaParameters {
|
||||
|
||||
static <T> Object[] toArray(
|
||||
public static <T> Object[] toArray(
|
||||
Method targetMethod, T input, Context context, BiFunction<T, Class<?>, Object> mapper) {
|
||||
Class<?>[] parameterTypes = targetMethod.getParameterTypes();
|
||||
Object[] parameters = new Object[parameterTypes.length];
|
||||
|
|
@ -28,7 +32,7 @@ final class LambdaParameters {
|
|||
return parameters;
|
||||
}
|
||||
|
||||
static <T> Object[] toParameters(Method targetMethod, T input, Context context) {
|
||||
public static <T> Object[] toParameters(Method targetMethod, T input, Context context) {
|
||||
Class<?>[] parameterTypes = targetMethod.getParameterTypes();
|
||||
Object[] parameters = new Object[parameterTypes.length];
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
|
|
@ -43,7 +47,7 @@ final class LambdaParameters {
|
|||
return parameters;
|
||||
}
|
||||
|
||||
static Object toInput(
|
||||
public static Object toInput(
|
||||
Method targetMethod,
|
||||
InputStream inputStream,
|
||||
BiFunction<InputStream, Class<?>, Object> mapper) {
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.serialization.PojoSerializer;
|
||||
import com.amazonaws.services.lambda.runtime.serialization.events.LambdaEventSerializers;
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||
import io.opentelemetry.context.Context;
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage;
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
|
|
@ -3,13 +3,12 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.amazonaws.services.lambda.runtime.Context;
|
||||
import io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal.SerializationUtil;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.v2_2.internal;
|
||||
package io.opentelemetry.instrumentation.awslambdaevents.common.v2_2.internal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
|
@ -164,6 +164,8 @@ include(":instrumentation:aws-lambda:aws-lambda-core-1.0:testing")
|
|||
include(":instrumentation:aws-lambda:aws-lambda-events-2.2:javaagent")
|
||||
include(":instrumentation:aws-lambda:aws-lambda-events-2.2:library")
|
||||
include(":instrumentation:aws-lambda:aws-lambda-events-2.2:testing")
|
||||
include(":instrumentation:aws-lambda:aws-lambda-events-3.11:library")
|
||||
include(":instrumentation:aws-lambda:aws-lambda-events-common-2.2:library")
|
||||
include(":instrumentation:aws-sdk:aws-sdk-1.11:javaagent")
|
||||
include(":instrumentation:aws-sdk:aws-sdk-1.11:library")
|
||||
include(":instrumentation:aws-sdk:aws-sdk-1.11:library-autoconfigure")
|
||||
|
|
|
|||
Loading…
Reference in New Issue