From 2e417241b5867f6e04763d969fbf4fdb0cf88d79 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 8 Nov 2022 11:49:51 +0100 Subject: [PATCH 1/3] Add modules for OTEL --- buildSrc/src/main/java/Config.kt | 4 + .../build.gradle.kts | 156 ++++++++++++++++++ ...entry-opentelemetry-agentcustomization.api | 10 ++ .../build.gradle.kts | 78 +++++++++ ...ryAutoConfigurationCustomizerProvider.java | 31 ++++ .../SentryBootstrapPackagesProvider.java | 21 +++ ...ling.bootstrap.BootstrapPackagesConfigurer | 1 + ...re.spi.AutoConfigurationCustomizerProvider | 1 + .../api/sentry-opentelemetry-core.api | 8 + .../build.gradle.kts | 74 +++++++++ .../opentelemetry/SentrySpanProcessor.java | 35 ++++ settings.gradle.kts | 3 + 12 files changed, 422 insertions(+) create mode 100644 sentry-opentelemetry/sentry-opentelemetry-agent/build.gradle.kts create mode 100644 sentry-opentelemetry/sentry-opentelemetry-agentcustomization/api/sentry-opentelemetry-agentcustomization.api create mode 100644 sentry-opentelemetry/sentry-opentelemetry-agentcustomization/build.gradle.kts create mode 100644 sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java create mode 100644 sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryBootstrapPackagesProvider.java create mode 100644 sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/resources/META-INF/services/io.opentelemetry.javaagent.tooling.bootstrap.BootstrapPackagesConfigurer create mode 100644 sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider create mode 100644 sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api create mode 100644 sentry-opentelemetry/sentry-opentelemetry-core/build.gradle.kts create mode 100644 sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 34ad1fbff3..ecc9288919 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -131,6 +131,10 @@ object Config { val composeMaterial = "androidx.compose.material3:material3:1.0.0-alpha13" val apolloKotlin = "com.apollographql.apollo3:apollo-runtime:3.3.0" + + val otelVersion = "1.19.0" + val otelJavaagentVersion = "1.19.2" + val otelJavaagentAlphaVersion = "1.19.2-alpha" } object AnnotationProcessors { diff --git a/sentry-opentelemetry/sentry-opentelemetry-agent/build.gradle.kts b/sentry-opentelemetry/sentry-opentelemetry-agent/build.gradle.kts new file mode 100644 index 0000000000..ed0f93dace --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-agent/build.gradle.kts @@ -0,0 +1,156 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + `java-library` + id("com.github.johnrengelman.shadow") version "7.1.2" +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +fun relocatePackages(shadowJar: ShadowJar) { + // rewrite dependencies calling Logger.getLogger + shadowJar.relocate("java.util.logging.Logger", "io.opentelemetry.javaagent.bootstrap.PatchLogger") + + // rewrite library instrumentation dependencies + shadowJar.relocate("io.opentelemetry.instrumentation", "io.opentelemetry.javaagent.shaded.instrumentation") + + // relocate OpenTelemetry API usage + shadowJar.relocate("io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api") + shadowJar.relocate("io.opentelemetry.semconv", "io.opentelemetry.javaagent.shaded.io.opentelemetry.semconv") + shadowJar.relocate("io.opentelemetry.context", "io.opentelemetry.javaagent.shaded.io.opentelemetry.context") + + // relocate the OpenTelemetry extensions that are used by instrumentation modules + // these extensions live in the AgentClassLoader, and are injected into the user's class loader + // by the instrumentation modules that use them + shadowJar.relocate("io.opentelemetry.extension.aws", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.aws") + shadowJar.relocate("io.opentelemetry.extension.kotlin", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.kotlin") +} + +// this configuration collects libs that will be placed in the bootstrap classloader +val bootstrapLibs = configurations.create("bootstrapLibs") { + isCanBeResolved = true + isCanBeConsumed = false +} + +// this configuration collects libs that will be placed in the agent classloader, isolated from the instrumented application code +val javaagentLibs = configurations.create("javaagentLibs") { + isCanBeResolved = true + isCanBeConsumed = false +} + +// this configuration stores the upstream agent dep that's extended by this project +val upstreamAgent = configurations.create("upstreamAgent") { + isCanBeResolved = true + isCanBeConsumed = false +} + +dependencies { + bootstrapLibs(projects.sentry) + javaagentLibs(projects.sentryOpentelemetry.sentryOpentelemetryAgentcustomization) + upstreamAgent("io.opentelemetry.javaagent:opentelemetry-javaagent:${Config.Libs.otelJavaagentVersion}") +} + +fun isolateClasses(jars: Iterable): CopySpec { + return copySpec { + jars.forEach { + from(zipTree(it)) { + into("inst") + rename("^(.*)\\.class\$", "\$1.classdata") + // Rename LICENSE file since it clashes with license dir on non-case sensitive FSs (i.e. Mac) + rename("^LICENSE\$", "LICENSE.renamed") + exclude("META-INF/INDEX.LIST") + exclude("META-INF/*.DSA") + exclude("META-INF/*.SF") + } + } + } +} + +// Don't publish non-shadowed jar (shadowJar is in shadowRuntimeElements) +with(components["java"] as AdhocComponentWithVariants) { + configurations.forEach { + withVariantsFromConfiguration(configurations["apiElements"]) { + skip() + } + withVariantsFromConfiguration(configurations["runtimeElements"]) { + skip() + } + } +} + +tasks { + jar { + archiveClassifier.set("dontuse") + } + + // building the final javaagent jar is done in 3 steps: + + // 1. all distro specific javaagent libs are relocated + create("relocateJavaagentLibs", ShadowJar::class.java) { + configurations = listOf(javaagentLibs) + + duplicatesStrategy = DuplicatesStrategy.FAIL + + archiveFileName.set("javaagentLibs-relocated.jar") + + mergeServiceFiles() + exclude("**/module-info.class") + relocatePackages(this) + + // exclude known bootstrap dependencies - they can't appear in the inst/ directory + dependencies { + exclude("org.slf4j:slf4j-api") + exclude("io.opentelemetry:opentelemetry-api") + exclude("io.opentelemetry:opentelemetry-api-logs") + exclude("io.opentelemetry:opentelemetry-context") + exclude("io.opentelemetry:opentelemetry-semconv") + } + } + + // 2. the distro javaagent libs are then isolated - moved to the inst/ directory + // having a separate task for isolating javaagent libs is required to avoid duplicates with the upstream javaagent + // duplicatesStrategy in shadowJar won't be applied when adding files with with(CopySpec) because each CopySpec has + // its own duplicatesStrategy + create("isolateJavaagentLibs", Copy::class.java) { + dependsOn(findByName("relocateJavaagentLibs")) + with(isolateClasses(findByName("relocateJavaagentLibs")!!.outputs.files)) + + into("$buildDir/isolated/javaagentLibs") + } + + // 3. the relocated and isolated javaagent libs are merged together with the bootstrap libs (which undergo relocation + // in this task) and the upstream javaagent jar; duplicates are removed + shadowJar { + configurations = listOf(bootstrapLibs, upstreamAgent) + + dependsOn(findByName("isolateJavaagentLibs")) + from(findByName("isolateJavaagentLibs")!!.outputs) + + archiveClassifier.set("") + + duplicatesStrategy = DuplicatesStrategy.FAIL + + mergeServiceFiles { + include("inst/META-INF/services/*") + } + exclude("**/module-info.class") + relocatePackages(this) + + manifest { + attributes.put("Main-Class", "io.opentelemetry.javaagent.OpenTelemetryAgent") + attributes.put("Agent-Class", "io.opentelemetry.javaagent.OpenTelemetryAgent") + attributes.put("Premain-Class", "io.opentelemetry.javaagent.OpenTelemetryAgent") + attributes.put("Can-Redefine-Classes", "true") + attributes.put("Can-Retransform-Classes", "true") + attributes.put("Implementation-Vendor", "Demo") + attributes.put("Implementation-Version", "demo-${project.version}-otel-${Config.Libs.otelJavaagentVersion}") + } + } + + assemble { + dependsOn(shadowJar) + } +} diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/api/sentry-opentelemetry-agentcustomization.api b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/api/sentry-opentelemetry-agentcustomization.api new file mode 100644 index 0000000000..edc0693040 --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/api/sentry-opentelemetry-agentcustomization.api @@ -0,0 +1,10 @@ +public final class io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider : io/opentelemetry/sdk/autoconfigure/spi/AutoConfigurationCustomizerProvider { + public fun ()V + public fun customize (Lio/opentelemetry/sdk/autoconfigure/spi/AutoConfigurationCustomizer;)V +} + +public final class io/sentry/opentelemetry/SentryBootstrapPackagesProvider : io/opentelemetry/javaagent/tooling/bootstrap/BootstrapPackagesConfigurer { + public fun ()V + public fun configure (Lio/opentelemetry/javaagent/tooling/bootstrap/BootstrapPackagesBuilder;Lio/opentelemetry/sdk/autoconfigure/spi/ConfigProperties;)V +} + diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/build.gradle.kts b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/build.gradle.kts new file mode 100644 index 0000000000..0b0dc08ca1 --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/build.gradle.kts @@ -0,0 +1,78 @@ +import net.ltgt.gradle.errorprone.errorprone +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + `java-library` + kotlin("jvm") + jacoco + id(Config.QualityPlugins.errorProne) + id(Config.QualityPlugins.gradleVersions) +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType().configureEach { + kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString() +} + +dependencies { + compileOnly(projects.sentry) + implementation(projects.sentryOpentelemetry.sentryOpentelemetryCore) + + compileOnly("io.opentelemetry:opentelemetry-sdk:${Config.Libs.otelVersion}") + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:${Config.Libs.otelVersion}") + compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api:${Config.Libs.otelJavaagentAlphaVersion}") + compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:${Config.Libs.otelJavaagentAlphaVersion}") + + compileOnly(Config.CompileOnly.nopen) + errorprone(Config.CompileOnly.nopenChecker) + errorprone(Config.CompileOnly.errorprone) + compileOnly(Config.CompileOnly.jetbrainsAnnotations) + errorprone(Config.CompileOnly.errorProneNullAway) + + // tests + testImplementation(projects.sentryTestSupport) + testImplementation(kotlin(Config.kotlinStdLib)) + testImplementation(Config.TestLibs.kotlinTestJunit) + testImplementation(Config.TestLibs.mockitoKotlin) + testImplementation(Config.TestLibs.awaitility) +} + +configure { + test { + java.srcDir("src/test/java") + } +} + +jacoco { + toolVersion = Config.QualityPlugins.Jacoco.version +} + +tasks.jacocoTestReport { + reports { + xml.isEnabled = true + html.isEnabled = false + } +} + +tasks { + jacocoTestCoverageVerification { + violationRules { + rule { limit { minimum = Config.QualityPlugins.Jacoco.minimumCoverage } } + } + } + check { + dependsOn(jacocoTestCoverageVerification) + dependsOn(jacocoTestReport) + } +} + +tasks.withType().configureEach { + options.errorprone { + check("NullAway", net.ltgt.gradle.errorprone.CheckSeverity.ERROR) + option("NullAway:AnnotatedPackages", "io.sentry") + } +} diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java new file mode 100644 index 0000000000..83b8d52635 --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryAutoConfigurationCustomizerProvider.java @@ -0,0 +1,31 @@ +package io.sentry.opentelemetry; + +import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; +import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; + +public final class SentryAutoConfigurationCustomizerProvider + implements AutoConfigurationCustomizerProvider { + + @Override + public void customize(AutoConfigurationCustomizer autoConfiguration) { + autoConfiguration.addTracerProviderCustomizer(this::configureSdkTracerProvider); + // .addPropertiesSupplier(this::getDefaultProperties); + } + + private SdkTracerProviderBuilder configureSdkTracerProvider( + SdkTracerProviderBuilder tracerProvider, ConfigProperties config) { + + return tracerProvider.addSpanProcessor(new SentrySpanProcessor()); + } + + // private Map getDefaultProperties() { + // Map properties = new HashMap<>(); + // properties.put("otel.exporter.otlp.endpoint", "http://backend:8080"); + // properties.put("otel.exporter.otlp.insecure", "true"); + // properties.put("otel.config.max.attrs", "16"); + // properties.put("otel.traces.sampler", "demo"); + // return properties; + // } +} diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryBootstrapPackagesProvider.java b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryBootstrapPackagesProvider.java new file mode 100644 index 0000000000..231a0af847 --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/java/io/sentry/opentelemetry/SentryBootstrapPackagesProvider.java @@ -0,0 +1,21 @@ +package io.sentry.opentelemetry; + +import io.opentelemetry.javaagent.tooling.bootstrap.BootstrapPackagesBuilder; +import io.opentelemetry.javaagent.tooling.bootstrap.BootstrapPackagesConfigurer; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.sentry.Sentry; + +/** + * To ensure that the classes we add to bootstrap class loader are available in class loaders that + * don't delegate all class loading requests to bootstrap class loader e.g. OSGi we need to tell the + * agent which packages we have added. + * + * @see BootstrapPackagesConfigurer + */ +public final class SentryBootstrapPackagesProvider implements BootstrapPackagesConfigurer { + + @Override + public void configure(BootstrapPackagesBuilder builder, ConfigProperties config) { + builder.add(Sentry.class.getPackage().getName()); + } +} diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/resources/META-INF/services/io.opentelemetry.javaagent.tooling.bootstrap.BootstrapPackagesConfigurer b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/resources/META-INF/services/io.opentelemetry.javaagent.tooling.bootstrap.BootstrapPackagesConfigurer new file mode 100644 index 0000000000..4733b4591e --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/resources/META-INF/services/io.opentelemetry.javaagent.tooling.bootstrap.BootstrapPackagesConfigurer @@ -0,0 +1 @@ +io.sentry.opentelemetry.SentryBootstrapPackagesProvider diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider new file mode 100644 index 0000000000..ba7c0a3190 --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-agentcustomization/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider @@ -0,0 +1 @@ +io.sentry.opentelemetry.SentryAutoConfigurationCustomizerProvider diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api b/sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api new file mode 100644 index 0000000000..7e54158bf6 --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-core/api/sentry-opentelemetry-core.api @@ -0,0 +1,8 @@ +public final class io/sentry/opentelemetry/SentrySpanProcessor : io/opentelemetry/sdk/trace/SpanProcessor { + public fun ()V + public fun isEndRequired ()Z + public fun isStartRequired ()Z + public fun onEnd (Lio/opentelemetry/sdk/trace/ReadableSpan;)V + public fun onStart (Lio/opentelemetry/context/Context;Lio/opentelemetry/sdk/trace/ReadWriteSpan;)V +} + diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/build.gradle.kts b/sentry-opentelemetry/sentry-opentelemetry-core/build.gradle.kts new file mode 100644 index 0000000000..8dcfc8389b --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-core/build.gradle.kts @@ -0,0 +1,74 @@ +import net.ltgt.gradle.errorprone.errorprone +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + `java-library` + kotlin("jvm") + jacoco + id(Config.QualityPlugins.errorProne) + id(Config.QualityPlugins.gradleVersions) +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType().configureEach { + kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString() +} + +dependencies { + compileOnly(projects.sentry) + + compileOnly("io.opentelemetry:opentelemetry-sdk:${Config.Libs.otelVersion}") + + compileOnly(Config.CompileOnly.nopen) + errorprone(Config.CompileOnly.nopenChecker) + errorprone(Config.CompileOnly.errorprone) + compileOnly(Config.CompileOnly.jetbrainsAnnotations) + errorprone(Config.CompileOnly.errorProneNullAway) + + // tests + testImplementation(projects.sentryTestSupport) + testImplementation(kotlin(Config.kotlinStdLib)) + testImplementation(Config.TestLibs.kotlinTestJunit) + testImplementation(Config.TestLibs.mockitoKotlin) + testImplementation(Config.TestLibs.awaitility) +} + +configure { + test { + java.srcDir("src/test/java") + } +} + +jacoco { + toolVersion = Config.QualityPlugins.Jacoco.version +} + +tasks.jacocoTestReport { + reports { + xml.isEnabled = true + html.isEnabled = false + } +} + +tasks { + jacocoTestCoverageVerification { + violationRules { + rule { limit { minimum = Config.QualityPlugins.Jacoco.minimumCoverage } } + } + } + check { + dependsOn(jacocoTestCoverageVerification) + dependsOn(jacocoTestReport) + } +} + +tasks.withType().configureEach { + options.errorprone { + check("NullAway", net.ltgt.gradle.errorprone.CheckSeverity.ERROR) + option("NullAway:AnnotatedPackages", "io.sentry") + } +} diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java new file mode 100644 index 0000000000..383cb11af0 --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java @@ -0,0 +1,35 @@ +package io.sentry.opentelemetry; + +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.ReadWriteSpan; +import io.opentelemetry.sdk.trace.ReadableSpan; +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.sentry.Sentry; + +@SuppressWarnings("CatchAndPrintStackTrace") +public final class SentrySpanProcessor implements SpanProcessor { + + @Override + public void onStart(Context parentContext, ReadWriteSpan span) { + System.out.println( + "hello from onStart " + Thread.currentThread().getId() + Sentry.getCurrentHub().toString()); + // TODO start + } + + @Override + public boolean isStartRequired() { + return true; + } + + @Override + public void onEnd(ReadableSpan span) { + System.out.println( + "hello from onEnd" + Thread.currentThread().getId() + Sentry.getCurrentHub().toString()); + // TODO end + } + + @Override + public boolean isEndRequired() { + return true; + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index d7dfb5c352..bc7b65baa9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -38,6 +38,9 @@ include( "sentry-openfeign", "sentry-graphql", "sentry-jdbc", + "sentry-opentelemetry:sentry-opentelemetry-core", + "sentry-opentelemetry:sentry-opentelemetry-agentcustomization", + "sentry-opentelemetry:sentry-opentelemetry-agent", "sentry-samples:sentry-samples-android", "sentry-samples:sentry-samples-console", "sentry-samples:sentry-samples-jul", From 0ee226e29743d2640e987f1d2481d82339fee257 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 8 Nov 2022 12:02:46 +0100 Subject: [PATCH 2/3] Add new modules in files --- .craft.yml | 3 ++ .github/ISSUE_TEMPLATE/bug_report_java.yml | 2 + README.md | 59 ++++++++++++---------- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/.craft.yml b/.craft.yml index 6ca89b13ca..ee94d4d7dd 100644 --- a/.craft.yml +++ b/.craft.yml @@ -40,6 +40,9 @@ targets: maven:io.sentry:sentry-android-fragment: maven:io.sentry:sentry-bom: maven:io.sentry:sentry-openfeign: + maven:io.sentry:sentry-opentelemetry-agent: + maven:io.sentry:sentry-opentelemetry-agentcustomization: + maven:io.sentry:sentry-opentelemetry-core: maven:io.sentry:sentry-apollo: maven:io.sentry:sentry-jdbc: maven:io.sentry:sentry-graphql: diff --git a/.github/ISSUE_TEMPLATE/bug_report_java.yml b/.github/ISSUE_TEMPLATE/bug_report_java.yml index 34dab19b01..ef030cbf43 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_java.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_java.yml @@ -14,6 +14,8 @@ body: - sentry-apollo - sentry-apollo-3 - sentry-kotlin-extensions + - sentry-opentelemetry-agent + - sentry-opentelemetry-core - sentry-servlet - sentry-servlet-jakarta - sentry-spring-boot-starter diff --git a/README.md b/README.md index 802a6189b0..52d005225e 100644 --- a/README.md +++ b/README.md @@ -16,33 +16,38 @@ Sentry SDK for Java and Android [![codecov](https://codecov.io/gh/getsentry/sentry-java/branch/main/graph/badge.svg)](https://codecov.io/gh/getsentry/sentry-java) [![Discord Chat](https://img.shields.io/discord/621778831602221064?logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/PXa5Apfe7K) -| Packages | Maven Central | Android API | -| ---------------------- | ------- | ------- | -| sentry-android | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android) | 16 | -| sentry-android-core | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-core) | 14 | -| sentry-android-ndk | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-ndk/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-ndk) | 16 | -| sentry-android-okhttp | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-okhttp/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-okhttp) | 21 | -| sentry-android-timber | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-timber/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-timber) | 14 | -| sentry-android-fragment | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-fragment/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-fragment) | 14 | -| sentry-android-navigation | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-navigation/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-navigation) | 14 | -| sentry-compose-android | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose-android/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose-android) | 21 | -| sentry-compose-desktop | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose-desktop/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose-desktop) | -| sentry-compose | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose) | -| sentry-apache-http-client-5 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apache-http-client-5/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apache-http-client-5) | -| sentry | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry) | 14 | -| sentry-jul | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-jul/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-jul) | -| sentry-jdbc | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-jdbc/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-jdbc) | -| sentry-apollo | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apollo/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apollo) | 14 | -| sentry-kotlin-extensions | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-kotlin-extensions/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-kotlin-extensions) | 14 | -| sentry-servlet | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet) | | -| sentry-servlet-jakarta | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet-jakarta/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet-jakarta) | | -| sentry-spring-boot-starter | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring-boot-starter/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring-boot-starter) | -| sentry-spring | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring) | -| sentry-logback | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-logback/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-logback) | -| sentry-log4j2 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-log4j2/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-log4j2) | -| sentry-bom | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-bom/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-bom) | -| sentry-graphql | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-graphql/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-graphql) | -| sentry-openfeign | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-openfeign/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-openfeign) | +| Packages | Maven Central | Android API | +|-----------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------- | +| sentry-android | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android) | 16 | +| sentry-android-core | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-core) | 14 | +| sentry-android-ndk | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-ndk/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-ndk) | 16 | +| sentry-android-okhttp | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-okhttp/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-okhttp) | 21 | +| sentry-android-timber | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-timber/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-timber) | 14 | +| sentry-android-fragment | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-fragment/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-fragment) | 14 | +| sentry-android-navigation | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-navigation/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-android-navigation) | 14 | +| sentry-compose-android | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose-android/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose-android) | 21 | +| sentry-compose-desktop | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose-desktop/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose-desktop) | +| sentry-compose | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-compose) | +| sentry-apache-http-client-5 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apache-http-client-5/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apache-http-client-5) | +| sentry | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry) | 14 | +| sentry-jul | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-jul/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-jul) | +| sentry-jdbc | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-jdbc/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-jdbc) | +| sentry-apollo | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apollo/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-apollo) | 14 | +| sentry-kotlin-extensions | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-kotlin-extensions/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-kotlin-extensions) | 14 | +| sentry-servlet | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet) | | +| sentry-servlet-jakarta | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet-jakarta/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-servlet-jakarta) | | +| sentry-spring-boot-starter | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring-boot-starter/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring-boot-starter) | +| sentry-spring-boot-starter-jakarta | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring-boot-starter-jakarta/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring-boot-starter-jakarta) | +| sentry-spring | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring) | +| sentry-spring-jakarta | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring-jakarta/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-spring-jakarta) | +| sentry-logback | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-logback/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-logback) | +| sentry-log4j2 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-log4j2/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-log4j2) | +| sentry-bom | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-bom/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-bom) | +| sentry-graphql | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-graphql/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-graphql) | +| sentry-openfeign | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-openfeign/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-openfeign) | +| sentry-opentelemetry-agent | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-opentelemetry-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-opentelemetry-agent) | +| sentry-opentelemetry-agentcustomization | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-opentelemetry-agentcustomization/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-opentelemetry-agentcustomization) | +| sentry-opentelemetry-core | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-opentelemetry-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.sentry/sentry-opentelemetry-core) | From ef5e638e726d9d020795185b007b4a836d54a3c8 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Wed, 9 Nov 2022 10:23:36 +0100 Subject: [PATCH 3/3] Add instrumenter option --- .../core/ActivityLifecycleIntegration.java | 6 +++- sentry/api/sentry.api | 21 ++++++++--- sentry/src/main/java/io/sentry/Hub.java | 9 +++++ sentry/src/main/java/io/sentry/ISpan.java | 5 ++- .../src/main/java/io/sentry/Instrumenter.java | 12 +++++++ sentry/src/main/java/io/sentry/NoOpSpan.java | 5 ++- .../main/java/io/sentry/NoOpTransaction.java | 5 ++- .../main/java/io/sentry/SentryOptions.java | 25 +++++++++++++ .../src/main/java/io/sentry/SentryTracer.java | 34 +++++++++++++----- sentry/src/main/java/io/sentry/Span.java | 6 ++-- .../java/io/sentry/TransactionContext.java | 9 +++++ sentry/src/test/java/io/sentry/HubTest.kt | 35 +++++++++++++++++++ .../test/java/io/sentry/InstrumenterTest.kt | 19 ++++++++++ sentry/src/test/java/io/sentry/SpanTest.kt | 26 +++++++++++--- 14 files changed, 193 insertions(+), 24 deletions(-) create mode 100644 sentry/src/main/java/io/sentry/Instrumenter.java create mode 100644 sentry/src/test/java/io/sentry/InstrumenterTest.kt diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java index a307b01679..62be5a39e0 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java @@ -15,6 +15,7 @@ import io.sentry.IHub; import io.sentry.ISpan; import io.sentry.ITransaction; +import io.sentry.Instrumenter; import io.sentry.Integration; import io.sentry.Scope; import io.sentry.SentryLevel; @@ -197,7 +198,10 @@ private void startTracing(final @NotNull Activity activity) { // start specific span for app start appStartSpan = transaction.startChild( - getAppStartOp(coldStart), getAppStartDesc(coldStart), appStartTime); + getAppStartOp(coldStart), + getAppStartDesc(coldStart), + appStartTime, + Instrumenter.SENTRY); } // lets bind to the scope so other integrations can pick it up diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 4d5c9ee87f..ba0252ab56 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -502,7 +502,7 @@ public abstract interface class io/sentry/ISpan { public abstract fun setThrowable (Ljava/lang/Throwable;)V public abstract fun startChild (Ljava/lang/String;)Lio/sentry/ISpan; public abstract fun startChild (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ISpan; - public abstract fun startChild (Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;)Lio/sentry/ISpan; + public abstract fun startChild (Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;Lio/sentry/Instrumenter;)Lio/sentry/ISpan; public abstract fun toBaggageHeader (Ljava/util/List;)Lio/sentry/BaggageHeader; public abstract fun toSentryTrace ()Lio/sentry/SentryTraceHeader; public abstract fun traceContext ()Lio/sentry/TraceContext; @@ -531,6 +531,13 @@ public abstract interface class io/sentry/ITransportFactory { public abstract fun create (Lio/sentry/SentryOptions;Lio/sentry/RequestDetails;)Lio/sentry/transport/ITransport; } +public final class io/sentry/Instrumenter : java/lang/Enum { + public static final field OTEL Lio/sentry/Instrumenter; + public static final field SENTRY Lio/sentry/Instrumenter; + public static fun valueOf (Ljava/lang/String;)Lio/sentry/Instrumenter; + public static fun values ()[Lio/sentry/Instrumenter; +} + public abstract interface class io/sentry/Integration { public abstract fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V } @@ -740,7 +747,7 @@ public final class io/sentry/NoOpSpan : io/sentry/ISpan { public fun setThrowable (Ljava/lang/Throwable;)V public fun startChild (Ljava/lang/String;)Lio/sentry/ISpan; public fun startChild (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ISpan; - public fun startChild (Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;)Lio/sentry/ISpan; + public fun startChild (Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;Lio/sentry/Instrumenter;)Lio/sentry/ISpan; public fun toBaggageHeader (Ljava/util/List;)Lio/sentry/BaggageHeader; public fun toSentryTrace ()Lio/sentry/SentryTraceHeader; public fun traceContext ()Lio/sentry/TraceContext; @@ -779,7 +786,7 @@ public final class io/sentry/NoOpTransaction : io/sentry/ITransaction { public fun setThrowable (Ljava/lang/Throwable;)V public fun startChild (Ljava/lang/String;)Lio/sentry/ISpan; public fun startChild (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ISpan; - public fun startChild (Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;)Lio/sentry/ISpan; + public fun startChild (Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;Lio/sentry/Instrumenter;)Lio/sentry/ISpan; public fun toBaggageHeader (Ljava/util/List;)Lio/sentry/BaggageHeader; public fun toSentryTrace ()Lio/sentry/SentryTraceHeader; public fun traceContext ()Lio/sentry/TraceContext; @@ -1369,6 +1376,7 @@ public class io/sentry/SentryOptions { public fun getIgnoredExceptionsForType ()Ljava/util/Set; public fun getInAppExcludes ()Ljava/util/List; public fun getInAppIncludes ()Ljava/util/List; + public fun getInstrumenter ()Lio/sentry/Instrumenter; public fun getIntegrations ()Ljava/util/List; public fun getLogger ()Lio/sentry/ILogger; public fun getMaxAttachmentSize ()J @@ -1449,6 +1457,7 @@ public class io/sentry/SentryOptions { public fun setFlushTimeoutMillis (J)V public fun setHostnameVerifier (Ljavax/net/ssl/HostnameVerifier;)V public fun setIdleTimeout (Ljava/lang/Long;)V + public fun setInstrumenter (Lio/sentry/Instrumenter;)V public fun setLogger (Lio/sentry/ILogger;)V public fun setMaxAttachmentSize (J)V public fun setMaxBreadcrumbs (I)V @@ -1578,7 +1587,7 @@ public final class io/sentry/SentryTracer : io/sentry/ITransaction { public fun setThrowable (Ljava/lang/Throwable;)V public fun startChild (Ljava/lang/String;)Lio/sentry/ISpan; public fun startChild (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ISpan; - public fun startChild (Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;)Lio/sentry/ISpan; + public fun startChild (Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;Lio/sentry/Instrumenter;)Lio/sentry/ISpan; public fun toBaggageHeader (Ljava/util/List;)Lio/sentry/BaggageHeader; public fun toSentryTrace ()Lio/sentry/SentryTraceHeader; public fun traceContext ()Lio/sentry/TraceContext; @@ -1684,7 +1693,7 @@ public final class io/sentry/Span : io/sentry/ISpan { public fun setThrowable (Ljava/lang/Throwable;)V public fun startChild (Ljava/lang/String;)Lio/sentry/ISpan; public fun startChild (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/ISpan; - public fun startChild (Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;)Lio/sentry/ISpan; + public fun startChild (Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;Lio/sentry/Instrumenter;)Lio/sentry/ISpan; public fun toBaggageHeader (Ljava/util/List;)Lio/sentry/BaggageHeader; public fun toSentryTrace ()Lio/sentry/SentryTraceHeader; public fun traceContext ()Lio/sentry/TraceContext; @@ -1848,10 +1857,12 @@ public final class io/sentry/TransactionContext : io/sentry/SpanContext { public static fun fromSentryTrace (Ljava/lang/String;Lio/sentry/protocol/TransactionNameSource;Ljava/lang/String;Lio/sentry/SentryTraceHeader;Lio/sentry/Baggage;)Lio/sentry/TransactionContext; public static fun fromSentryTrace (Ljava/lang/String;Ljava/lang/String;Lio/sentry/SentryTraceHeader;)Lio/sentry/TransactionContext; public fun getBaggage ()Lio/sentry/Baggage; + public fun getInstrumenter ()Lio/sentry/Instrumenter; public fun getName ()Ljava/lang/String; public fun getParentSampled ()Ljava/lang/Boolean; public fun getParentSamplingDecision ()Lio/sentry/TracesSamplingDecision; public fun getTransactionNameSource ()Lio/sentry/protocol/TransactionNameSource; + public fun setInstrumenter (Lio/sentry/Instrumenter;)V public fun setParentSampled (Ljava/lang/Boolean;)V public fun setParentSampled (Ljava/lang/Boolean;Ljava/lang/Boolean;)V } diff --git a/sentry/src/main/java/io/sentry/Hub.java b/sentry/src/main/java/io/sentry/Hub.java index c573b45c12..c97cd98dc1 100644 --- a/sentry/src/main/java/io/sentry/Hub.java +++ b/sentry/src/main/java/io/sentry/Hub.java @@ -699,6 +699,15 @@ public void flush(long timeoutMillis) { SentryLevel.WARNING, "Instance is disabled and this 'startTransaction' returns a no-op."); transaction = NoOpTransaction.getInstance(); + } else if (!options.getInstrumenter().equals(transactionContext.getInstrumenter())) { + options + .getLogger() + .log( + SentryLevel.DEBUG, + "Returning no-op for instrumenter %s as the SDK has been configured to use instrumenter %s", + transactionContext.getInstrumenter(), + options.getInstrumenter()); + transaction = NoOpTransaction.getInstance(); } else if (!options.isTracingEnabled()) { options .getLogger() diff --git a/sentry/src/main/java/io/sentry/ISpan.java b/sentry/src/main/java/io/sentry/ISpan.java index ab4bfdffe5..b32e434853 100644 --- a/sentry/src/main/java/io/sentry/ISpan.java +++ b/sentry/src/main/java/io/sentry/ISpan.java @@ -20,7 +20,10 @@ public interface ISpan { @ApiStatus.Internal @NotNull ISpan startChild( - @NotNull String operation, @Nullable String description, @Nullable Date timestamp); + @NotNull String operation, + @Nullable String description, + @Nullable Date timestamp, + @NotNull Instrumenter instrumenter); /** * Starts a child Span. diff --git a/sentry/src/main/java/io/sentry/Instrumenter.java b/sentry/src/main/java/io/sentry/Instrumenter.java new file mode 100644 index 0000000000..f72535bde8 --- /dev/null +++ b/sentry/src/main/java/io/sentry/Instrumenter.java @@ -0,0 +1,12 @@ +package io.sentry; + +/** + * Which framework is responsible for instrumenting. This includes starting and stopping of + * transactions and spans. + */ +public enum Instrumenter { + SENTRY, + + /** OpenTelemetry */ + OTEL +} diff --git a/sentry/src/main/java/io/sentry/NoOpSpan.java b/sentry/src/main/java/io/sentry/NoOpSpan.java index 08388f8368..4a3a475236 100644 --- a/sentry/src/main/java/io/sentry/NoOpSpan.java +++ b/sentry/src/main/java/io/sentry/NoOpSpan.java @@ -23,7 +23,10 @@ public static NoOpSpan getInstance() { @Override public @NotNull ISpan startChild( - @NotNull String operation, @Nullable String description, @Nullable Date timestamp) { + @NotNull String operation, + @Nullable String description, + @Nullable Date timestamp, + @NotNull Instrumenter instrumenter) { return NoOpSpan.getInstance(); } diff --git a/sentry/src/main/java/io/sentry/NoOpTransaction.java b/sentry/src/main/java/io/sentry/NoOpTransaction.java index a3ca631a3b..26f2850cdb 100644 --- a/sentry/src/main/java/io/sentry/NoOpTransaction.java +++ b/sentry/src/main/java/io/sentry/NoOpTransaction.java @@ -43,7 +43,10 @@ public void setName(@NotNull String name, @NotNull TransactionNameSource transac @Override public @NotNull ISpan startChild( - @NotNull String operation, @Nullable String description, @Nullable Date timestamp) { + @NotNull String operation, + @Nullable String description, + @Nullable Date timestamp, + @NotNull Instrumenter instrumenter) { return NoOpSpan.getInstance(); } diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index e7c0980c2b..16f5aa6437 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -361,6 +361,9 @@ public class SentryOptions { /** Modules (dependencies, packages) that will be send along with each event. */ private @NotNull IModulesLoader modulesLoader = NoOpModulesLoader.getInstance(); + /** Which framework is responsible for instrumenting. */ + private @NotNull Instrumenter instrumenter = Instrumenter.SENTRY; + /** * Adds an event processor * @@ -1741,6 +1744,28 @@ public void setSendClientReports(boolean sendClientReports) { } } + /** + * Sets the instrumenter used for performance instrumentation. + * + *

If you set this to something other than {{@link Instrumenter#SENTRY}} Sentry will not create + * any transactions automatically nor will it create transactions if you call + * startTransaction(...), nor will it create child spans if you call startChild(...) + * + * @param instrumenter - the instrumenter to use + */ + public void setInstrumenter(final @NotNull Instrumenter instrumenter) { + this.instrumenter = instrumenter; + } + + /** + * Returns the instrumenter used for performance instrumentation + * + * @return the configured instrumenter + */ + public @NotNull Instrumenter getInstrumenter() { + return instrumenter; + } + /** * Returns a ClientReportRecorder or a NoOp if sending of client reports has been disabled. * diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index 6d5c069992..29a65153d8 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -77,6 +77,7 @@ public final class SentryTracer implements ITransaction { private final @NotNull Baggage baggage; private @NotNull TransactionNameSource transactionNameSource; private final @NotNull Map measurements; + private final @NotNull Instrumenter instrumenter; public SentryTracer(final @NotNull TransactionContext context, final @NotNull IHub hub) { this(context, hub, null); @@ -110,6 +111,7 @@ public SentryTracer( this.measurements = new ConcurrentHashMap<>(); this.root = new Span(context, this, hub, startTimestamp); this.name = context.getName(); + this.instrumenter = context.getInstrumenter(); this.hub = hub; this.waitForChildren = waitForChildren; this.idleTimeout = idleTimeout; @@ -195,8 +197,9 @@ ISpan startChild( final @NotNull SpanId parentSpanId, final @NotNull String operation, final @Nullable String description, - final @Nullable Date timestamp) { - return createChild(parentSpanId, operation, description, timestamp); + final @Nullable Date timestamp, + final @NotNull Instrumenter instrumenter) { + return createChild(parentSpanId, operation, description, timestamp, instrumenter); } /** @@ -207,7 +210,7 @@ ISpan startChild( */ @NotNull private ISpan createChild(final @NotNull SpanId parentSpanId, final @NotNull String operation) { - return createChild(parentSpanId, operation, null, null); + return createChild(parentSpanId, operation, null, null, Instrumenter.SENTRY); } @NotNull @@ -215,11 +218,16 @@ private ISpan createChild( final @NotNull SpanId parentSpanId, final @NotNull String operation, final @Nullable String description, - @Nullable Date timestamp) { + @Nullable Date timestamp, + final @NotNull Instrumenter instrumenter) { if (root.isFinished()) { return NoOpSpan.getInstance(); } + if (!this.instrumenter.equals(instrumenter)) { + return NoOpSpan.getInstance(); + } + Objects.requireNonNull(parentSpanId, "parentSpanId is required"); Objects.requireNonNull(operation, "operation is required"); cancelTimer(); @@ -256,26 +264,34 @@ private ISpan createChild( @Override public @NotNull ISpan startChild( - final @NotNull String operation, @Nullable String description, @Nullable Date timestamp) { - return createChild(operation, description, timestamp); + final @NotNull String operation, + @Nullable String description, + @Nullable Date timestamp, + @NotNull Instrumenter instrumenter) { + return createChild(operation, description, timestamp, instrumenter); } @Override public @NotNull ISpan startChild( final @NotNull String operation, final @Nullable String description) { - return createChild(operation, description, null); + return createChild(operation, description, null, Instrumenter.SENTRY); } private @NotNull ISpan createChild( final @NotNull String operation, final @Nullable String description, - @Nullable Date timestamp) { + @Nullable Date timestamp, + final @NotNull Instrumenter instrumenter) { if (root.isFinished()) { return NoOpSpan.getInstance(); } + if (!this.instrumenter.equals(instrumenter)) { + return NoOpSpan.getInstance(); + } + if (children.size() < hub.getOptions().getMaxSpans()) { - return root.startChild(operation, description, timestamp); + return root.startChild(operation, description, timestamp, instrumenter); } else { hub.getOptions() .getLogger() diff --git a/sentry/src/main/java/io/sentry/Span.java b/sentry/src/main/java/io/sentry/Span.java index b149fac379..828cab7782 100644 --- a/sentry/src/main/java/io/sentry/Span.java +++ b/sentry/src/main/java/io/sentry/Span.java @@ -117,12 +117,14 @@ public Span( public @NotNull ISpan startChild( final @NotNull String operation, final @Nullable String description, - final @Nullable Date timestamp) { + final @Nullable Date timestamp, + final @NotNull Instrumenter instrumenter) { if (finished.get()) { return NoOpSpan.getInstance(); } - return transaction.startChild(context.getSpanId(), operation, description, timestamp); + return transaction.startChild( + context.getSpanId(), operation, description, timestamp, instrumenter); } @Override diff --git a/sentry/src/main/java/io/sentry/TransactionContext.java b/sentry/src/main/java/io/sentry/TransactionContext.java index e941621112..c52ad60144 100644 --- a/sentry/src/main/java/io/sentry/TransactionContext.java +++ b/sentry/src/main/java/io/sentry/TransactionContext.java @@ -12,6 +12,7 @@ public final class TransactionContext extends SpanContext { private final @NotNull TransactionNameSource transactionNameSource; private @Nullable TracesSamplingDecision parentSamplingDecision; private @Nullable Baggage baggage; + private @NotNull Instrumenter instrumenter = Instrumenter.SENTRY; /** * Creates {@link TransactionContext} from sentry-trace header. @@ -203,4 +204,12 @@ public void setParentSampled( public @NotNull TransactionNameSource getTransactionNameSource() { return transactionNameSource; } + + public @NotNull Instrumenter getInstrumenter() { + return instrumenter; + } + + public void setInstrumenter(final @NotNull Instrumenter instrumenter) { + this.instrumenter = instrumenter; + } } diff --git a/sentry/src/test/java/io/sentry/HubTest.kt b/sentry/src/test/java/io/sentry/HubTest.kt index f5fb838d9f..dfeccb12c0 100644 --- a/sentry/src/test/java/io/sentry/HubTest.kt +++ b/sentry/src/test/java/io/sentry/HubTest.kt @@ -906,6 +906,41 @@ class HubTest { assertEquals("test", scope?.transactionName) } + + @Test + fun `when startTransaction is called with different instrumenter, no-op is returned`() { + val hub = generateHub() + + val transactionContext = TransactionContext("test", "op").also { it.instrumenter = Instrumenter.OTEL } + val transactionOptions = TransactionOptions() + val tx = hub.startTransaction(transactionContext, transactionOptions) + + assertTrue(tx is NoOpTransaction) + } + + @Test + fun `when startTransaction is called with different instrumenter, no-op is returned 2`() { + val hub = generateHub() { + it.instrumenter = Instrumenter.OTEL + } + + val tx = hub.startTransaction("test", "op") + + assertTrue(tx is NoOpTransaction) + } + + @Test + fun `when startTransaction is called with configured instrumenter, it works`() { + val hub = generateHub() { + it.instrumenter = Instrumenter.OTEL + } + + val transactionContext = TransactionContext("test", "op").also { it.instrumenter = Instrumenter.OTEL } + val transactionOptions = TransactionOptions() + val tx = hub.startTransaction(transactionContext, transactionOptions) + + assertFalse(tx is NoOpTransaction) + } //endregion //region setUser tests diff --git a/sentry/src/test/java/io/sentry/InstrumenterTest.kt b/sentry/src/test/java/io/sentry/InstrumenterTest.kt new file mode 100644 index 0000000000..529f637c4e --- /dev/null +++ b/sentry/src/test/java/io/sentry/InstrumenterTest.kt @@ -0,0 +1,19 @@ +package io.sentry + +import kotlin.test.Test +import kotlin.test.assertEquals + +class InstrumenterTest { + + @Test + fun `can create from otel string`() { + val instrumenter = Instrumenter.valueOf("OTEL") + assertEquals(instrumenter, Instrumenter.OTEL) + } + + @Test + fun `can create from sentry string`() { + val instrumenter = Instrumenter.valueOf("SENTRY") + assertEquals(instrumenter, Instrumenter.SENTRY) + } +} diff --git a/sentry/src/test/java/io/sentry/SpanTest.kt b/sentry/src/test/java/io/sentry/SpanTest.kt index 9f21645ffe..f1823b1877 100644 --- a/sentry/src/test/java/io/sentry/SpanTest.kt +++ b/sentry/src/test/java/io/sentry/SpanTest.kt @@ -63,7 +63,7 @@ class SpanTest { @Test fun `when span is created with a start timestamp, finish timestamp is equals to high precision timestamp`() { - val span = fixture.getSut().startChild("op", "desc", Date()) as Span + val span = fixture.getSut().startChild("op", "desc", Date(), Instrumenter.SENTRY) as Span span.finish() assertNotNull(span.timestamp) @@ -140,6 +140,24 @@ class SpanTest { assertEquals(2, transaction.spans.size) } + @Test + fun `starting a child with different instrumenter no-ops`() { + val transaction = getTransaction(TransactionContext("name", "op").also { it.instrumenter = Instrumenter.OTEL }) + val span = transaction.startChild("operation", "description") + + span.startChild("op") + assertEquals(0, transaction.spans.size) + } + + @Test + fun `starting a child with same instrumenter adds span to transaction`() { + val transaction = getTransaction(TransactionContext("name", "op").also { it.instrumenter = Instrumenter.OTEL }) + val span = transaction.startChild("operation", "description", null, Instrumenter.OTEL) + + span.startChild("op", "desc", null, Instrumenter.OTEL) + assertEquals(2, transaction.spans.size) + } + @Test fun `when span was not finished, isFinished returns false`() { val span = startChildFromSpan() @@ -200,7 +218,7 @@ class SpanTest { span.finish(SpanStatus.OK) assertTrue(span.isFinished) - assertEquals(NoOpSpan.getInstance(), span.startChild("op", "desc", null)) + assertEquals(NoOpSpan.getInstance(), span.startChild("op", "desc", null, Instrumenter.SENTRY)) assertEquals(NoOpSpan.getInstance(), span.startChild("op", "desc")) span.finish(SpanStatus.UNKNOWN_ERROR) @@ -248,8 +266,8 @@ class SpanTest { } } - private fun getTransaction(): SentryTracer { - return SentryTracer(TransactionContext("name", "op"), fixture.hub) + private fun getTransaction(transactionContext: TransactionContext = TransactionContext("name", "op")): SentryTracer { + return SentryTracer(transactionContext, fixture.hub) } private fun startChildFromSpan(): Span {