diff --git a/.github/patches/opentelemetry-java-contrib.patch b/.github/patches/opentelemetry-java-contrib.patch deleted file mode 100644 index 65a6f8b780..0000000000 --- a/.github/patches/opentelemetry-java-contrib.patch +++ /dev/null @@ -1,237 +0,0 @@ -diff --git a/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/SamplingRuleApplier.java b/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/SamplingRuleApplier.java -index 1ef8abf..ef84f35 100644 ---- a/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/SamplingRuleApplier.java -+++ b/aws-xray/src/main/java/io/opentelemetry/contrib/awsxray/SamplingRuleApplier.java -@@ -35,6 +35,11 @@ final class SamplingRuleApplier { - - private static final Map XRAY_CLOUD_PLATFORM; - -+ private static final AttributeKey URL_PATH = AttributeKey.stringKey("url.path"); -+ private static final AttributeKey URL_FULL = AttributeKey.stringKey("url.full"); -+ private static final AttributeKey HTTP_REQUEST_METHOD = -+ AttributeKey.stringKey("http.request.method"); -+ - static { - Map xrayCloudPlatform = new HashMap<>(); - xrayCloudPlatform.put(ResourceAttributes.CloudPlatformValues.AWS_EC2, "AWS::EC2::Instance"); -@@ -162,11 +167,14 @@ final class SamplingRuleApplier { - String host = null; - - for (Map.Entry, Object> entry : attributes.asMap().entrySet()) { -- if (entry.getKey().equals(SemanticAttributes.HTTP_TARGET)) { -+ if (entry.getKey().equals(SemanticAttributes.HTTP_TARGET) -+ || entry.getKey().equals(URL_PATH)) { - httpTarget = (String) entry.getValue(); -- } else if (entry.getKey().equals(SemanticAttributes.HTTP_URL)) { -+ } else if (entry.getKey().equals(SemanticAttributes.HTTP_URL) -+ || entry.getKey().equals(URL_FULL)) { - httpUrl = (String) entry.getValue(); -- } else if (entry.getKey().equals(SemanticAttributes.HTTP_METHOD)) { -+ } else if (entry.getKey().equals(SemanticAttributes.HTTP_METHOD) -+ || entry.getKey().equals(HTTP_REQUEST_METHOD)) { - httpMethod = (String) entry.getValue(); - } else if (entry.getKey().equals(SemanticAttributes.NET_HOST_NAME)) { - host = (String) entry.getValue(); -diff --git a/aws-xray/src/test/java/io/opentelemetry/contrib/awsxray/SamplingRuleApplierTest.java b/aws-xray/src/test/java/io/opentelemetry/contrib/awsxray/SamplingRuleApplierTest.java -index 6bb6e82..55dabbd 100644 ---- a/aws-xray/src/test/java/io/opentelemetry/contrib/awsxray/SamplingRuleApplierTest.java -+++ b/aws-xray/src/test/java/io/opentelemetry/contrib/awsxray/SamplingRuleApplierTest.java -@@ -42,6 +42,11 @@ class SamplingRuleApplierTest { - - private static final String CLIENT_ID = "test-client-id"; - -+ private static final AttributeKey URL_PATH = AttributeKey.stringKey("url.path"); -+ private static final AttributeKey URL_FULL = AttributeKey.stringKey("url.full"); -+ private static final AttributeKey HTTP_REQUEST_METHOD = -+ AttributeKey.stringKey("http.request.method"); -+ - @Nested - @SuppressWarnings("ClassCanBeStatic") - class ExactMatch { -@@ -68,6 +73,15 @@ class SamplingRuleApplierTest { - .put(AttributeKey.longKey("speed"), 10) - .build(); - -+ private final Attributes newSemCovAttributes = -+ Attributes.builder() -+ .put(HTTP_REQUEST_METHOD, "GET") -+ .put(SemanticAttributes.NET_HOST_NAME, "opentelemetry.io") -+ .put(URL_PATH, "/instrument-me") -+ .put(AttributeKey.stringKey("animal"), "cat") -+ .put(AttributeKey.longKey("speed"), 10) -+ .build(); -+ - // FixedRate set to 1.0 in rule and no reservoir - @Test - void fixedRateAlwaysSample() { -@@ -116,6 +130,21 @@ class SamplingRuleApplierTest { - .isTrue(); - } - -+ @Test -+ void matchesURLFullNewSemCov() { -+ assertThat(applier.matches(newSemCovAttributes, resource)).isTrue(); -+ -+ // http.url works too -+ assertThat( -+ applier.matches( -+ attributes.toBuilder() -+ .remove(URL_FULL) -+ .put(URL_FULL, "scheme://host:port/instrument-me") -+ .build(), -+ resource)) -+ .isTrue(); -+ } -+ - @Test - void serviceNameNotMatch() { - assertThat( -@@ -137,6 +166,13 @@ class SamplingRuleApplierTest { - assertThat(applier.matches(attributes, resource)).isFalse(); - } - -+ @Test -+ void methodNewSemCovNotMatch() { -+ Attributes attributes = -+ this.newSemCovAttributes.toBuilder().put(HTTP_REQUEST_METHOD, "POST").build(); -+ assertThat(applier.matches(attributes, resource)).isFalse(); -+ } -+ - @Test - void hostNotMatch() { - // Replacing dot with character makes sure we're not accidentally treating dot as regex -@@ -178,6 +214,34 @@ class SamplingRuleApplierTest { - assertThat(applier.matches(attributes, resource)).isFalse(); - } - -+ @Test -+ void pathNewSemCovNotMatch() { -+ Attributes attributes = -+ this.newSemCovAttributes.toBuilder().put(URL_PATH, "/instrument-you").build(); -+ assertThat(applier.matches(attributes, resource)).isFalse(); -+ attributes = -+ this.newSemCovAttributes.toBuilder() -+ .remove(URL_PATH) -+ .put(URL_FULL, "scheme://host:port/instrument-you") -+ .build(); -+ assertThat(applier.matches(attributes, resource)).isFalse(); -+ attributes = -+ this.newSemCovAttributes.toBuilder() -+ .remove(URL_PATH) -+ .put(URL_FULL, "scheme://host:port") -+ .build(); -+ assertThat(applier.matches(attributes, resource)).isFalse(); -+ -+ // Correct path, but we ignore anyways since the URL is malformed per spec, scheme is always -+ // present. -+ attributes = -+ this.newSemCovAttributes.toBuilder() -+ .remove(URL_PATH) -+ .put(URL_FULL, "host:port/instrument-me") -+ .build(); -+ assertThat(applier.matches(attributes, resource)).isFalse(); -+ } -+ - @Test - void attributeNotMatch() { - Attributes attributes = -@@ -243,6 +307,15 @@ class SamplingRuleApplierTest { - .put(AttributeKey.longKey("speed"), 10) - .build(); - -+ private final Attributes newSemCovAttributes = -+ Attributes.builder() -+ .put(HTTP_REQUEST_METHOD, "GET") -+ .put(SemanticAttributes.NET_HOST_NAME, "opentelemetry.io") -+ .put(URL_PATH, "/instrument-me?foo=bar&cat=meow") -+ .put(AttributeKey.stringKey("animal"), "cat") -+ .put(AttributeKey.longKey("speed"), 10) -+ .build(); -+ - // FixedRate set to 0.0 in rule and no reservoir - @Test - void fixedRateNeverSample() { -@@ -329,6 +402,26 @@ class SamplingRuleApplierTest { - assertThat(applier.matches(attributes, resource)).isFalse(); - } - -+ @Test -+ void newSemCovMethodMatches() { -+ Attributes attributes = -+ this.newSemCovAttributes.toBuilder().put(HTTP_REQUEST_METHOD, "BADGETGOOD").build(); -+ assertThat(applier.matches(attributes, resource)).isTrue(); -+ attributes = newSemCovAttributes.toBuilder().put(HTTP_REQUEST_METHOD, "BADGET").build(); -+ assertThat(applier.matches(attributes, resource)).isTrue(); -+ attributes = newSemCovAttributes.toBuilder().put(HTTP_REQUEST_METHOD, "GETGET").build(); -+ assertThat(applier.matches(attributes, resource)).isTrue(); -+ } -+ -+ @Test -+ void newSemCovMethodNotMatch() { -+ Attributes attributes = -+ newSemCovAttributes.toBuilder().put(HTTP_REQUEST_METHOD, "POST").build(); -+ assertThat(applier.matches(attributes, resource)).isFalse(); -+ attributes = removeAttribute(newSemCovAttributes, HTTP_REQUEST_METHOD); -+ assertThat(applier.matches(attributes, resource)).isFalse(); -+ } -+ - @Test - void hostMatches() { - Attributes attributes = -@@ -410,6 +503,29 @@ class SamplingRuleApplierTest { - assertThat(applier.matches(attributes, resource)).isFalse(); - } - -+ @Test -+ void pathNewSemCovMatches() { -+ Attributes attributes = -+ newSemCovAttributes.toBuilder().put(URL_PATH, "/instrument-me?foo=bar&cat=").build(); -+ assertThat(applier.matches(attributes, resource)).isTrue(); -+ // Deceptive question mark, it's actually a wildcard :-) -+ attributes = -+ newSemCovAttributes.toBuilder().put(URL_PATH, "/instrument-meafoo=bar&cat=").build(); -+ assertThat(applier.matches(attributes, resource)).isTrue(); -+ } -+ -+ @Test -+ void pathNewSemCovNotMatch() { -+ Attributes attributes = -+ newSemCovAttributes.toBuilder().put(URL_PATH, "/instrument-mea?foo=bar&cat=").build(); -+ assertThat(applier.matches(attributes, resource)).isFalse(); -+ attributes = -+ newSemCovAttributes.toBuilder().put(URL_PATH, "foo/instrument-meafoo=bar&cat=").build(); -+ assertThat(applier.matches(attributes, resource)).isFalse(); -+ attributes = removeAttribute(newSemCovAttributes, URL_PATH); -+ assertThat(applier.matches(attributes, resource)).isFalse(); -+ } -+ - @Test - void attributeMatches() { - Attributes attributes = -diff --git a/disk-buffering/build.gradle.kts b/disk-buffering/build.gradle.kts -index 041d2e9..e3d60f4 100644 ---- a/disk-buffering/build.gradle.kts -+++ b/disk-buffering/build.gradle.kts -@@ -70,6 +70,10 @@ tasks.named("shadowJar") { - mustRunAfter("jar") - } - -+tasks.withType().configureEach { -+ dependsOn("shadowJar") -+} -+ - // The javadoc from wire's generated classes has errors that make the task that generates the "javadoc" artifact to fail. This - // makes the javadoc task to ignore those generated classes. - tasks.withType(Javadoc::class.java) { -diff --git a/version.gradle.kts b/version.gradle.kts -index acefcee..329b524 100644 ---- a/version.gradle.kts -+++ b/version.gradle.kts -@@ -1,5 +1,5 @@ --val stableVersion = "1.39.0" --val alphaVersion = "1.39.0-alpha" -+val stableVersion = "1.39.0-adot1" -+val alphaVersion = "1.39.0-alpha-adot1" - - allprojects { - if (findProperty("otel.stable") != "true") { diff --git a/.github/patches/versions b/.github/patches/versions index be4e3bbcb6..03f4b3f51f 100644 --- a/.github/patches/versions +++ b/.github/patches/versions @@ -1,2 +1 @@ -OTEL_JAVA_INSTRUMENTATION_VERSION=v2.11.0 -OTEL_JAVA_CONTRIB_VERSION=v1.39.0 \ No newline at end of file +OTEL_JAVA_INSTRUMENTATION_VERSION=v2.18.1 diff --git a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/UdpExporterTest.java b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/UdpExporterTest.java index 2a1cea7106..b070d53bba 100644 --- a/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/UdpExporterTest.java +++ b/awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/UdpExporterTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.*; import io.opentelemetry.api.common.AttributeKey; @@ -36,8 +37,10 @@ public class UdpExporterTest { public void testUdpExporterWithDefaults() { OtlpUdpSpanExporter exporter = new OtlpUdpSpanExporterBuilder().build(); UdpSender sender = exporter.getSender(); - assertThat(sender.getEndpoint().getHostName()) - .isEqualTo("localhost"); // getHostName implicitly converts 127.0.0.1 to localhost + String senderEndpointHostName = sender.getEndpoint().getHostName(); + // getHostName may or may not convert 127.0.0.1 to localhost + assertTrue( + senderEndpointHostName.equals("localhost") || senderEndpointHostName.equals("127.0.0.1")); assertThat(sender.getEndpoint().getPort()).isEqualTo(2000); assertThat(exporter.getPayloadPrefix()).endsWith("T1S"); } diff --git a/dependencyManagement/build.gradle.kts b/dependencyManagement/build.gradle.kts index 11a6441070..d186406009 100644 --- a/dependencyManagement/build.gradle.kts +++ b/dependencyManagement/build.gradle.kts @@ -27,8 +27,8 @@ data class DependencySet(val group: String, val version: String, val modules: Li val testSnapshots = rootProject.findProperty("testUpstreamSnapshots") == "true" // This is the version of the upstream instrumentation BOM -val otelVersion = "2.11.0" -val otelSnapshotVersion = "2.12.0" +val otelVersion = "2.18.1" +val otelSnapshotVersion = "2.19.0" val otelAlphaVersion = if (!testSnapshots) "$otelVersion-alpha" else "$otelSnapshotVersion-alpha-SNAPSHOT" val otelJavaAgentVersion = if (!testSnapshots) otelVersion else "$otelSnapshotVersion-SNAPSHOT" // All versions below are only used in testing and do not affect the released artifact. @@ -76,8 +76,8 @@ val dependencyLists = listOf( "commons-logging:commons-logging:1.2", "com.sparkjava:spark-core:2.9.4", "com.squareup.okhttp3:okhttp:4.12.0", - "io.opentelemetry.contrib:opentelemetry-aws-xray:1.39.0-adot1", - "io.opentelemetry.contrib:opentelemetry-aws-resources:1.39.0-alpha", + "io.opentelemetry.contrib:opentelemetry-aws-xray:1.48.0", + "io.opentelemetry.contrib:opentelemetry-aws-resources:1.48.0-alpha", "io.opentelemetry.proto:opentelemetry-proto:1.0.0-alpha", "io.opentelemetry.javaagent:opentelemetry-javaagent:$otelJavaAgentVersion", "io.opentelemetry:opentelemetry-extension-aws:1.20.1", diff --git a/instrumentation/aws-sdk/build.gradle.kts b/instrumentation/aws-sdk/build.gradle.kts index 101e966a12..58fb6b48d7 100644 --- a/instrumentation/aws-sdk/build.gradle.kts +++ b/instrumentation/aws-sdk/build.gradle.kts @@ -41,4 +41,6 @@ dependencies { testImplementation("com.amazonaws:aws-java-sdk-sns:1.11.106") testImplementation("com.amazonaws:aws-java-sdk-stepfunctions:1.11.230") testImplementation("com.amazonaws:aws-java-sdk-secretsmanager:1.11.309") + + testRuntimeOnly("org.junit.platform:junit-platform-launcher") } diff --git a/lambda-layer/build-layer.sh b/lambda-layer/build-layer.sh index 265a367d66..ddd144716d 100755 --- a/lambda-layer/build-layer.sh +++ b/lambda-layer/build-layer.sh @@ -25,8 +25,6 @@ git checkout v${version} -b tag-v${version} # This patch is for Lambda related context propagation patch -p1 < "$SOURCEDIR"/patches/opentelemetry-java-instrumentation.patch -patch -p1 < "$SOURCEDIR"/patches/StreamHandlerInstrumentation.patch - ./gradlew publishToMavenLocal popd rm -rf opentelemetry-java-instrumentation diff --git a/lambda-layer/patches/StreamHandlerInstrumentation.patch b/lambda-layer/patches/StreamHandlerInstrumentation.patch deleted file mode 100644 index c4d4751c89..0000000000 --- a/lambda-layer/patches/StreamHandlerInstrumentation.patch +++ /dev/null @@ -1,513 +0,0 @@ -diff --git a/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaInstrumentationModule.java b/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaInstrumentationModule.java -index 35d6b70ed6..b6a305178e 100644 ---- a/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaInstrumentationModule.java -+++ b/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaInstrumentationModule.java -@@ -6,17 +6,18 @@ - package io.opentelemetry.javaagent.instrumentation.awslambdacore.v1_0; - - import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; --import static java.util.Collections.singletonList; - import static net.bytebuddy.matcher.ElementMatchers.not; - - import com.google.auto.service.AutoService; - import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; - import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -+import java.util.Arrays; - import java.util.List; - import net.bytebuddy.matcher.ElementMatcher; - - @AutoService(InstrumentationModule.class) - public class AwsLambdaInstrumentationModule extends InstrumentationModule { -+ - public AwsLambdaInstrumentationModule() { - super("aws-lambda-core", "aws-lambda-core-1.0", "aws-lambda"); - } -@@ -34,6 +35,8 @@ public class AwsLambdaInstrumentationModule extends InstrumentationModule { - - @Override - public List typeInstrumentations() { -- return singletonList(new AwsLambdaRequestHandlerInstrumentation()); -+ return Arrays.asList( -+ new AwsLambdaRequestHandlerInstrumentation(), -+ new AwsLambdaRequestStreamHandlerInstrumentation()); - } - } -diff --git a/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaRequestStreamHandlerInstrumentation.java b/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaRequestStreamHandlerInstrumentation.java -new file mode 100644 -index 0000000000..1c4ef1ac07 ---- /dev/null -+++ b/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaRequestStreamHandlerInstrumentation.java -@@ -0,0 +1,98 @@ -+/* -+ * Copyright The OpenTelemetry Authors -+ * SPDX-License-Identifier: Apache-2.0 -+ */ -+ -+package io.opentelemetry.javaagent.instrumentation.awslambdacore.v1_0; -+ -+import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; -+import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; -+import static io.opentelemetry.javaagent.instrumentation.awslambdacore.v1_0.AwsLambdaInstrumentationHelper.functionInstrumenter; -+import static net.bytebuddy.matcher.ElementMatchers.isMethod; -+import static net.bytebuddy.matcher.ElementMatchers.isPublic; -+import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; -+import static net.bytebuddy.matcher.ElementMatchers.named; -+import static net.bytebuddy.matcher.ElementMatchers.not; -+import static net.bytebuddy.matcher.ElementMatchers.takesArgument; -+ -+import com.amazonaws.services.lambda.runtime.Context; -+import io.opentelemetry.context.Scope; -+import io.opentelemetry.instrumentation.awslambdacore.v1_0.AwsLambdaRequest; -+import io.opentelemetry.javaagent.bootstrap.OpenTelemetrySdkAccess; -+import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -+import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -+import java.io.InputStream; -+import java.util.Collections; -+import java.util.concurrent.TimeUnit; -+import net.bytebuddy.asm.Advice; -+import net.bytebuddy.description.type.TypeDescription; -+import net.bytebuddy.implementation.bytecode.assign.Assigner.Typing; -+import net.bytebuddy.matcher.ElementMatcher; -+ -+public class AwsLambdaRequestStreamHandlerInstrumentation implements TypeInstrumentation { -+ -+ @Override -+ public ElementMatcher classLoaderOptimization() { -+ return hasClassesNamed("com.amazonaws.services.lambda.runtime.RequestStreamHandler"); -+ } -+ -+ @Override -+ public ElementMatcher typeMatcher() { -+ return implementsInterface(named("com.amazonaws.services.lambda.runtime.RequestStreamHandler")) -+ .and(not(nameStartsWith("com.amazonaws.services.lambda.runtime.api.client"))) -+ // In Java 8 and Java 11 runtimes, -+ // AWS Lambda runtime is packaged under `lambdainternal` package. -+ // But it is `com.amazonaws.services.lambda.runtime.api.client` -+ // for new runtime likes Java 17 and Java 21. -+ .and(not(nameStartsWith("lambdainternal"))); -+ } -+ -+ @Override -+ public void transform(TypeTransformer transformer) { -+ transformer.applyAdviceToMethod( -+ isMethod() -+ .and(isPublic()) -+ .and(named("handleRequest")) -+ .and(takesArgument(2, named("com.amazonaws.services.lambda.runtime.Context"))), -+ AwsLambdaRequestStreamHandlerInstrumentation.class.getName() + "$HandleRequestAdvice"); -+ } -+ -+ @SuppressWarnings("unused") -+ public static class HandleRequestAdvice { -+ -+ @Advice.OnMethodEnter(suppress = Throwable.class) -+ public static void onEnter( -+ @Advice.Argument(0) InputStream input, -+ @Advice.Argument(2) Context context, -+ @Advice.Local("otelInput") AwsLambdaRequest otelInput, -+ @Advice.Local("otelContext") io.opentelemetry.context.Context otelContext, -+ @Advice.Local("otelScope") Scope otelScope) { -+ -+ otelInput = AwsLambdaRequest.create(context, input, Collections.emptyMap()); -+ io.opentelemetry.context.Context parentContext = functionInstrumenter().extract(otelInput); -+ -+ if (!functionInstrumenter().shouldStart(parentContext, otelInput)) { -+ return; -+ } -+ -+ otelContext = functionInstrumenter().start(parentContext, otelInput); -+ otelScope = otelContext.makeCurrent(); -+ } -+ -+ @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) -+ public static void stopSpan( -+ @Advice.Argument(value = 0, typing = Typing.DYNAMIC) Object arg, -+ @Advice.Thrown Throwable throwable, -+ @Advice.Local("otelInput") AwsLambdaRequest input, -+ @Advice.Local("otelContext") io.opentelemetry.context.Context functionContext, -+ @Advice.Local("otelScope") Scope functionScope) { -+ -+ if (functionScope != null) { -+ functionScope.close(); -+ functionInstrumenter().end(functionContext, input, null, throwable); -+ } -+ -+ OpenTelemetrySdkAccess.forceFlush((long)1, TimeUnit.SECONDS); -+ } -+ } -+} -diff --git a/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaStreamHandlerTest.java b/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaStreamHandlerTest.java -new file mode 100644 -index 0000000000..7bed968d77 ---- /dev/null -+++ b/instrumentation/aws-lambda/aws-lambda-core-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambdacore/v1_0/AwsLambdaStreamHandlerTest.java -@@ -0,0 +1,113 @@ -+/* -+ * Copyright The OpenTelemetry Authors -+ * SPDX-License-Identifier: Apache-2.0 -+ */ -+ -+package io.opentelemetry.javaagent.instrumentation.awslambdacore.v1_0; -+ -+import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; -+import static org.assertj.core.api.Assertions.assertThat; -+import static org.assertj.core.api.Assertions.catchThrowable; -+import static org.mockito.Mockito.when; -+ -+import com.amazonaws.services.lambda.runtime.Context; -+import com.amazonaws.services.lambda.runtime.RequestStreamHandler; -+import io.opentelemetry.api.trace.SpanKind; -+import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; -+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; -+import io.opentelemetry.sdk.trace.data.StatusData; -+import io.opentelemetry.semconv.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.mockito.Mock; -+import org.mockito.junit.jupiter.MockitoExtension; -+ -+@ExtendWith(MockitoExtension.class) -+public class AwsLambdaStreamHandlerTest { -+ -+ @RegisterExtension -+ public static final InstrumentationExtension testing = AgentInstrumentationExtension.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 handlerTraced() throws Exception { -+ InputStream input = new ByteArrayInputStream("hello\n".getBytes(StandardCharsets.UTF_8)); -+ OutputStream output = new ByteArrayOutputStream(); -+ RequestStreamHandlerTestImpl handler = new RequestStreamHandlerTestImpl(); -+ handler.handleRequest(input, output, context); -+ -+ testing.waitAndAssertTraces( -+ trace -> -+ trace.hasSpansSatisfyingExactly( -+ span -> -+ span.hasName("my_function") -+ .hasKind(SpanKind.SERVER) -+ .hasAttributesSatisfyingExactly( -+ equalTo(SemanticAttributes.FAAS_INVOCATION_ID, "1-22-333")))); -+ } -+ -+ @Test -+ void handlerTracedWithException() { -+ InputStream input = new ByteArrayInputStream("bye\n".getBytes(StandardCharsets.UTF_8)); -+ OutputStream output = new ByteArrayOutputStream(); -+ RequestStreamHandlerTestImpl handler = new RequestStreamHandlerTestImpl(); -+ -+ Throwable thrown = catchThrowable(() -> handler.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) -+ .hasAttributesSatisfyingExactly( -+ equalTo(SemanticAttributes.FAAS_INVOCATION_ID, "1-22-333")))); -+ } -+ -+ static final class RequestStreamHandlerTestImpl 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"); -+ } -+ } -+ } -+} -diff --git a/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaInstrumentationModule.java b/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaInstrumentationModule.java -index 9e0e372241..2dd6051c23 100644 ---- a/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaInstrumentationModule.java -+++ b/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaInstrumentationModule.java -@@ -6,11 +6,11 @@ - package io.opentelemetry.javaagent.instrumentation.awslambdaevents.v2_2; - - import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; --import static java.util.Collections.singletonList; - - import com.google.auto.service.AutoService; - import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; - import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -+import java.util.Arrays; - import java.util.List; - import net.bytebuddy.matcher.ElementMatcher; - -@@ -32,6 +32,8 @@ public class AwsLambdaInstrumentationModule extends InstrumentationModule { - - @Override - public List typeInstrumentations() { -- return singletonList(new AwsLambdaRequestHandlerInstrumentation()); -+ return Arrays.asList( -+ new AwsLambdaRequestHandlerInstrumentation(), -+ new AwsLambdaRequestStreamHandlerInstrumentation()); - } - } -diff --git a/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaRequestStreamHandlerInstrumentation.java b/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaRequestStreamHandlerInstrumentation.java -new file mode 100644 -index 0000000000..f21a4a5526 ---- /dev/null -+++ b/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaRequestStreamHandlerInstrumentation.java -@@ -0,0 +1,104 @@ -+/* -+ * Copyright The OpenTelemetry Authors -+ * SPDX-License-Identifier: Apache-2.0 -+ */ -+ -+package io.opentelemetry.javaagent.instrumentation.awslambdaevents.v2_2; -+ -+import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; -+import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; -+import static net.bytebuddy.matcher.ElementMatchers.isMethod; -+import static net.bytebuddy.matcher.ElementMatchers.isPublic; -+import static net.bytebuddy.matcher.ElementMatchers.named; -+import static net.bytebuddy.matcher.ElementMatchers.takesArgument; -+ -+import com.amazonaws.services.lambda.runtime.Context; -+import com.amazonaws.services.lambda.runtime.events.SQSEvent; -+import io.opentelemetry.context.Scope; -+import io.opentelemetry.instrumentation.awslambdacore.v1_0.AwsLambdaRequest; -+import io.opentelemetry.javaagent.bootstrap.OpenTelemetrySdkAccess; -+import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; -+import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -+import java.io.InputStream; -+import java.util.Collections; -+import java.util.concurrent.TimeUnit; -+import net.bytebuddy.asm.Advice; -+import net.bytebuddy.description.type.TypeDescription; -+import net.bytebuddy.implementation.bytecode.assign.Assigner.Typing; -+import net.bytebuddy.matcher.ElementMatcher; -+ -+public class AwsLambdaRequestStreamHandlerInstrumentation implements TypeInstrumentation { -+ -+ @Override -+ public ElementMatcher classLoaderOptimization() { -+ return hasClassesNamed("com.amazonaws.services.lambda.runtime.RequestStreamHandler"); -+ } -+ -+ @Override -+ public ElementMatcher typeMatcher() { -+ return implementsInterface(named("com.amazonaws.services.lambda.runtime.RequestStreamHandler")); -+ } -+ -+ @Override -+ public void transform(TypeTransformer transformer) { -+ transformer.applyAdviceToMethod( -+ isMethod() -+ .and(isPublic()) -+ .and(named("handleRequest")) -+ .and(takesArgument(2, named("com.amazonaws.services.lambda.runtime.Context"))), -+ AwsLambdaRequestStreamHandlerInstrumentation.class.getName() + "$HandleRequestAdvice"); -+ } -+ -+ @SuppressWarnings("unused") -+ public static class HandleRequestAdvice { -+ -+ @Advice.OnMethodEnter(suppress = Throwable.class) -+ public static void onEnter( -+ @Advice.Argument(0) InputStream input, -+ @Advice.Argument(2) Context context, -+ @Advice.Local("otelInput") AwsLambdaRequest otelInput, -+ @Advice.Local("otelFunctionContext") io.opentelemetry.context.Context functionContext, -+ @Advice.Local("otelFunctionScope") Scope functionScope, -+ @Advice.Local("otelMessageContext") io.opentelemetry.context.Context messageContext, -+ @Advice.Local("otelMessageScope") Scope messageScope) { -+ otelInput = AwsLambdaRequest.create(context, input, Collections.emptyMap()); -+ io.opentelemetry.context.Context parentContext = -+ AwsLambdaInstrumentationHelper.functionInstrumenter().extract(otelInput); -+ -+ if (!AwsLambdaInstrumentationHelper.functionInstrumenter() -+ .shouldStart(parentContext, otelInput)) { -+ return; -+ } -+ -+ functionContext = -+ AwsLambdaInstrumentationHelper.functionInstrumenter().start(parentContext, otelInput); -+ -+ functionScope = functionContext.makeCurrent(); -+ } -+ -+ @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) -+ public static void stopSpan( -+ @Advice.Argument(value = 0, typing = Typing.DYNAMIC) Object arg, -+ @Advice.Thrown Throwable throwable, -+ @Advice.Local("otelInput") AwsLambdaRequest input, -+ @Advice.Local("otelFunctionContext") io.opentelemetry.context.Context functionContext, -+ @Advice.Local("otelFunctionScope") Scope functionScope, -+ @Advice.Local("otelMessageContext") io.opentelemetry.context.Context messageContext, -+ @Advice.Local("otelMessageScope") Scope messageScope) { -+ -+ if (messageScope != null) { -+ messageScope.close(); -+ AwsLambdaInstrumentationHelper.messageInstrumenter() -+ .end(messageContext, (SQSEvent) arg, null, throwable); -+ } -+ -+ if (functionScope != null) { -+ functionScope.close(); -+ AwsLambdaInstrumentationHelper.functionInstrumenter() -+ .end(functionContext, input, null, throwable); -+ } -+ -+ OpenTelemetrySdkAccess.forceFlush((long)1, TimeUnit.SECONDS); -+ } -+ } -+} -diff --git a/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaStreamHandlerTest.java b/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaStreamHandlerTest.java -new file mode 100644 -index 0000000000..e30690418d ---- /dev/null -+++ b/instrumentation/aws-lambda/aws-lambda-events-2.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awslambdaevents/v2_2/AwsLambdaStreamHandlerTest.java -@@ -0,0 +1,113 @@ -+/* -+ * Copyright The OpenTelemetry Authors -+ * SPDX-License-Identifier: Apache-2.0 -+ */ -+ -+package io.opentelemetry.javaagent.instrumentation.awslambdaevents.v2_2; -+ -+import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; -+import static org.assertj.core.api.Assertions.assertThat; -+import static org.assertj.core.api.Assertions.catchThrowable; -+import static org.mockito.Mockito.when; -+ -+import com.amazonaws.services.lambda.runtime.Context; -+import com.amazonaws.services.lambda.runtime.RequestStreamHandler; -+import io.opentelemetry.api.trace.SpanKind; -+import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; -+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; -+import io.opentelemetry.sdk.trace.data.StatusData; -+import io.opentelemetry.semconv.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.mockito.Mock; -+import org.mockito.junit.jupiter.MockitoExtension; -+ -+@ExtendWith(MockitoExtension.class) -+public class AwsLambdaStreamHandlerTest { -+ -+ @RegisterExtension -+ public static final InstrumentationExtension testing = AgentInstrumentationExtension.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 handlerTraced() throws Exception { -+ InputStream input = new ByteArrayInputStream("hello\n".getBytes(StandardCharsets.UTF_8)); -+ OutputStream output = new ByteArrayOutputStream(); -+ RequestStreamHandlerTestImpl handler = new RequestStreamHandlerTestImpl(); -+ handler.handleRequest(input, output, context); -+ -+ testing.waitAndAssertTraces( -+ trace -> -+ trace.hasSpansSatisfyingExactly( -+ span -> -+ span.hasName("my_function") -+ .hasKind(SpanKind.SERVER) -+ .hasAttributesSatisfyingExactly( -+ equalTo(SemanticAttributes.FAAS_INVOCATION_ID, "1-22-333")))); -+ } -+ -+ @Test -+ void handlerTracedWithException() { -+ InputStream input = new ByteArrayInputStream("bye\n".getBytes(StandardCharsets.UTF_8)); -+ OutputStream output = new ByteArrayOutputStream(); -+ RequestStreamHandlerTestImpl handler = new RequestStreamHandlerTestImpl(); -+ -+ Throwable thrown = catchThrowable(() -> handler.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) -+ .hasAttributesSatisfyingExactly( -+ equalTo(SemanticAttributes.FAAS_INVOCATION_ID, "1-22-333")))); -+ } -+ -+ static final class RequestStreamHandlerTestImpl 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"); -+ } -+ } -+ } -+} diff --git a/lambda-layer/patches/aws-otel-java-instrumentation.patch b/lambda-layer/patches/aws-otel-java-instrumentation.patch index 6b1f5eb9d5..bbd66b64c1 100644 --- a/lambda-layer/patches/aws-otel-java-instrumentation.patch +++ b/lambda-layer/patches/aws-otel-java-instrumentation.patch @@ -1,13 +1,13 @@ diff --git a/dependencyManagement/build.gradle.kts b/dependencyManagement/build.gradle.kts -index 9493189..6090207 100644 +index d186406..91b9386 100644 --- a/dependencyManagement/build.gradle.kts +++ b/dependencyManagement/build.gradle.kts @@ -27,7 +27,7 @@ data class DependencySet(val group: String, val version: String, val modules: Li val testSnapshots = rootProject.findProperty("testUpstreamSnapshots") == "true" - + // This is the version of the upstream instrumentation BOM --val otelVersion = "2.11.0" -+val otelVersion = "2.11.0-adot-lambda1" - val otelSnapshotVersion = "2.12.0" +-val otelVersion = "2.18.1" ++val otelVersion = "2.18.1-adot-lambda1" + val otelSnapshotVersion = "2.19.0" val otelAlphaVersion = if (!testSnapshots) "$otelVersion-alpha" else "$otelSnapshotVersion-alpha-SNAPSHOT" val otelJavaAgentVersion = if (!testSnapshots) otelVersion else "$otelSnapshotVersion-SNAPSHOT" diff --git a/lambda-layer/patches/opentelemetry-java-instrumentation.patch b/lambda-layer/patches/opentelemetry-java-instrumentation.patch index a4004e3330..9f4baa1481 100644 --- a/lambda-layer/patches/opentelemetry-java-instrumentation.patch +++ b/lambda-layer/patches/opentelemetry-java-instrumentation.patch @@ -306,14 +306,14 @@ index 4cd11fc0c4..7b7d62755c 100644 } diff --git a/version.gradle.kts b/version.gradle.kts -index 7900c9a4d9..80383d7c22 100644 +index 023d04703c..b267166804 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -1,5 +1,5 @@ --val stableVersion = "2.11.0" --val alphaVersion = "2.11.0-alpha" -+val stableVersion = "2.11.0-adot-lambda1" -+val alphaVersion = "2.11.0-adot-lambda1-alpha" - +-val stableVersion = "2.18.1" +-val alphaVersion = "2.18.1-alpha" ++val stableVersion = "2.18.1-adot-lambda1" ++val alphaVersion = "2.18.1-adot-lambda1-alpha" + allprojects { if (findProperty("otel.stable") != "true") {