Migrate AWS Lambda tests to Java (#5315)
* Migrate AWS Lambda tests to Java * Only assert OTLP fields for links
This commit is contained in:
parent
186c657b4e
commit
b9fac11c90
|
@ -110,6 +110,7 @@ val DEPENDENCIES = listOf(
|
||||||
"com.google.code.findbugs:annotations:3.0.1u2",
|
"com.google.code.findbugs:annotations:3.0.1u2",
|
||||||
"com.google.code.findbugs:jsr305:3.0.2",
|
"com.google.code.findbugs:jsr305:3.0.2",
|
||||||
"org.codehaus.groovy:groovy-all:${groovyVersion}",
|
"org.codehaus.groovy:groovy-all:${groovyVersion}",
|
||||||
|
"org.junit-pioneer:junit-pioneer:1.5.0",
|
||||||
"org.objenesis:objenesis:3.2",
|
"org.objenesis:objenesis:3.2",
|
||||||
"org.spockframework:spock-core:2.0-groovy-3.0",
|
"org.spockframework:spock-core:2.0-groovy-3.0",
|
||||||
"org.spockframework:spock-junit4:2.0-groovy-3.0",
|
"org.spockframework:spock-junit4:2.0-groovy-3.0",
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import com.amazonaws.services.lambda.runtime.RequestHandler
|
|
||||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent
|
|
||||||
import io.opentelemetry.instrumentation.awslambda.v1_0.AbstractAwsLambdaSqsHandlerTest
|
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
|
||||||
|
|
||||||
class AwsLambdaSqsHandlerTest extends AbstractAwsLambdaSqsHandlerTest implements AgentTestTrait {
|
|
||||||
|
|
||||||
static class TestRequestHandler implements RequestHandler<SQSEvent, Void> {
|
|
||||||
@Override
|
|
||||||
Void handleRequest(SQSEvent input, Context context) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
RequestHandler<SQSEvent, Void> handler() {
|
|
||||||
return new TestRequestHandler()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import com.amazonaws.services.lambda.runtime.RequestHandler
|
|
||||||
import io.opentelemetry.instrumentation.awslambda.v1_0.AbstractAwsLambdaRequestHandlerTest
|
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
|
||||||
import io.opentelemetry.javaagent.testing.common.AgentTestingExporterAccess
|
|
||||||
|
|
||||||
class AwsLambdaTest extends AbstractAwsLambdaRequestHandlerTest implements AgentTestTrait {
|
|
||||||
|
|
||||||
def cleanup() {
|
|
||||||
assert AgentTestingExporterAccess.forceFlushCalled()
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TestRequestHandler implements RequestHandler<String, String> {
|
|
||||||
@Override
|
|
||||||
String handleRequest(String input, Context context) {
|
|
||||||
return doHandleRequest(input, context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
RequestHandler<String, String> handler() {
|
|
||||||
return new TestRequestHandler()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import com.amazonaws.services.lambda.runtime.Context;
|
||||||
|
import com.amazonaws.services.lambda.runtime.RequestHandler;
|
||||||
|
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||||
|
import io.opentelemetry.instrumentation.awslambda.v1_0.AbstractAwsLambdaSqsEventHandlerTest;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
|
public class AwsLambdaSqsEventHandlerTest extends AbstractAwsLambdaSqsEventHandlerTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RequestHandler<SQSEvent, Void> handler() {
|
||||||
|
return new TestRequestHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected InstrumentationExtension testing() {
|
||||||
|
return testing;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class TestRequestHandler implements RequestHandler<SQSEvent, Void> {
|
||||||
|
@Override
|
||||||
|
public Void handleRequest(SQSEvent input, Context context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import com.amazonaws.services.lambda.runtime.Context;
|
||||||
|
import com.amazonaws.services.lambda.runtime.RequestHandler;
|
||||||
|
import io.opentelemetry.instrumentation.awslambda.v1_0.AbstractAwsLambdaTest;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
|
public class AwsLambdaTest extends AbstractAwsLambdaTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RequestHandler<String, String> handler() {
|
||||||
|
return new TestRequestHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected InstrumentationExtension testing() {
|
||||||
|
return testing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void tearDown() {
|
||||||
|
assertThat(testing.forceFlushCalled()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class TestRequestHandler implements RequestHandler<String, String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String handleRequest(String input, Context context) {
|
||||||
|
return doHandleRequest(input, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import com.amazonaws.services.lambda.runtime.RequestHandler
|
|
||||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent
|
|
||||||
import io.opentelemetry.instrumentation.test.LibraryTestTrait
|
|
||||||
import io.opentelemetry.sdk.OpenTelemetrySdk
|
|
||||||
|
|
||||||
class AwsLambdaSqsHandlerTest extends AbstractAwsLambdaSqsHandlerTest implements LibraryTestTrait {
|
|
||||||
|
|
||||||
static class TestHandler extends TracingSqsEventHandler {
|
|
||||||
|
|
||||||
TestHandler(OpenTelemetrySdk openTelemetrySdk) {
|
|
||||||
super(openTelemetrySdk)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void handleEvent(SQSEvent event, Context context) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
RequestHandler<SQSEvent, Void> handler() {
|
|
||||||
return new TestHandler(testRunner().openTelemetrySdk)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,102 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent
|
|
||||||
import io.opentelemetry.instrumentation.test.LibraryInstrumentationSpecification
|
|
||||||
import io.opentelemetry.sdk.OpenTelemetrySdk
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
|
||||||
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.CONSUMER
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.SERVER
|
|
||||||
|
|
||||||
class AwsLambdaSqsMessageHandlerTest extends LibraryInstrumentationSpecification {
|
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
static class TestHandler extends TracingSqsMessageHandler {
|
|
||||||
|
|
||||||
TestHandler(OpenTelemetrySdk openTelemetrySdk) {
|
|
||||||
super(openTelemetrySdk)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void handleMessage(SQSEvent.SQSMessage event, Context context) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "messages with process spans"() {
|
|
||||||
when:
|
|
||||||
def context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
|
|
||||||
def message1 = new SQSEvent.SQSMessage()
|
|
||||||
message1.setAttributes(["AWSTraceHeader": AWS_TRACE_HEADER1])
|
|
||||||
message1.setMessageId("message1")
|
|
||||||
message1.setEventSource("queue1")
|
|
||||||
|
|
||||||
def message2 = new SQSEvent.SQSMessage()
|
|
||||||
message2.setAttributes(["AWSTraceHeader": AWS_TRACE_HEADER2])
|
|
||||||
message2.setMessageId("message2")
|
|
||||||
message2.setEventSource("queue1")
|
|
||||||
|
|
||||||
def event = new SQSEvent()
|
|
||||||
event.setRecords([message1, message2])
|
|
||||||
|
|
||||||
new TestHandler(testRunner().openTelemetrySdk).handleRequest(event, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 4) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
span(1) {
|
|
||||||
name("queue1 process")
|
|
||||||
kind CONSUMER
|
|
||||||
parentSpanId(span(0).spanId)
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
|
||||||
"$SemanticAttributes.MESSAGING_OPERATION" "process"
|
|
||||||
}
|
|
||||||
hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad8")
|
|
||||||
hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad9")
|
|
||||||
}
|
|
||||||
span(2) {
|
|
||||||
name("queue1 process")
|
|
||||||
kind CONSUMER
|
|
||||||
parentSpanId(span(1).spanId)
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
|
||||||
"$SemanticAttributes.MESSAGING_OPERATION" "process"
|
|
||||||
"$SemanticAttributes.MESSAGING_MESSAGE_ID" "message1"
|
|
||||||
"$SemanticAttributes.MESSAGING_DESTINATION" "queue1"
|
|
||||||
}
|
|
||||||
hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad8")
|
|
||||||
}
|
|
||||||
span(3) {
|
|
||||||
name("queue1 process")
|
|
||||||
kind CONSUMER
|
|
||||||
parentSpanId(span(1).spanId)
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
|
||||||
"$SemanticAttributes.MESSAGING_OPERATION" "process"
|
|
||||||
"$SemanticAttributes.MESSAGING_MESSAGE_ID" "message2"
|
|
||||||
"$SemanticAttributes.MESSAGING_DESTINATION" "queue1"
|
|
||||||
}
|
|
||||||
hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad9")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import com.amazonaws.services.lambda.runtime.RequestHandler
|
|
||||||
import io.opentelemetry.instrumentation.test.LibraryTestTrait
|
|
||||||
import io.opentelemetry.sdk.OpenTelemetrySdk
|
|
||||||
|
|
||||||
class AwsLambdaTest extends AbstractAwsLambdaRequestHandlerTest implements LibraryTestTrait {
|
|
||||||
|
|
||||||
def cleanup() {
|
|
||||||
assert forceFlushCalled()
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TestRequestHandler extends TracingRequestHandler<String, String> {
|
|
||||||
|
|
||||||
TestRequestHandler(OpenTelemetrySdk openTelemetrySdk) {
|
|
||||||
super(openTelemetrySdk)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String doHandleRequest(String input, Context context) {
|
|
||||||
return AbstractAwsLambdaRequestHandlerTest.doHandleRequest(input, context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
RequestHandler<String, String> handler() {
|
|
||||||
return new TestRequestHandler(testRunner().openTelemetrySdk)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,232 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
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 com.google.common.collect.ImmutableMap
|
|
||||||
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
|
||||||
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.SERVER
|
|
||||||
|
|
||||||
class TracingRequestApiGatewayWrapperTest extends TracingRequestWrapperTestBase {
|
|
||||||
|
|
||||||
static class TestApiGatewayEventHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
|
|
||||||
if (input.getBody() == "hello") {
|
|
||||||
return new APIGatewayProxyResponseEvent()
|
|
||||||
.withStatusCode(200)
|
|
||||||
.withBody("world")
|
|
||||||
} else if (input.getBody() == "empty") {
|
|
||||||
return new APIGatewayProxyResponseEvent()
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("bad request")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TestApiGatewayStringHandler implements RequestHandler<String, String> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String handleRequest(String input, Context context) {
|
|
||||||
if (input == "hello") {
|
|
||||||
return "world"
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("bad request")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TestApiGatewayIntegerHandler implements RequestHandler<Integer, String> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String handleRequest(Integer input, Context context) {
|
|
||||||
if (input == 1) {
|
|
||||||
return "world"
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("bad request")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class CustomType {
|
|
||||||
String key, value
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TestApiGatewayCustomTypeHandler implements RequestHandler<CustomType, String> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String handleRequest(CustomType input, Context context) {
|
|
||||||
if (input.key == "hello") {
|
|
||||||
return "Hello " + input.value
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("bad request")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def propagationHeaders() {
|
|
||||||
return Collections.singletonMap("traceparent", "00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01")
|
|
||||||
}
|
|
||||||
|
|
||||||
def "event handler traced with trace propagation"() {
|
|
||||||
given:
|
|
||||||
setLambda(TestApiGatewayEventHandler.getName() + "::handleRequest", TracingRequestApiGatewayWrapper.metaClass.&invokeConstructor, TracingRequestApiGatewayWrapper.&map)
|
|
||||||
|
|
||||||
def headers = ImmutableMap.builder()
|
|
||||||
.putAll(propagationHeaders())
|
|
||||||
.put("User-Agent", "Test Client")
|
|
||||||
.put("host", "localhost:123")
|
|
||||||
.put("X-FORWARDED-PROTO", "http")
|
|
||||||
.build()
|
|
||||||
def input = new APIGatewayProxyRequestEvent()
|
|
||||||
.withHttpMethod("GET")
|
|
||||||
.withResource("/hello/{param}")
|
|
||||||
.withPath("/hello/world")
|
|
||||||
.withBody("hello")
|
|
||||||
.withQueryStringParamters(["a": "b", "c": "d"])
|
|
||||||
.withHeaders(headers)
|
|
||||||
|
|
||||||
when:
|
|
||||||
APIGatewayProxyResponseEvent result = wrapper.handleRequest(input, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
result.getBody() == "world"
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
parentSpanId("0000000000000456")
|
|
||||||
traceId("4fd0b6131f19f39af59518d127b0cafe")
|
|
||||||
name("/hello/{param}")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
"$SemanticAttributes.FAAS_TRIGGER" "http"
|
|
||||||
"$SemanticAttributes.HTTP_METHOD" "GET"
|
|
||||||
"$SemanticAttributes.HTTP_USER_AGENT" "Test Client"
|
|
||||||
"$SemanticAttributes.HTTP_URL" "http://localhost:123/hello/world?a=b&c=d"
|
|
||||||
"$SemanticAttributes.HTTP_STATUS_CODE" 200
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "event handler test empty request & response"() {
|
|
||||||
given:
|
|
||||||
setLambda(TestApiGatewayEventHandler.getName() + "::handleRequest", TracingRequestApiGatewayWrapper.metaClass.&invokeConstructor, TracingRequestApiGatewayWrapper.&map)
|
|
||||||
|
|
||||||
def input = new APIGatewayProxyRequestEvent()
|
|
||||||
.withBody("empty")
|
|
||||||
|
|
||||||
when:
|
|
||||||
APIGatewayProxyResponseEvent result = wrapper.handleRequest(input, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
result.body == null
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
"$SemanticAttributes.FAAS_TRIGGER" "http"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "string handler test request"() {
|
|
||||||
given:
|
|
||||||
setLambda(TestApiGatewayStringHandler.getName() + "::handleRequest", TracingRequestApiGatewayWrapper.metaClass.&invokeConstructor, TracingRequestApiGatewayWrapper.&map)
|
|
||||||
|
|
||||||
def input = new APIGatewayProxyRequestEvent()
|
|
||||||
.withBody("\"hello\"")
|
|
||||||
|
|
||||||
when:
|
|
||||||
APIGatewayProxyResponseEvent result = wrapper.handleRequest(input, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
result.body == "\"world\""
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
"$SemanticAttributes.FAAS_TRIGGER" "http"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "integer handler test request"() {
|
|
||||||
given:
|
|
||||||
setLambda(TestApiGatewayIntegerHandler.getName() + "::handleRequest", TracingRequestApiGatewayWrapper.metaClass.&invokeConstructor, TracingRequestApiGatewayWrapper.&map)
|
|
||||||
|
|
||||||
def input = new APIGatewayProxyRequestEvent()
|
|
||||||
.withBody("1")
|
|
||||||
|
|
||||||
when:
|
|
||||||
APIGatewayProxyResponseEvent result = wrapper.handleRequest(input, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
result.body == "\"world\""
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
"$SemanticAttributes.FAAS_TRIGGER" "http"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "custom type handler test request"() {
|
|
||||||
given:
|
|
||||||
setLambda(TestApiGatewayCustomTypeHandler.getName() + "::handleRequest", TracingRequestApiGatewayWrapper.metaClass.&invokeConstructor, TracingRequestApiGatewayWrapper.&map)
|
|
||||||
|
|
||||||
def input = new APIGatewayProxyRequestEvent()
|
|
||||||
.withBody("{\"key\":\"hello\", \"value\":\"General Kenobi\"}")
|
|
||||||
|
|
||||||
when:
|
|
||||||
APIGatewayProxyResponseEvent result = wrapper.handleRequest(input, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
result.body == "\"Hello General Kenobi\""
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
"$SemanticAttributes.FAAS_TRIGGER" "http"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import com.amazonaws.services.lambda.runtime.RequestStreamHandler
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
|
||||||
import io.opentelemetry.instrumentation.test.LibraryInstrumentationSpecification
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.contrib.java.lang.system.EnvironmentVariables
|
|
||||||
import spock.lang.Shared
|
|
||||||
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.SERVER
|
|
||||||
import static io.opentelemetry.api.trace.StatusCode.ERROR
|
|
||||||
|
|
||||||
class TracingRequestStreamWrapperPropagationTest extends LibraryInstrumentationSpecification {
|
|
||||||
|
|
||||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final EnvironmentVariables environmentVariables = new EnvironmentVariables()
|
|
||||||
|
|
||||||
static class TestRequestHandler implements RequestStreamHandler {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void handleRequest(InputStream input, OutputStream output, Context context) {
|
|
||||||
|
|
||||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output))
|
|
||||||
|
|
||||||
JsonNode root = OBJECT_MAPPER.readTree(input)
|
|
||||||
String body = root.get("body").asText()
|
|
||||||
if (body == "hello") {
|
|
||||||
writer.write("world")
|
|
||||||
writer.flush()
|
|
||||||
writer.close()
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("bad argument")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
TracingRequestStreamWrapper wrapper
|
|
||||||
|
|
||||||
def setup() {
|
|
||||||
environmentVariables.set(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY, "io.opentelemetry.instrumentation.awslambda.v1_0.TracingRequestStreamWrapperPropagationTest\$TestRequestHandler::handleRequest")
|
|
||||||
wrapper = new TracingRequestStreamWrapper(testRunner().openTelemetrySdk, WrappedLambda.fromConfiguration())
|
|
||||||
}
|
|
||||||
|
|
||||||
def cleanup() {
|
|
||||||
environmentVariables.clear(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY)
|
|
||||||
}
|
|
||||||
|
|
||||||
def "handler traced with trace propagation"() {
|
|
||||||
when:
|
|
||||||
String content =
|
|
||||||
"{" +
|
|
||||||
"\"headers\" : {" +
|
|
||||||
"\"traceparent\": \"00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01\"" +
|
|
||||||
"}," +
|
|
||||||
"\"body\" : \"hello\"" +
|
|
||||||
"}"
|
|
||||||
def context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
def input = new ByteArrayInputStream(content.getBytes(Charset.defaultCharset()))
|
|
||||||
def output = new ByteArrayOutputStream()
|
|
||||||
|
|
||||||
wrapper.handleRequest(input, output, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
parentSpanId("0000000000000456")
|
|
||||||
traceId("4fd0b6131f19f39af59518d127b0cafe")
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "handler traced with exception and trace propagation"() {
|
|
||||||
when:
|
|
||||||
String content =
|
|
||||||
"{" +
|
|
||||||
"\"headers\" : {" +
|
|
||||||
"\"traceparent\": \"00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01\"" +
|
|
||||||
"}," +
|
|
||||||
"\"body\" : \"bye\"" +
|
|
||||||
"}"
|
|
||||||
def context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
def input = new ByteArrayInputStream(content.getBytes(Charset.defaultCharset()))
|
|
||||||
def output = new ByteArrayOutputStream()
|
|
||||||
|
|
||||||
def thrown
|
|
||||||
try {
|
|
||||||
wrapper.handleRequest(input, output, context)
|
|
||||||
} catch (Throwable t) {
|
|
||||||
thrown = t
|
|
||||||
}
|
|
||||||
|
|
||||||
then:
|
|
||||||
thrown != null
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
parentSpanId("0000000000000456")
|
|
||||||
traceId("4fd0b6131f19f39af59518d127b0cafe")
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
status ERROR
|
|
||||||
errorEvent(IllegalArgumentException, "bad argument")
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,119 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import com.amazonaws.services.lambda.runtime.RequestStreamHandler
|
|
||||||
import io.opentelemetry.instrumentation.test.LibraryInstrumentationSpecification
|
|
||||||
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.contrib.java.lang.system.EnvironmentVariables
|
|
||||||
import spock.lang.Shared
|
|
||||||
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.SERVER
|
|
||||||
import static io.opentelemetry.api.trace.StatusCode.ERROR
|
|
||||||
|
|
||||||
class TracingRequestStreamWrapperTest extends LibraryInstrumentationSpecification {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final EnvironmentVariables environmentVariables = new EnvironmentVariables()
|
|
||||||
|
|
||||||
static class TestRequestHandler implements RequestStreamHandler {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void handleRequest(InputStream input, OutputStream output, Context context) {
|
|
||||||
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(input))
|
|
||||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output))
|
|
||||||
String line = reader.readLine()
|
|
||||||
if (line == "hello") {
|
|
||||||
writer.write("world")
|
|
||||||
writer.flush()
|
|
||||||
writer.close()
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("bad argument")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
TracingRequestStreamWrapper wrapper
|
|
||||||
|
|
||||||
def setup() {
|
|
||||||
environmentVariables.set(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY, "io.opentelemetry.instrumentation.awslambda.v1_0.TracingRequestStreamWrapperTest\$TestRequestHandler::handleRequest")
|
|
||||||
wrapper = new TracingRequestStreamWrapper(testRunner().openTelemetrySdk, WrappedLambda.fromConfiguration())
|
|
||||||
}
|
|
||||||
|
|
||||||
def cleanup() {
|
|
||||||
environmentVariables.clear(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY)
|
|
||||||
}
|
|
||||||
|
|
||||||
def "handler traced"() {
|
|
||||||
when:
|
|
||||||
def context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
context.getInvokedFunctionArn() >> "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
def input = new ByteArrayInputStream("hello\n".getBytes(Charset.defaultCharset()))
|
|
||||||
def output = new ByteArrayOutputStream()
|
|
||||||
|
|
||||||
wrapper.handleRequest(input, output, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "handler traced with exception"() {
|
|
||||||
when:
|
|
||||||
def context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
context.getInvokedFunctionArn() >> "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
def input = new ByteArrayInputStream("bye".getBytes(Charset.defaultCharset()))
|
|
||||||
def output = new ByteArrayOutputStream()
|
|
||||||
|
|
||||||
def thrown
|
|
||||||
try {
|
|
||||||
wrapper.handleRequest(input, output, context)
|
|
||||||
} catch (Throwable t) {
|
|
||||||
thrown = t
|
|
||||||
}
|
|
||||||
|
|
||||||
then:
|
|
||||||
thrown != null
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
status ERROR
|
|
||||||
errorEvent(IllegalArgumentException, "bad argument")
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,160 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import com.amazonaws.services.lambda.runtime.RequestHandler
|
|
||||||
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
|
||||||
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.SERVER
|
|
||||||
import static io.opentelemetry.api.trace.StatusCode.ERROR
|
|
||||||
|
|
||||||
class TracingRequestWrapperTest extends TracingRequestWrapperTestBase {
|
|
||||||
|
|
||||||
static class TestRequestHandlerString implements RequestHandler<String, String> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String handleRequest(String input, Context context) {
|
|
||||||
if (input == "hello") {
|
|
||||||
return "world"
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("bad argument")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TestRequestHandlerInteger implements RequestHandler<Integer, String> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String handleRequest(Integer input, Context context) {
|
|
||||||
if (input == 1) {
|
|
||||||
return "world"
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("bad argument")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class CustomType {
|
|
||||||
String key, value
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TestRequestHandlerCustomType implements RequestHandler<CustomType, String> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
String handleRequest(CustomType input, Context context) {
|
|
||||||
if (input.key == "hello there") {
|
|
||||||
return input.value
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("bad argument")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "handler string traced"() {
|
|
||||||
given:
|
|
||||||
setLambda(TestRequestHandlerString.getName() + "::handleRequest", TracingRequestWrapper.metaClass.&invokeConstructor, TracingRequestWrapper.&map)
|
|
||||||
|
|
||||||
when:
|
|
||||||
def result = wrapper.handleRequest("hello", context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
result == "world"
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "handler with exception"() {
|
|
||||||
given:
|
|
||||||
setLambda(TestRequestHandlerString.getName() + "::handleRequest", TracingRequestWrapper.metaClass.&invokeConstructor, TracingRequestWrapper.&map)
|
|
||||||
|
|
||||||
when:
|
|
||||||
def thrown
|
|
||||||
try {
|
|
||||||
wrapper.handleRequest("goodbye", context)
|
|
||||||
} catch (Throwable t) {
|
|
||||||
thrown = t
|
|
||||||
}
|
|
||||||
|
|
||||||
then:
|
|
||||||
thrown != null
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
status ERROR
|
|
||||||
errorEvent(IllegalArgumentException, "bad argument")
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "handler integer traced"() {
|
|
||||||
given:
|
|
||||||
setLambda(TestRequestHandlerInteger.getName() + "::handleRequest", TracingRequestWrapper.metaClass.&invokeConstructor, TracingRequestWrapper.&map)
|
|
||||||
|
|
||||||
when:
|
|
||||||
def result = wrapper.handleRequest(1, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
result == "world"
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "handler custom type traced"() {
|
|
||||||
given:
|
|
||||||
setLambda(TestRequestHandlerCustomType.getName() + "::handleRequest", TracingRequestWrapper.metaClass.&invokeConstructor, TracingRequestWrapper.&map)
|
|
||||||
|
|
||||||
when:
|
|
||||||
CustomType ct = new CustomType()
|
|
||||||
ct.key = "hello there"
|
|
||||||
ct.value = "General Kenobi"
|
|
||||||
def result = wrapper.handleRequest(ct, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
result == "General Kenobi"
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import io.opentelemetry.instrumentation.test.LibraryInstrumentationSpecification
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.contrib.java.lang.system.EnvironmentVariables
|
|
||||||
import spock.lang.Shared
|
|
||||||
|
|
||||||
import java.util.function.BiFunction
|
|
||||||
|
|
||||||
class TracingRequestWrapperTestBase extends LibraryInstrumentationSpecification {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final EnvironmentVariables environmentVariables = new EnvironmentVariables()
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
TracingRequestWrapperBase wrapper
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
Context context
|
|
||||||
|
|
||||||
def setup() {
|
|
||||||
context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
context.getInvokedFunctionArn() >> "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
}
|
|
||||||
|
|
||||||
def setLambda(handler, Closure<TracingRequestWrapperBase> wrapperConstructor, BiFunction<?, Class, Object> mapper) {
|
|
||||||
environmentVariables.set(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY, handler)
|
|
||||||
wrapper = wrapperConstructor.call(testRunner().openTelemetrySdk, WrappedLambda.fromConfiguration(), mapper)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import com.amazonaws.services.lambda.runtime.RequestHandler
|
|
||||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent
|
|
||||||
import io.opentelemetry.instrumentation.test.LibraryInstrumentationSpecification
|
|
||||||
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.contrib.java.lang.system.EnvironmentVariables
|
|
||||||
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.CONSUMER
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.SERVER
|
|
||||||
|
|
||||||
class TracingSqsEventWrapperTest extends LibraryInstrumentationSpecification {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final EnvironmentVariables environmentVariables = new EnvironmentVariables()
|
|
||||||
|
|
||||||
TracingSqsEventWrapper wrapper
|
|
||||||
Context context
|
|
||||||
|
|
||||||
def setup() {
|
|
||||||
context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
context.getInvokedFunctionArn() >> "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
}
|
|
||||||
|
|
||||||
def setLambda(handler, Closure<TracingSqsEventWrapper> wrapperConstructor) {
|
|
||||||
environmentVariables.set(WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY, handler)
|
|
||||||
wrapper = wrapperConstructor.call(testRunner().openTelemetrySdk, WrappedLambda.fromConfiguration())
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TestRequestHandler implements RequestHandler<SQSEvent, Void> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Void handleRequest(SQSEvent input, Context context) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def "handler event traced"() {
|
|
||||||
given:
|
|
||||||
setLambda(TestRequestHandler.getName() + "::handleRequest", TracingSqsEventWrapper.metaClass.&invokeConstructor)
|
|
||||||
|
|
||||||
when:
|
|
||||||
SQSEvent event = new SQSEvent()
|
|
||||||
SQSEvent.SQSMessage record = new SQSEvent.SQSMessage()
|
|
||||||
record.setEventSource("otel")
|
|
||||||
record.setAttributes(Collections.emptyMap())
|
|
||||||
event.setRecords(Arrays.asList(record))
|
|
||||||
wrapper.handleRequest(event, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 2) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$ResourceAttributes.FAAS_ID.key" "arn:aws:lambda:us-east-1:123456789:function:test"
|
|
||||||
"$ResourceAttributes.CLOUD_ACCOUNT_ID.key" "123456789"
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
span(1) {
|
|
||||||
name("otel process")
|
|
||||||
kind CONSUMER
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
|
||||||
"$SemanticAttributes.MESSAGING_OPERATION" "process"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,308 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
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.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
|
||||||
|
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||||
|
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)
|
||||||
|
public class AwsLambdaApiGatewayWrapperTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public 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.awslambda.v1_0.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("/hello/{param}")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasTraceId("4fd0b6131f19f39af59518d127b0cafe")
|
||||||
|
.hasParentSpanId("0000000000000456")
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"),
|
||||||
|
entry(SemanticAttributes.FAAS_TRIGGER, "http"),
|
||||||
|
entry(SemanticAttributes.HTTP_METHOD, "GET"),
|
||||||
|
entry(SemanticAttributes.HTTP_USER_AGENT, "Test Client"),
|
||||||
|
entry(
|
||||||
|
SemanticAttributes.HTTP_URL,
|
||||||
|
"http://localhost:123/hello/world?a=b&c=d"),
|
||||||
|
entry(SemanticAttributes.HTTP_STATUS_CODE, 200L)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SetEnvironmentVariable(
|
||||||
|
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||||
|
value =
|
||||||
|
"io.opentelemetry.instrumentation.awslambda.v1_0.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)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"),
|
||||||
|
entry(SemanticAttributes.FAAS_TRIGGER, "http")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SetEnvironmentVariable(
|
||||||
|
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||||
|
value =
|
||||||
|
"io.opentelemetry.instrumentation.awslambda.v1_0.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)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"),
|
||||||
|
entry(SemanticAttributes.FAAS_TRIGGER, "http")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SetEnvironmentVariable(
|
||||||
|
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||||
|
value =
|
||||||
|
"io.opentelemetry.instrumentation.awslambda.v1_0.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)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"),
|
||||||
|
entry(SemanticAttributes.FAAS_TRIGGER, "http")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SetEnvironmentVariable(
|
||||||
|
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||||
|
value =
|
||||||
|
"io.opentelemetry.instrumentation.awslambda.v1_0.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)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"),
|
||||||
|
entry(SemanticAttributes.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,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import com.amazonaws.services.lambda.runtime.Context;
|
||||||
|
import com.amazonaws.services.lambda.runtime.RequestHandler;
|
||||||
|
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class AwsLambdaSqsEventHandlerTest extends AbstractAwsLambdaSqsEventHandlerTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RequestHandler<SQSEvent, Void> 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 void handleEvent(SQSEvent event, Context context) {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
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.SQSEvent;
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||||
|
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||||
|
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.awslambda.v1_0.AwsLambdaSqsEventWrapperTest$TestRequestHandler::handleRequest")
|
||||||
|
public class AwsLambdaSqsEventWrapperTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public 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
|
||||||
|
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)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"))),
|
||||||
|
span ->
|
||||||
|
span.hasName("otel process")
|
||||||
|
.hasKind(SpanKind.CONSUMER)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
|
||||||
|
entry(
|
||||||
|
SemanticAttributes.MESSAGING_OPERATION, "process")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class TestRequestHandler implements RequestHandler<SQSEvent, Void> {
|
||||||
|
@Override
|
||||||
|
public Void 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,168 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.amazonaws.services.lambda.runtime.Context;
|
||||||
|
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.trace.attributes.SemanticAttributes;
|
||||||
|
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)
|
||||||
|
public 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
|
||||||
|
public 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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));
|
||||||
|
|
||||||
|
new TestHandler(testing.getOpenTelemetrySdk()).handleRequest(event, context);
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("my_function")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"))),
|
||||||
|
span ->
|
||||||
|
span.hasName("queue1 process")
|
||||||
|
.hasKind(SpanKind.CONSUMER)
|
||||||
|
.hasParentSpanId(trace.getSpan(0).getSpanId())
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
|
||||||
|
entry(SemanticAttributes.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())
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
|
||||||
|
entry(SemanticAttributes.MESSAGING_OPERATION, "process"),
|
||||||
|
entry(SemanticAttributes.MESSAGING_MESSAGE_ID, "message1"),
|
||||||
|
entry(SemanticAttributes.MESSAGING_DESTINATION, "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())
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
|
||||||
|
entry(SemanticAttributes.MESSAGING_OPERATION, "process"),
|
||||||
|
entry(SemanticAttributes.MESSAGING_MESSAGE_ID, "message2"),
|
||||||
|
entry(SemanticAttributes.MESSAGING_DESTINATION, "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 void handleMessage(SQSEvent.SQSMessage message, Context context) {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.amazonaws.services.lambda.runtime.Context;
|
||||||
|
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
|
||||||
|
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||||
|
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
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.awslambda.v1_0.AwsLambdaStreamWrapperHttpPropagationTest$TestRequestHandler::handleRequest")
|
||||||
|
public class AwsLambdaStreamWrapperHttpPropagationTest {
|
||||||
|
|
||||||
|
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public 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
|
||||||
|
void handlerTraced() throws Exception {
|
||||||
|
String content =
|
||||||
|
"{"
|
||||||
|
+ "\"headers\" : {"
|
||||||
|
+ "\"traceparent\": \"00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01\""
|
||||||
|
+ "},"
|
||||||
|
+ "\"body\" : \"hello\""
|
||||||
|
+ "}";
|
||||||
|
InputStream input = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
OutputStream output = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
TracingRequestStreamWrapper wrapper =
|
||||||
|
new TracingRequestStreamWrapper(
|
||||||
|
testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
|
||||||
|
wrapper.handleRequest(input, output, context);
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("my_function")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasTraceId("4fd0b6131f19f39af59518d127b0cafe")
|
||||||
|
.hasParentSpanId("0000000000000456")
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void handlerTracedWithException() {
|
||||||
|
String content =
|
||||||
|
"{"
|
||||||
|
+ "\"headers\" : {"
|
||||||
|
+ "\"traceparent\": \"00-4fd0b6131f19f39af59518d127b0cafe-0000000000000456-01\""
|
||||||
|
+ "},"
|
||||||
|
+ "\"body\" : \"bye\""
|
||||||
|
+ "}";
|
||||||
|
InputStream input = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
OutputStream output = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
TracingRequestStreamWrapper wrapper =
|
||||||
|
new TracingRequestStreamWrapper(
|
||||||
|
testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
|
||||||
|
|
||||||
|
Throwable thrown = catchThrowable(() -> wrapper.handleRequest(input, output, context));
|
||||||
|
assertThat(thrown).isInstanceOf(IllegalArgumentException.class);
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("my_function")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasTraceId("4fd0b6131f19f39af59518d127b0cafe")
|
||||||
|
.hasParentSpanId("0000000000000456")
|
||||||
|
.hasStatus(StatusData.error())
|
||||||
|
.hasException(thrown)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class TestRequestHandler implements RequestStreamHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleRequest(InputStream input, OutputStream output, Context context)
|
||||||
|
throws IOException {
|
||||||
|
JsonNode root = OBJECT_MAPPER.readTree(input);
|
||||||
|
String body = root.get("body").asText();
|
||||||
|
BufferedWriter writer =
|
||||||
|
new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));
|
||||||
|
if (body.equals("hello")) {
|
||||||
|
writer.write("world");
|
||||||
|
writer.flush();
|
||||||
|
writer.close();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("bad argument");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.amazonaws.services.lambda.runtime.Context;
|
||||||
|
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
|
||||||
|
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||||
|
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
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.awslambda.v1_0.AwsLambdaStreamWrapperTest$TestRequestHandler::handleRequest")
|
||||||
|
public class AwsLambdaStreamWrapperTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public 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
|
||||||
|
void handlerTraced() throws Exception {
|
||||||
|
InputStream input = new ByteArrayInputStream("hello\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
OutputStream output = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
TracingRequestStreamWrapper wrapper =
|
||||||
|
new TracingRequestStreamWrapper(
|
||||||
|
testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
|
||||||
|
wrapper.handleRequest(input, output, context);
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("my_function")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void handlerTracedWithException() {
|
||||||
|
InputStream input = new ByteArrayInputStream("bye\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
OutputStream output = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
TracingRequestStreamWrapper wrapper =
|
||||||
|
new TracingRequestStreamWrapper(
|
||||||
|
testing.getOpenTelemetrySdk(), WrappedLambda.fromConfiguration());
|
||||||
|
|
||||||
|
Throwable thrown = catchThrowable(() -> wrapper.handleRequest(input, output, context));
|
||||||
|
assertThat(thrown).isInstanceOf(IllegalArgumentException.class);
|
||||||
|
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("my_function")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasStatus(StatusData.error())
|
||||||
|
.hasException(thrown)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class TestRequestHandler implements RequestStreamHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleRequest(InputStream input, OutputStream output, Context context)
|
||||||
|
throws IOException {
|
||||||
|
BufferedReader reader =
|
||||||
|
new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
|
||||||
|
BufferedWriter writer =
|
||||||
|
new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));
|
||||||
|
String line = reader.readLine();
|
||||||
|
if (line.equals("hello")) {
|
||||||
|
writer.write("world");
|
||||||
|
writer.flush();
|
||||||
|
writer.close();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("bad argument");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import com.amazonaws.services.lambda.runtime.Context;
|
||||||
|
import com.amazonaws.services.lambda.runtime.RequestHandler;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class AwsLambdaTest extends AbstractAwsLambdaTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RequestHandler<String, String> handler() {
|
||||||
|
return new TestRequestHandler(testing.getOpenTelemetrySdk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected InstrumentationExtension testing() {
|
||||||
|
return testing;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class TestRequestHandler extends TracingRequestHandler<String, String> {
|
||||||
|
|
||||||
|
TestRequestHandler(OpenTelemetrySdk openTelemetrySdk) {
|
||||||
|
super(openTelemetrySdk);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String doHandleRequest(String input, Context context) {
|
||||||
|
return AbstractAwsLambdaTest.doHandleRequest(input, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,219 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
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.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
|
||||||
|
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions;
|
||||||
|
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||||
|
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||||
|
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)
|
||||||
|
public class AwsLambdaWrapperTest {
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public 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.awslambda.v1_0.AwsLambdaWrapperTest$TestRequestHandlerString::handleRequest")
|
||||||
|
void handlerTraced() {
|
||||||
|
TracingRequestWrapper wrapper =
|
||||||
|
new TracingRequestWrapper(
|
||||||
|
testing.getOpenTelemetrySdk(),
|
||||||
|
WrappedLambda.fromConfiguration(),
|
||||||
|
TracingRequestWrapper::map);
|
||||||
|
Object result = wrapper.handleRequest("hello", context);
|
||||||
|
|
||||||
|
assertThat(result).isEqualTo("world");
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("my_function")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SetEnvironmentVariable(
|
||||||
|
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||||
|
value =
|
||||||
|
"io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaWrapperTest$TestRequestHandlerString::handleRequest")
|
||||||
|
void handlerTracedWithException() {
|
||||||
|
TracingRequestWrapper wrapper =
|
||||||
|
new TracingRequestWrapper(
|
||||||
|
testing.getOpenTelemetrySdk(),
|
||||||
|
WrappedLambda.fromConfiguration(),
|
||||||
|
TracingRequestWrapper::map);
|
||||||
|
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)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SetEnvironmentVariable(
|
||||||
|
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||||
|
value =
|
||||||
|
"io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaWrapperTest$TestRequestHandlerInteger::handleRequest")
|
||||||
|
void handlerTraced_integer() {
|
||||||
|
TracingRequestWrapper wrapper =
|
||||||
|
new TracingRequestWrapper(
|
||||||
|
testing.getOpenTelemetrySdk(),
|
||||||
|
WrappedLambda.fromConfiguration(),
|
||||||
|
TracingRequestWrapper::map);
|
||||||
|
Object result = wrapper.handleRequest(1, context);
|
||||||
|
|
||||||
|
assertThat(result).isEqualTo("world");
|
||||||
|
testing.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("my_function")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SetEnvironmentVariable(
|
||||||
|
key = WrappedLambda.OTEL_LAMBDA_HANDLER_ENV_KEY,
|
||||||
|
value =
|
||||||
|
"io.opentelemetry.instrumentation.awslambda.v1_0.AwsLambdaWrapperTest$TestRequestHandlerCustomType::handleRequest")
|
||||||
|
void handlerTraced_custom() {
|
||||||
|
TracingRequestWrapper wrapper =
|
||||||
|
new TracingRequestWrapper(
|
||||||
|
testing.getOpenTelemetrySdk(),
|
||||||
|
WrappedLambda.fromConfiguration(),
|
||||||
|
TracingRequestWrapper::map);
|
||||||
|
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)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
OpenTelemetryAssertions.assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
ResourceAttributes.FAAS_ID,
|
||||||
|
"arn:aws:lambda:us-east-1:123456789:function:test"),
|
||||||
|
entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "123456789"),
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CustomType {
|
||||||
|
String key;
|
||||||
|
String 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,9 @@ dependencies {
|
||||||
api("com.amazonaws:aws-lambda-java-core:1.0.0")
|
api("com.amazonaws:aws-lambda-java-core:1.0.0")
|
||||||
api("com.amazonaws:aws-lambda-java-events:2.2.1")
|
api("com.amazonaws:aws-lambda-java-events:2.2.1")
|
||||||
|
|
||||||
|
api("org.junit-pioneer:junit-pioneer")
|
||||||
|
api("org.mockito:mockito-junit-jupiter")
|
||||||
|
|
||||||
implementation("com.google.guava:guava")
|
implementation("com.google.guava:guava")
|
||||||
|
|
||||||
implementation("org.codehaus.groovy:groovy-all")
|
implementation("org.codehaus.groovy:groovy-all")
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import com.amazonaws.services.lambda.runtime.RequestHandler
|
|
||||||
import com.github.stefanbirkner.systemlambda.SystemLambda
|
|
||||||
import io.opentelemetry.instrumentation.test.InstrumentationSpecification
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
|
||||||
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.SERVER
|
|
||||||
import static io.opentelemetry.api.trace.StatusCode.ERROR
|
|
||||||
|
|
||||||
abstract class AbstractAwsLambdaRequestHandlerTest extends InstrumentationSpecification {
|
|
||||||
|
|
||||||
protected static String doHandleRequest(String input, Context context) {
|
|
||||||
if (input == "hello") {
|
|
||||||
return "world"
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("bad argument")
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract RequestHandler<String, String> handler()
|
|
||||||
|
|
||||||
def "handler traced"() {
|
|
||||||
when:
|
|
||||||
def context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
|
|
||||||
def result = handler().handleRequest("hello", context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
result == "world"
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "handler traced with exception"() {
|
|
||||||
when:
|
|
||||||
def context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
|
|
||||||
def thrown
|
|
||||||
try {
|
|
||||||
handler().handleRequest("goodbye", context)
|
|
||||||
} catch (Throwable t) {
|
|
||||||
thrown = t
|
|
||||||
}
|
|
||||||
|
|
||||||
then:
|
|
||||||
thrown != null
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
status ERROR
|
|
||||||
errorEvent(IllegalArgumentException, "bad argument")
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "handler links to lambda trace"() {
|
|
||||||
when:
|
|
||||||
def context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
|
|
||||||
def result
|
|
||||||
SystemLambda.withEnvironmentVariable("_X_AMZN_TRACE_ID", "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=0000000000000456;Sampled=1")
|
|
||||||
.execute({
|
|
||||||
result = handler().handleRequest("hello", context)
|
|
||||||
})
|
|
||||||
|
|
||||||
then:
|
|
||||||
result == "world"
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 1) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
parentSpanId("0000000000000456")
|
|
||||||
traceId("8a3c60f7d188f8fa79d48a391a778fa6")
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.instrumentation.awslambda.v1_0
|
|
||||||
|
|
||||||
import com.amazonaws.services.lambda.runtime.Context
|
|
||||||
import com.amazonaws.services.lambda.runtime.RequestHandler
|
|
||||||
import com.amazonaws.services.lambda.runtime.events.SQSEvent
|
|
||||||
import io.opentelemetry.instrumentation.test.InstrumentationSpecification
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
|
||||||
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.CONSUMER
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.SERVER
|
|
||||||
|
|
||||||
abstract class AbstractAwsLambdaSqsHandlerTest extends InstrumentationSpecification {
|
|
||||||
|
|
||||||
private static final String AWS_TRACE_HEADER = "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1"
|
|
||||||
|
|
||||||
abstract RequestHandler<SQSEvent, Void> handler()
|
|
||||||
|
|
||||||
def "messages from same source"() {
|
|
||||||
when:
|
|
||||||
def context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
|
|
||||||
def message1 = new SQSEvent.SQSMessage()
|
|
||||||
message1.setAttributes(["AWSTraceHeader": AWS_TRACE_HEADER])
|
|
||||||
message1.setMessageId("message1")
|
|
||||||
message1.setEventSource("queue1")
|
|
||||||
|
|
||||||
def message2 = new SQSEvent.SQSMessage()
|
|
||||||
message2.setAttributes([:])
|
|
||||||
message2.setMessageId("message2")
|
|
||||||
message2.setEventSource("queue1")
|
|
||||||
|
|
||||||
def event = new SQSEvent()
|
|
||||||
event.setRecords([message1, message2])
|
|
||||||
|
|
||||||
handler().handleRequest(event, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 2) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
span(1) {
|
|
||||||
name("queue1 process")
|
|
||||||
kind CONSUMER
|
|
||||||
parentSpanId(span(0).spanId)
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
|
||||||
"$SemanticAttributes.MESSAGING_OPERATION" "process"
|
|
||||||
}
|
|
||||||
hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad8")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def "messages from different source"() {
|
|
||||||
when:
|
|
||||||
def context = Mock(Context)
|
|
||||||
context.getFunctionName() >> "my_function"
|
|
||||||
context.getAwsRequestId() >> "1-22-333"
|
|
||||||
|
|
||||||
def message1 = new SQSEvent.SQSMessage()
|
|
||||||
message1.setAttributes(["AWSTraceHeader": AWS_TRACE_HEADER])
|
|
||||||
message1.setMessageId("message1")
|
|
||||||
message1.setEventSource("queue1")
|
|
||||||
|
|
||||||
def message2 = new SQSEvent.SQSMessage()
|
|
||||||
message2.setAttributes([:])
|
|
||||||
message2.setMessageId("message2")
|
|
||||||
message2.setEventSource("queue2")
|
|
||||||
|
|
||||||
def event = new SQSEvent()
|
|
||||||
event.setRecords([message1, message2])
|
|
||||||
|
|
||||||
handler().handleRequest(event, context)
|
|
||||||
|
|
||||||
then:
|
|
||||||
assertTraces(1) {
|
|
||||||
trace(0, 2) {
|
|
||||||
span(0) {
|
|
||||||
name("my_function")
|
|
||||||
kind SERVER
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.FAAS_EXECUTION" "1-22-333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
span(1) {
|
|
||||||
name("multiple_sources process")
|
|
||||||
kind CONSUMER
|
|
||||||
parentSpanId(span(0).spanId)
|
|
||||||
attributes {
|
|
||||||
"$SemanticAttributes.MESSAGING_SYSTEM" "AmazonSQS"
|
|
||||||
"$SemanticAttributes.MESSAGING_OPERATION" "process"
|
|
||||||
}
|
|
||||||
hasLink("5759e988bd862e3fe1be46a994272793", "53995c3f42cd8ad8")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
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.SQSEvent;
|
||||||
|
import io.opentelemetry.api.trace.SpanKind;
|
||||||
|
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||||
|
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.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
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 InstrumentationExtension testing();
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void sameSource() {
|
||||||
|
SQSEvent.SQSMessage message1 = newMessage();
|
||||||
|
message1.setAttributes(Collections.singletonMap("AWSTraceHeader", AWS_TRACE_HEADER));
|
||||||
|
message1.setMessageId("message1");
|
||||||
|
message1.setEventSource("queue1");
|
||||||
|
|
||||||
|
SQSEvent.SQSMessage message2 = newMessage();
|
||||||
|
message2.setAttributes(Collections.emptyMap());
|
||||||
|
message2.setMessageId("message2");
|
||||||
|
message2.setEventSource("queue1");
|
||||||
|
|
||||||
|
SQSEvent event = new SQSEvent();
|
||||||
|
event.setRecords(Arrays.asList(message1, message2));
|
||||||
|
|
||||||
|
handler().handleRequest(event, context);
|
||||||
|
|
||||||
|
testing()
|
||||||
|
.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("my_function")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"))),
|
||||||
|
span ->
|
||||||
|
span.hasName("queue1 process")
|
||||||
|
.hasKind(SpanKind.CONSUMER)
|
||||||
|
.hasParentSpanId(trace.getSpan(0).getSpanId())
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
|
||||||
|
entry(
|
||||||
|
SemanticAttributes.MESSAGING_OPERATION, "process")))
|
||||||
|
.hasLinksSatisfying(
|
||||||
|
links ->
|
||||||
|
assertThat(links)
|
||||||
|
.singleElement()
|
||||||
|
.satisfies(
|
||||||
|
link -> {
|
||||||
|
assertThat(link.getSpanContext().getTraceId())
|
||||||
|
.isEqualTo("5759e988bd862e3fe1be46a994272793");
|
||||||
|
assertThat(link.getSpanContext().getSpanId())
|
||||||
|
.isEqualTo("53995c3f42cd8ad8");
|
||||||
|
}))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void differentSource() {
|
||||||
|
SQSEvent.SQSMessage message1 = newMessage();
|
||||||
|
message1.setAttributes(Collections.singletonMap("AWSTraceHeader", AWS_TRACE_HEADER));
|
||||||
|
message1.setMessageId("message1");
|
||||||
|
message1.setEventSource("queue1");
|
||||||
|
|
||||||
|
SQSEvent.SQSMessage message2 = newMessage();
|
||||||
|
message2.setAttributes(Collections.emptyMap());
|
||||||
|
message2.setMessageId("message2");
|
||||||
|
message2.setEventSource("queue2");
|
||||||
|
|
||||||
|
SQSEvent event = new SQSEvent();
|
||||||
|
event.setRecords(Arrays.asList(message1, message2));
|
||||||
|
|
||||||
|
handler().handleRequest(event, context);
|
||||||
|
|
||||||
|
testing()
|
||||||
|
.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("my_function")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(SemanticAttributes.FAAS_EXECUTION, "1-22-333"))),
|
||||||
|
span ->
|
||||||
|
span.hasName("multiple_sources process")
|
||||||
|
.hasKind(SpanKind.CONSUMER)
|
||||||
|
.hasParentSpanId(trace.getSpan(0).getSpanId())
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(SemanticAttributes.MESSAGING_SYSTEM, "AmazonSQS"),
|
||||||
|
entry(
|
||||||
|
SemanticAttributes.MESSAGING_OPERATION, "process")))
|
||||||
|
.hasLinksSatisfying(
|
||||||
|
links ->
|
||||||
|
assertThat(links)
|
||||||
|
.singleElement()
|
||||||
|
.satisfies(
|
||||||
|
link -> {
|
||||||
|
assertThat(link.getSpanContext().getTraceId())
|
||||||
|
.isEqualTo("5759e988bd862e3fe1be46a994272793");
|
||||||
|
assertThat(link.getSpanContext().getSpanId())
|
||||||
|
.isEqualTo("53995c3f42cd8ad8");
|
||||||
|
}))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor private in early versions.
|
||||||
|
private static SQSEvent.SQSMessage newMessage() {
|
||||||
|
try {
|
||||||
|
Constructor<SQSEvent.SQSMessage> ctor = SQSEvent.SQSMessage.class.getDeclaredConstructor();
|
||||||
|
ctor.setAccessible(true);
|
||||||
|
return ctor.newInstance();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw new AssertionError(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.awslambda.v1_0;
|
||||||
|
|
||||||
|
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
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.testing.junit.InstrumentationExtension;
|
||||||
|
import io.opentelemetry.sdk.trace.data.StatusData;
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||||
|
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.junitpioneer.jupiter.SetEnvironmentVariable;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
public abstract class AbstractAwsLambdaTest {
|
||||||
|
|
||||||
|
protected static String doHandleRequest(String input, Context context) {
|
||||||
|
if (input.equals("hello")) {
|
||||||
|
return "world";
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("bad argument");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract RequestHandler<String, String> handler();
|
||||||
|
|
||||||
|
protected abstract InstrumentationExtension testing();
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void handlerTraced() {
|
||||||
|
String result = handler().handleRequest("hello", context);
|
||||||
|
assertThat(result).isEqualTo("world");
|
||||||
|
|
||||||
|
testing()
|
||||||
|
.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("my_function")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void handlerTracedWithException() {
|
||||||
|
Throwable thrown = catchThrowable(() -> handler().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)
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SetEnvironmentVariable(
|
||||||
|
key = "_X_AMZN_TRACE_ID",
|
||||||
|
value = "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=0000000000000456;Sampled=1")
|
||||||
|
void handlerLinksToInfrastructureTrace() {
|
||||||
|
String result = handler().handleRequest("hello", context);
|
||||||
|
assertThat(result).isEqualTo("world");
|
||||||
|
|
||||||
|
testing()
|
||||||
|
.waitAndAssertTraces(
|
||||||
|
trace ->
|
||||||
|
trace.hasSpansSatisfyingExactly(
|
||||||
|
span ->
|
||||||
|
span.hasName("my_function")
|
||||||
|
.hasKind(SpanKind.SERVER)
|
||||||
|
.hasTraceId("8a3c60f7d188f8fa79d48a391a778fa6")
|
||||||
|
.hasParentSpanId("0000000000000456")
|
||||||
|
.hasAttributesSatisfying(
|
||||||
|
attrs ->
|
||||||
|
assertThat(attrs)
|
||||||
|
.containsOnly(
|
||||||
|
entry(
|
||||||
|
SemanticAttributes.FAAS_EXECUTION, "1-22-333")))));
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,9 +11,11 @@ import static org.awaitility.Awaitility.await;
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
import io.opentelemetry.context.ContextStorage;
|
import io.opentelemetry.context.ContextStorage;
|
||||||
import io.opentelemetry.instrumentation.testing.InstrumentationTestRunner;
|
import io.opentelemetry.instrumentation.testing.InstrumentationTestRunner;
|
||||||
|
import io.opentelemetry.instrumentation.testing.LibraryTestRunner;
|
||||||
import io.opentelemetry.instrumentation.testing.util.ContextStorageCloser;
|
import io.opentelemetry.instrumentation.testing.util.ContextStorageCloser;
|
||||||
import io.opentelemetry.instrumentation.testing.util.ThrowingRunnable;
|
import io.opentelemetry.instrumentation.testing.util.ThrowingRunnable;
|
||||||
import io.opentelemetry.instrumentation.testing.util.ThrowingSupplier;
|
import io.opentelemetry.instrumentation.testing.util.ThrowingSupplier;
|
||||||
|
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||||
import io.opentelemetry.sdk.metrics.data.MetricData;
|
import io.opentelemetry.sdk.metrics.data.MetricData;
|
||||||
import io.opentelemetry.sdk.testing.assertj.TraceAssert;
|
import io.opentelemetry.sdk.testing.assertj.TraceAssert;
|
||||||
import io.opentelemetry.sdk.trace.data.SpanData;
|
import io.opentelemetry.sdk.trace.data.SpanData;
|
||||||
|
@ -108,6 +110,7 @@ public abstract class InstrumentationExtension
|
||||||
}
|
}
|
||||||
|
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
|
@SuppressWarnings("varargs")
|
||||||
public final void waitAndAssertTraces(Consumer<TraceAssert>... assertions) {
|
public final void waitAndAssertTraces(Consumer<TraceAssert>... assertions) {
|
||||||
testRunner.waitAndAssertTraces(assertions);
|
testRunner.waitAndAssertTraces(assertions);
|
||||||
}
|
}
|
||||||
|
@ -166,6 +169,19 @@ public abstract class InstrumentationExtension
|
||||||
return testRunner.runWithServerSpan(spanName, callback);
|
return testRunner.runWithServerSpan(spanName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns whether forceFlush was called. */
|
||||||
|
public boolean forceFlushCalled() {
|
||||||
|
return testRunner.forceFlushCalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the {@link OpenTelemetrySdk} initialied for library tests. */
|
||||||
|
public OpenTelemetrySdk getOpenTelemetrySdk() {
|
||||||
|
if (testRunner instanceof LibraryTestRunner) {
|
||||||
|
return ((LibraryTestRunner) testRunner).getOpenTelemetrySdk();
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Can only be called from library instrumentation tests.");
|
||||||
|
}
|
||||||
|
|
||||||
protected InstrumentationTestRunner getTestRunner() {
|
protected InstrumentationTestRunner getTestRunner() {
|
||||||
return testRunner;
|
return testRunner;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue