diff --git a/conventions/build.gradle.kts b/conventions/build.gradle.kts index 8e10828932b9..cf023135400a 100644 --- a/conventions/build.gradle.kts +++ b/conventions/build.gradle.kts @@ -46,6 +46,7 @@ dependencies { implementation("org.ow2.asm:asm-tree:9.1") implementation("org.apache.httpcomponents:httpclient:4.5.13") implementation("org.gradle:test-retry-gradle-plugin:1.2.1") + implementation("ru.vyarus:gradle-animalsniffer-plugin:1.5.3") // When updating, also update dependencyManagement/build.gradle.kts implementation("net.bytebuddy:byte-buddy-gradle-plugin:1.11.22") implementation("gradle.plugin.io.morethan.jmhreport:gradle-jmh-report:0.9.0") diff --git a/conventions/src/main/kotlin/otel.animalsniffer-conventions.gradle.kts b/conventions/src/main/kotlin/otel.animalsniffer-conventions.gradle.kts new file mode 100644 index 000000000000..92336a0bfe65 --- /dev/null +++ b/conventions/src/main/kotlin/otel.animalsniffer-conventions.gradle.kts @@ -0,0 +1,13 @@ +plugins { + `java-library` + + id("ru.vyarus.animalsniffer") +} + +dependencies { + add("signature", "com.toasttab.android:gummy-bears-api-21:0.3.0:coreLib@signature") +} + +animalsniffer { + sourceSets = listOf(java.sourceSets.main.get()) +} \ No newline at end of file diff --git a/instrumentation-api/build.gradle.kts b/instrumentation-api/build.gradle.kts index 08123c57de29..69da311f9155 100644 --- a/instrumentation-api/build.gradle.kts +++ b/instrumentation-api/build.gradle.kts @@ -2,6 +2,7 @@ plugins { id("org.xbib.gradle.plugin.jflex") id("otel.java-conventions") + id("otel.animalsniffer-conventions") id("otel.jacoco-conventions") id("otel.japicmp-conventions") id("otel.publish-conventions") diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/JdkErrorCauseExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/JdkErrorCauseExtractor.java index cb90193d4020..05bc587f749b 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/JdkErrorCauseExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/JdkErrorCauseExtractor.java @@ -7,17 +7,20 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.UndeclaredThrowableException; -import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; +import javax.annotation.Nullable; final class JdkErrorCauseExtractor implements ErrorCauseExtractor { static final ErrorCauseExtractor INSTANCE = new JdkErrorCauseExtractor(); + @Nullable + private static final Class COMPLETION_EXCEPTION_CLASS = getCompletionExceptionClass(); + @Override public Throwable extractCause(Throwable error) { if (error.getCause() != null && (error instanceof ExecutionException - || error instanceof CompletionException + || isInstanceOfCompletionException(error) || error instanceof InvocationTargetException || error instanceof UndeclaredThrowableException)) { return extractCause(error.getCause()); @@ -25,5 +28,19 @@ public Throwable extractCause(Throwable error) { return error; } + private static boolean isInstanceOfCompletionException(Throwable error) { + return COMPLETION_EXCEPTION_CLASS != null && COMPLETION_EXCEPTION_CLASS.isInstance(error); + } + + @Nullable + private static Class getCompletionExceptionClass() { + try { + return Class.forName("java.util.concurrent.CompletionException"); + } catch (ClassNotFoundException e) { + // Android level 21 does not support java.util.concurrent.CompletionException + return null; + } + } + private JdkErrorCauseExtractor() {} } diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/BaseTracer.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/BaseTracer.java index f14df0f00331..637a555afcf9 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/BaseTracer.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/BaseTracer.java @@ -22,9 +22,9 @@ import io.opentelemetry.instrumentation.api.internal.SupportabilityMetrics; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.UndeclaredThrowableException; -import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; /** * Base class for all instrumentation specific tracer implementations. @@ -48,6 +48,9 @@ public abstract class BaseTracer { private static final SupportabilityMetrics supportability = SupportabilityMetrics.instance(); + @Nullable + private static final Class COMPLETION_EXCEPTION_CLASS = getCompletionExceptionClass(); + private final Tracer tracer; private final ContextPropagators propagators; @@ -242,7 +245,7 @@ public void onException(Context context, Throwable throwable) { protected Throwable unwrapThrowable(Throwable throwable) { if (throwable.getCause() != null && (throwable instanceof ExecutionException - || throwable instanceof CompletionException + || isInstanceOfCompletionException(throwable) || throwable instanceof InvocationTargetException || throwable instanceof UndeclaredThrowableException)) { return unwrapThrowable(throwable.getCause()); @@ -283,4 +286,18 @@ public Context extract(C carrier, TextMapGetter getter) { public void inject(Context context, C carrier, TextMapSetter setter) { propagators.getTextMapPropagator().inject(context, carrier, setter); } + + private static boolean isInstanceOfCompletionException(Throwable error) { + return COMPLETION_EXCEPTION_CLASS != null && COMPLETION_EXCEPTION_CLASS.isInstance(error); + } + + @Nullable + private static Class getCompletionExceptionClass() { + try { + return Class.forName("java.util.concurrent.CompletionException"); + } catch (ClassNotFoundException e) { + // Android level 21 does not support java.util.concurrent.CompletionException + return null; + } + } } diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.3/library/build.gradle.kts b/instrumentation/apache-httpclient/apache-httpclient-4.3/library/build.gradle.kts index 36958d1b1105..6eea0d1754f4 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.3/library/build.gradle.kts +++ b/instrumentation/apache-httpclient/apache-httpclient-4.3/library/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("otel.library-instrumentation") id("otel.nullaway-conventions") + id("otel.animalsniffer-conventions") } dependencies { diff --git a/instrumentation/grpc-1.6/library/build.gradle.kts b/instrumentation/grpc-1.6/library/build.gradle.kts index e67788d53241..2a346f74c24c 100644 --- a/instrumentation/grpc-1.6/library/build.gradle.kts +++ b/instrumentation/grpc-1.6/library/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("otel.library-instrumentation") + id("otel.animalsniffer-conventions") } val grpcVersion = "1.6.0" diff --git a/instrumentation/okhttp/okhttp-3.0/library/build.gradle.kts b/instrumentation/okhttp/okhttp-3.0/library/build.gradle.kts index 712ad84a04e2..4d262a4cf477 100644 --- a/instrumentation/okhttp/okhttp-3.0/library/build.gradle.kts +++ b/instrumentation/okhttp/okhttp-3.0/library/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("otel.library-instrumentation") id("otel.nullaway-conventions") + id("otel.animalsniffer-conventions") } dependencies { diff --git a/settings.gradle.kts b/settings.gradle.kts index 0667c3d1f671..030fac33370a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,6 +10,7 @@ pluginManagement { id("org.xbib.gradle.plugin.jflex") version "1.5.0" id("nebula.release") version "15.3.1" id("com.github.johnrengelman.shadow") version "7.0.0" + id("ru.vyarus.animalsniffer") version "1.5.3" } }