From 08507dff16688fb4e5ca44946d8f50be73f1282c Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 6 Dec 2024 10:10:02 +0100 Subject: [PATCH 01/18] add agentless module for OpenTelemetry setup without any agent --- .craft.yml | 1 + .github/ISSUE_TEMPLATE/bug_report_java.yml | 1 + .../sentry-opentelemetry-agentless/README.md | 54 +++++++++++++++++++ .../build.gradle.kts | 18 +++++++ .../opentelemetry/agent/AgentlessMarker.java | 3 ++ .../build.gradle.kts | 9 +--- .../java/io/sentry/samples/console/Main.java | 3 ++ .../build.gradle.kts | 5 +- .../build.gradle.kts | 2 +- .../build.gradle.kts | 3 +- settings.gradle.kts | 1 + 11 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 sentry-opentelemetry/sentry-opentelemetry-agentless/README.md create mode 100644 sentry-opentelemetry/sentry-opentelemetry-agentless/build.gradle.kts create mode 100644 sentry-opentelemetry/sentry-opentelemetry-agentless/src/main/java/io/sentry/opentelemetry/agent/AgentlessMarker.java diff --git a/.craft.yml b/.craft.yml index 3d0a878a4c..72373fa343 100644 --- a/.craft.yml +++ b/.craft.yml @@ -44,6 +44,7 @@ targets: maven:io.sentry:sentry-opentelemetry-agent: maven:io.sentry:sentry-opentelemetry-agentcustomization: maven:io.sentry:sentry-opentelemetry-core: +# maven:io.sentry:sentry-opentelemetry-agentless: 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 f95244f5b1..98521cdd7a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_java.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_java.yml @@ -15,6 +15,7 @@ body: - sentry-apollo-3 - sentry-kotlin-extensions - sentry-opentelemetry-agent + - sentry-opentelemetry-agentless - sentry-opentelemetry-core - sentry-servlet - sentry-servlet-jakarta diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentless/README.md b/sentry-opentelemetry/sentry-opentelemetry-agentless/README.md new file mode 100644 index 0000000000..9ce3319bae --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-agentless/README.md @@ -0,0 +1,54 @@ +# sentry-opentelemetry-agentless + +*NOTE: Our OpenTelemetry modules are still experimental. Any feedback is welcome.* + +## How to use it + +Add the latest `sentry-opentelemetry-agentless` module as a dependency and add a `sentry.properties` +configuration file to your project that could look like this: + +```properties +# NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry project/dashboard +dsn=https://502f25099c204a2fbf4cb16edc5975d1@o447951.ingest.sentry.io/5428563 +traces-sample-rate=1.0 +``` + +For more details on configuring Sentry via `sentry.properties` please see the +[docs page](https://docs.sentry.io/platforms/java/configuration/). + +As an alternative to the `SENTRY_PROPERTIES_FILE` environment variable you can provide individual +settings as environment variables (e.g. `SENTRY_DSN=...`) or you may initialize `Sentry` inside +your target application. If you do so, please make sure to apply OpenTelemetry specific options, e.g. +like this: + +``` +Sentry.init( + options -> { + options.setDsn("..."); + ... + OpenTelemetryUtil.applyOpenTelemetryOptions(options, false); + } +) +``` + +## Getting rid of exporter error messages + +In case you are using this module without needing to use any OpenTelemetry exporters you can add +the following environment variables to turn off exporters and stop seeing error messages about +servers not being reachable in the logs. + +Example log message: +``` +ERROR io.opentelemetry.exporter.internal.grpc.OkHttpGrpcExporter - Failed to export spans. The request could not be executed. Full error message: Failed to connect to localhost/[0:0:0:0:0:0:0:1]:4317 +ERROR io.opentelemetry.exporter.internal.grpc.OkHttpGrpcExporter - Failed to export metrics. The request could not be executed. Full error message: Failed to connect to localhost/[0:0:0:0:0:0:0:1]:4317 +``` + +### Traces + +To turn off exporting of traces you can set `OTEL_TRACES_EXPORTER=none` +see [OpenTelemetry GitHub](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure#otlp-exporter-span-metric-and-log-exporters) + +### Metrics + +To turn off exporting of metrics you can set `OTEL_METRICS_EXPORTER=none` +see [OpenTelemetry GitHub](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure#otlp-exporter-span-metric-and-log-exporters) diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentless/build.gradle.kts b/sentry-opentelemetry/sentry-opentelemetry-agentless/build.gradle.kts new file mode 100644 index 0000000000..eeeb8c7e95 --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-agentless/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + `java-library` +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +dependencies { + api(projects.sentry) + api(projects.sentryOpentelemetry.sentryOpentelemetryBootstrap) + implementation(projects.sentryOpentelemetry.sentryOpentelemetryAgentcustomization) + api(Config.Libs.OpenTelemetry.otelSdk) + api(Config.Libs.OpenTelemetry.otelSemconv) + api(Config.Libs.OpenTelemetry.otelSemconvIncubating) + implementation(Config.Libs.OpenTelemetry.otelExtensionAutoconfigure) +} diff --git a/sentry-opentelemetry/sentry-opentelemetry-agentless/src/main/java/io/sentry/opentelemetry/agent/AgentlessMarker.java b/sentry-opentelemetry/sentry-opentelemetry-agentless/src/main/java/io/sentry/opentelemetry/agent/AgentlessMarker.java new file mode 100644 index 0000000000..ddb5101c29 --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-agentless/src/main/java/io/sentry/opentelemetry/agent/AgentlessMarker.java @@ -0,0 +1,3 @@ +package io.sentry.opentelemetry.agent; + +public final class AgentlessMarker {} diff --git a/sentry-samples/sentry-samples-console-opentelemetry-noagent/build.gradle.kts b/sentry-samples/sentry-samples-console-opentelemetry-noagent/build.gradle.kts index 6d33de11cd..100490935f 100644 --- a/sentry-samples/sentry-samples-console-opentelemetry-noagent/build.gradle.kts +++ b/sentry-samples/sentry-samples-console-opentelemetry-noagent/build.gradle.kts @@ -14,12 +14,5 @@ configure { } dependencies { - implementation(projects.sentry) - - implementation(projects.sentryOpentelemetry.sentryOpentelemetryAgentcustomization) - implementation(projects.sentryOpentelemetry.sentryOpentelemetryBootstrap) - implementation(Config.Libs.OpenTelemetry.otelSdk) - implementation(Config.Libs.OpenTelemetry.otelExtensionAutoconfigure) - implementation(Config.Libs.OpenTelemetry.otelSemconv) - implementation(Config.Libs.OpenTelemetry.otelSemconvIncubating) + implementation(projects.sentryOpentelemetry.sentryOpentelemetryAgentless) } diff --git a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java index c27aad737b..91e76978fb 100644 --- a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java +++ b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java @@ -14,6 +14,7 @@ import io.sentry.SentryEvent; import io.sentry.SentryLevel; import io.sentry.SpanStatus; +import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.protocol.Message; import io.sentry.protocol.User; import java.util.Collections; @@ -28,6 +29,8 @@ public static void main(String[] args) throws InterruptedException { options.setDsn( "https://502f25099c204a2fbf4cb16edc5975d1@o447951.ingest.sentry.io/5428563"); + OpenTelemetryUtil.applyOpenTelemetryOptions(options, false); + // All events get assigned to the release. See more at // https://docs.sentry.io/workflow/releases/ options.setRelease("io.sentry.samples.console@3.0.0+1"); diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts index e0f82ad781..4a5794cb34 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts @@ -53,8 +53,7 @@ dependencies { implementation(projects.sentryGraphql22) implementation(projects.sentryQuartz) implementation(Config.Libs.springBoot3StarterOpenTelemetry) - implementation(projects.sentryOpentelemetry.sentryOpentelemetryBootstrap) - implementation(projects.sentryOpentelemetry.sentryOpentelemetryAgentcustomization) + implementation(projects.sentryOpentelemetry.sentryOpentelemetryAgentless) // database query tracing implementation(projects.sentryJdbc) @@ -71,7 +70,7 @@ dependencies { dependencyManagement { imports { - mavenBom("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.7.0") + mavenBom("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:${Config.Libs.OpenTelemetry.otelInstrumentationVersion}") } } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts index 2dd6f2574b..89aedb6404 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts @@ -70,7 +70,7 @@ dependencies { dependencyManagement { imports { - mavenBom("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.7.0") + mavenBom("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:${Config.Libs.OpenTelemetry.otelInstrumentationVersion}") } } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts index 2eab2bb10e..199eb274be 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts @@ -53,8 +53,7 @@ dependencies { implementation(projects.sentryGraphql) implementation(projects.sentryQuartz) implementation(Config.Libs.springBoot3StarterOpenTelemetry) - implementation(projects.sentryOpentelemetry.sentryOpentelemetryBootstrap) - implementation(projects.sentryOpentelemetry.sentryOpentelemetryAgentcustomization) + implementation(projects.sentryOpentelemetry.sentryOpentelemetryAgentless) // database query tracing implementation(projects.sentryJdbc) diff --git a/settings.gradle.kts b/settings.gradle.kts index 90ae3048f9..75cff85874 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -48,6 +48,7 @@ include( "sentry-opentelemetry:sentry-opentelemetry-core", "sentry-opentelemetry:sentry-opentelemetry-agentcustomization", "sentry-opentelemetry:sentry-opentelemetry-agent", + "sentry-opentelemetry:sentry-opentelemetry-agentless", "sentry-quartz", "sentry-okhttp", "sentry-samples:sentry-samples-android", From b36339c93ca01147d4a37e39f5764e58c27257ca Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 16 Dec 2024 09:56:03 +0100 Subject: [PATCH 02/18] Replace bool with enum for OpenTelemetryUtil mode --- ...ryAutoConfigurationCustomizerProvider.java | 3 +- .../api/sentry-opentelemetry-bootstrap.api | 2 +- .../opentelemetry/OpenTelemetryUtil.java | 6 ++-- .../java/io/sentry/samples/console/Main.java | 3 +- ...etryAgentWithoutAutoInitConfiguration.java | 3 +- ...ntryOpenTelemetryNoAgentConfiguration.java | 4 ++- ...etryAgentWithoutAutoInitConfiguration.java | 3 +- ...ntryOpenTelemetryNoAgentConfiguration.java | 4 ++- sentry/api/sentry.api | 10 +++++- .../io/sentry/SentryOpenTelemetryMode.java | 7 ++++ .../main/java/io/sentry/util/SpanUtils.java | 32 +++++++++++-------- 11 files changed, 53 insertions(+), 24 deletions(-) create mode 100644 sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java 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 index 7d50fe3702..8285f8a19e 100644 --- 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 @@ -8,6 +8,7 @@ import io.sentry.InitPriority; import io.sentry.Sentry; import io.sentry.SentryIntegrationPackageStorage; +import io.sentry.SentryOpenTelemetryMode; import io.sentry.SentryOptions; import io.sentry.protocol.SdkVersion; import io.sentry.protocol.SentryPackage; @@ -38,7 +39,7 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) { options -> { options.setEnableExternalConfiguration(true); options.setInitPriority(InitPriority.HIGH); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, true); + OpenTelemetryUtil.applyOpenTelemetryOptions(options, SentryOpenTelemetryMode.AGENT); final @Nullable SdkVersion sdkVersion = createSdkVersion(options, versionInfoHolder); if (sdkVersion != null) { options.setSdkVersion(sdkVersion); diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api index 0e061c84c0..55053604f4 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api +++ b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api @@ -26,7 +26,7 @@ public final class io/sentry/opentelemetry/InternalSemanticAttributes { public final class io/sentry/opentelemetry/OpenTelemetryUtil { public fun ()V - public static fun applyOpenTelemetryOptions (Lio/sentry/SentryOptions;Z)V + public static fun applyOpenTelemetryOptions (Lio/sentry/SentryOptions;Lio/sentry/SentryOpenTelemetryMode;)V } public final class io/sentry/opentelemetry/OtelContextScopesStorage : io/sentry/IScopesStorage { diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java index c9dbd7d595..b83a951a8d 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java +++ b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java @@ -1,17 +1,19 @@ package io.sentry.opentelemetry; +import io.sentry.SentryOpenTelemetryMode; import io.sentry.SentryOptions; import io.sentry.util.SpanUtils; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @ApiStatus.Experimental public final class OpenTelemetryUtil { public static void applyOpenTelemetryOptions( - final @Nullable SentryOptions options, final boolean isAgent) { + final @Nullable SentryOptions options, final @NotNull SentryOpenTelemetryMode mode) { if (options != null) { - options.setIgnoredSpanOrigins(SpanUtils.ignoredSpanOriginsForOpenTelemetry(isAgent)); + options.setIgnoredSpanOrigins(SpanUtils.ignoredSpanOriginsForOpenTelemetry(mode)); } } } diff --git a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java index 91e76978fb..842485cf26 100644 --- a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java +++ b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java @@ -13,6 +13,7 @@ import io.sentry.Sentry; import io.sentry.SentryEvent; import io.sentry.SentryLevel; +import io.sentry.SentryOpenTelemetryMode; import io.sentry.SpanStatus; import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.protocol.Message; @@ -29,7 +30,7 @@ public static void main(String[] args) throws InterruptedException { options.setDsn( "https://502f25099c204a2fbf4cb16edc5975d1@o447951.ingest.sentry.io/5428563"); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, false); + OpenTelemetryUtil.applyOpenTelemetryOptions(options, SentryOpenTelemetryMode.AGENTLESS); // All events get assigned to the release. See more at // https://docs.sentry.io/workflow/releases/ diff --git a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java index 96ba5ae770..74ef7c303b 100644 --- a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java +++ b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java @@ -3,6 +3,7 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.Sentry; import io.sentry.SentryIntegrationPackageStorage; +import io.sentry.SentryOpenTelemetryMode; import io.sentry.SentryOptions; import io.sentry.opentelemetry.OpenTelemetryUtil; import org.jetbrains.annotations.NotNull; @@ -21,7 +22,7 @@ public class SentryOpenTelemetryAgentWithoutAutoInitConfiguration { return options -> { SentryIntegrationPackageStorage.getInstance() .addIntegration("SpringBoot3OpenTelemetryAgentWithoutAutoInit"); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, true); + OpenTelemetryUtil.applyOpenTelemetryOptions(options, SentryOpenTelemetryMode.AGENT); }; } } diff --git a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java index d53acca52f..cf579ab6c4 100644 --- a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java +++ b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java @@ -5,6 +5,7 @@ import io.sentry.ISpanFactory; import io.sentry.Sentry; import io.sentry.SentryIntegrationPackageStorage; +import io.sentry.SentryOpenTelemetryMode; import io.sentry.SentryOptions; import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.opentelemetry.OtelSpanFactory; @@ -32,7 +33,8 @@ public static ISpanFactory openTelemetrySpanFactory(OpenTelemetry openTelemetry) SentryIntegrationPackageStorage.getInstance() .addIntegration("SpringBoot3OpenTelemetryNoAgent"); SentryAutoConfigurationCustomizerProvider.skipInit = true; - OpenTelemetryUtil.applyOpenTelemetryOptions(options, false); + OpenTelemetryUtil.applyOpenTelemetryOptions( + options, SentryOpenTelemetryMode.AGENTLESS_SPRING); }; } } diff --git a/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java b/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java index bfc613512e..cd342a0f79 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java +++ b/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java @@ -3,6 +3,7 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.Sentry; import io.sentry.SentryIntegrationPackageStorage; +import io.sentry.SentryOpenTelemetryMode; import io.sentry.SentryOptions; import io.sentry.opentelemetry.OpenTelemetryUtil; import org.jetbrains.annotations.NotNull; @@ -21,7 +22,7 @@ public class SentryOpenTelemetryAgentWithoutAutoInitConfiguration { return options -> { SentryIntegrationPackageStorage.getInstance() .addIntegration("SpringBootOpenTelemetryAgentWithoutAutoInit"); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, true); + OpenTelemetryUtil.applyOpenTelemetryOptions(options, SentryOpenTelemetryMode.AGENT); }; } } diff --git a/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java b/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java index 61ee3aa1e7..f74f5d94f3 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java +++ b/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java @@ -5,6 +5,7 @@ import io.sentry.ISpanFactory; import io.sentry.Sentry; import io.sentry.SentryIntegrationPackageStorage; +import io.sentry.SentryOpenTelemetryMode; import io.sentry.SentryOptions; import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.opentelemetry.OtelSpanFactory; @@ -32,7 +33,8 @@ public static ISpanFactory openTelemetrySpanFactory(OpenTelemetry openTelemetry) SentryIntegrationPackageStorage.getInstance() .addIntegration("SpringBootOpenTelemetryNoAgent"); SentryAutoConfigurationCustomizerProvider.skipInit = true; - OpenTelemetryUtil.applyOpenTelemetryOptions(options, false); + OpenTelemetryUtil.applyOpenTelemetryOptions( + options, SentryOpenTelemetryMode.AGENTLESS_SPRING); }; } } diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 7cf213a03c..3329397a72 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -2781,6 +2781,14 @@ public final class io/sentry/SentryNanotimeDateProvider : io/sentry/SentryDatePr public fun now ()Lio/sentry/SentryDate; } +public final class io/sentry/SentryOpenTelemetryMode : java/lang/Enum { + public static final field AGENT Lio/sentry/SentryOpenTelemetryMode; + public static final field AGENTLESS Lio/sentry/SentryOpenTelemetryMode; + public static final field AGENTLESS_SPRING Lio/sentry/SentryOpenTelemetryMode; + public static fun valueOf (Ljava/lang/String;)Lio/sentry/SentryOpenTelemetryMode; + public static fun values ()[Lio/sentry/SentryOpenTelemetryMode; +} + public class io/sentry/SentryOptions { public static final field DEFAULT_PROPAGATION_TARGETS Ljava/lang/String; protected final field lock Lio/sentry/util/AutoClosableReentrantLock; @@ -6194,7 +6202,7 @@ public final class io/sentry/util/SentryRandom { public final class io/sentry/util/SpanUtils { public fun ()V - public static fun ignoredSpanOriginsForOpenTelemetry (Z)Ljava/util/List; + public static fun ignoredSpanOriginsForOpenTelemetry (Lio/sentry/SentryOpenTelemetryMode;)Ljava/util/List; public static fun isIgnored (Ljava/util/List;Ljava/lang/String;)Z } diff --git a/sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java b/sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java new file mode 100644 index 0000000000..5121c013e5 --- /dev/null +++ b/sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java @@ -0,0 +1,7 @@ +package io.sentry; + +public enum SentryOpenTelemetryMode { + AGENT, + AGENTLESS, + AGENTLESS_SPRING +} diff --git a/sentry/src/main/java/io/sentry/util/SpanUtils.java b/sentry/src/main/java/io/sentry/util/SpanUtils.java index a657186744..323bdbee98 100644 --- a/sentry/src/main/java/io/sentry/util/SpanUtils.java +++ b/sentry/src/main/java/io/sentry/util/SpanUtils.java @@ -1,5 +1,6 @@ package io.sentry.util; +import io.sentry.SentryOpenTelemetryMode; import java.util.ArrayList; import java.util.List; import org.jetbrains.annotations.ApiStatus; @@ -13,23 +14,26 @@ public final class SpanUtils { * * @return a list of span origins to be ignored */ - public static @NotNull List ignoredSpanOriginsForOpenTelemetry(final boolean isAgent) { + public static @NotNull List ignoredSpanOriginsForOpenTelemetry( + final @NotNull SentryOpenTelemetryMode mode) { final @NotNull List origins = new ArrayList<>(); - origins.add("auto.http.spring_jakarta.webmvc"); - origins.add("auto.http.spring.webmvc"); - origins.add("auto.spring_jakarta.webflux"); - origins.add("auto.spring.webflux"); - origins.add("auto.db.jdbc"); - origins.add("auto.http.spring_jakarta.webclient"); - origins.add("auto.http.spring.webclient"); - origins.add("auto.http.spring_jakarta.restclient"); - origins.add("auto.http.spring.restclient"); - origins.add("auto.http.spring_jakarta.resttemplate"); - origins.add("auto.http.spring.resttemplate"); - origins.add("auto.http.openfeign"); + if (SentryOpenTelemetryMode.AGENT == mode || SentryOpenTelemetryMode.AGENTLESS_SPRING == mode) { + origins.add("auto.http.spring_jakarta.webmvc"); + origins.add("auto.http.spring.webmvc"); + origins.add("auto.spring_jakarta.webflux"); + origins.add("auto.spring.webflux"); + origins.add("auto.db.jdbc"); + origins.add("auto.http.spring_jakarta.webclient"); + origins.add("auto.http.spring.webclient"); + origins.add("auto.http.spring_jakarta.restclient"); + origins.add("auto.http.spring.restclient"); + origins.add("auto.http.spring_jakarta.resttemplate"); + origins.add("auto.http.spring.resttemplate"); + origins.add("auto.http.openfeign"); + } - if (isAgent) { + if (SentryOpenTelemetryMode.AGENT == mode) { origins.add("auto.graphql.graphql"); origins.add("auto.graphql.graphql22"); } From d48d398cfc551da7dfa161819595060a214b1109 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 16 Dec 2024 13:36:14 +0100 Subject: [PATCH 03/18] Move OpenTelemetryUtil into core sentry --- .../api/sentry-opentelemetry-bootstrap.api | 5 ----- sentry/api/sentry.api | 5 +++++ .../main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java | 0 3 files changed, 5 insertions(+), 5 deletions(-) rename {sentry-opentelemetry/sentry-opentelemetry-bootstrap => sentry}/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java (100%) diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api index 55053604f4..47e4f5ad9b 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api +++ b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api @@ -24,11 +24,6 @@ public final class io/sentry/opentelemetry/InternalSemanticAttributes { public fun ()V } -public final class io/sentry/opentelemetry/OpenTelemetryUtil { - public fun ()V - public static fun applyOpenTelemetryOptions (Lio/sentry/SentryOptions;Lio/sentry/SentryOpenTelemetryMode;)V -} - public final class io/sentry/opentelemetry/OtelContextScopesStorage : io/sentry/IScopesStorage { public fun ()V public fun close ()V diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 3329397a72..75a7bd2751 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -4211,6 +4211,11 @@ public abstract interface class io/sentry/internal/viewhierarchy/ViewHierarchyEx public abstract fun export (Lio/sentry/protocol/ViewHierarchyNode;Ljava/lang/Object;)Z } +public final class io/sentry/opentelemetry/OpenTelemetryUtil { + public fun ()V + public static fun applyOpenTelemetryOptions (Lio/sentry/SentryOptions;Lio/sentry/SentryOpenTelemetryMode;)V +} + public final class io/sentry/profilemeasurements/ProfileMeasurement : io/sentry/JsonSerializable, io/sentry/JsonUnknown { public static final field ID_CPU_USAGE Ljava/lang/String; public static final field ID_FROZEN_FRAME_RENDERS Ljava/lang/String; diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java b/sentry/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java similarity index 100% rename from sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java rename to sentry/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java From 66b4206645a8a5f2cd3c3f917871992afbd9dde0 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 17 Dec 2024 10:27:26 +0100 Subject: [PATCH 04/18] Add openTelemetryMode option --- ...ryAutoConfigurationCustomizerProvider.java | 2 +- .../java/io/sentry/samples/console/Main.java | 4 -- .../jakarta/it/SentrySpringIntegrationTest.kt | 2 + .../boot/it/SentrySpringIntegrationTest.kt | 3 ++ ...etryAgentWithoutAutoInitConfiguration.java | 3 +- ...ntryOpenTelemetryNoAgentConfiguration.java | 4 +- ...etryAgentWithoutAutoInitConfiguration.java | 3 +- ...ntryOpenTelemetryNoAgentConfiguration.java | 4 +- sentry/api/sentry.api | 7 ++- sentry/src/main/java/io/sentry/Sentry.java | 3 ++ .../io/sentry/SentryOpenTelemetryMode.java | 23 ++++++++++ .../main/java/io/sentry/SentryOptions.java | 28 ++++++++++++ .../opentelemetry/OpenTelemetryUtil.java | 43 ++++++++++++++++--- 13 files changed, 107 insertions(+), 22 deletions(-) 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 index 8285f8a19e..c1281d0a08 100644 --- 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 @@ -39,7 +39,7 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) { options -> { options.setEnableExternalConfiguration(true); options.setInitPriority(InitPriority.HIGH); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, SentryOpenTelemetryMode.AGENT); + options.setOpenTelemetryMode(SentryOpenTelemetryMode.AGENT); final @Nullable SdkVersion sdkVersion = createSdkVersion(options, versionInfoHolder); if (sdkVersion != null) { options.setSdkVersion(sdkVersion); diff --git a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java index 842485cf26..c27aad737b 100644 --- a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java +++ b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java @@ -13,9 +13,7 @@ import io.sentry.Sentry; import io.sentry.SentryEvent; import io.sentry.SentryLevel; -import io.sentry.SentryOpenTelemetryMode; import io.sentry.SpanStatus; -import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.protocol.Message; import io.sentry.protocol.User; import java.util.Collections; @@ -30,8 +28,6 @@ public static void main(String[] args) throws InterruptedException { options.setDsn( "https://502f25099c204a2fbf4cb16edc5975d1@o447951.ingest.sentry.io/5428563"); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, SentryOpenTelemetryMode.AGENTLESS); - // All events get assigned to the release. See more at // https://docs.sentry.io/workflow/releases/ options.setRelease("io.sentry.samples.console@3.0.0+1"); diff --git a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/it/SentrySpringIntegrationTest.kt b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/it/SentrySpringIntegrationTest.kt index 643f3da682..d24d3366e6 100644 --- a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/it/SentrySpringIntegrationTest.kt +++ b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/it/SentrySpringIntegrationTest.kt @@ -4,6 +4,7 @@ import io.sentry.DefaultSpanFactory import io.sentry.IScopes import io.sentry.ITransportFactory import io.sentry.Sentry +import io.sentry.SentryOpenTelemetryMode import io.sentry.SentryOptions import io.sentry.checkEvent import io.sentry.checkTransaction @@ -230,6 +231,7 @@ open class App { open fun optionsCallback() = Sentry.OptionsConfiguration { options -> // due to OTel being on the classpath we need to set the default again options.spanFactory = DefaultSpanFactory() + options.openTelemetryMode = SentryOpenTelemetryMode.ALL_ORIGINS } } diff --git a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/it/SentrySpringIntegrationTest.kt b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/it/SentrySpringIntegrationTest.kt index 8d0013dae9..72f20eb5bf 100644 --- a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/it/SentrySpringIntegrationTest.kt +++ b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/it/SentrySpringIntegrationTest.kt @@ -4,6 +4,7 @@ import io.sentry.DefaultSpanFactory import io.sentry.IScopes import io.sentry.ITransportFactory import io.sentry.Sentry +import io.sentry.SentryOpenTelemetryMode import io.sentry.SentryOptions import io.sentry.checkEvent import io.sentry.checkTransaction @@ -230,6 +231,8 @@ open class App { open fun optionsCallback() = Sentry.OptionsConfiguration { options -> // due to OTel being on the classpath we need to set the default again options.spanFactory = DefaultSpanFactory() + // to test the actual spring implementation + options.openTelemetryMode = SentryOpenTelemetryMode.ALL_ORIGINS } } diff --git a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java index 74ef7c303b..bac77cfafc 100644 --- a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java +++ b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java @@ -5,7 +5,6 @@ import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOpenTelemetryMode; import io.sentry.SentryOptions; -import io.sentry.opentelemetry.OpenTelemetryUtil; import org.jetbrains.annotations.NotNull; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -22,7 +21,7 @@ public class SentryOpenTelemetryAgentWithoutAutoInitConfiguration { return options -> { SentryIntegrationPackageStorage.getInstance() .addIntegration("SpringBoot3OpenTelemetryAgentWithoutAutoInit"); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, SentryOpenTelemetryMode.AGENT); + options.setOpenTelemetryMode(SentryOpenTelemetryMode.AGENT); }; } } diff --git a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java index cf579ab6c4..3e3ef9e2af 100644 --- a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java +++ b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java @@ -7,7 +7,6 @@ import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOpenTelemetryMode; import io.sentry.SentryOptions; -import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.opentelemetry.OtelSpanFactory; import io.sentry.opentelemetry.SentryAutoConfigurationCustomizerProvider; import org.jetbrains.annotations.NotNull; @@ -33,8 +32,7 @@ public static ISpanFactory openTelemetrySpanFactory(OpenTelemetry openTelemetry) SentryIntegrationPackageStorage.getInstance() .addIntegration("SpringBoot3OpenTelemetryNoAgent"); SentryAutoConfigurationCustomizerProvider.skipInit = true; - OpenTelemetryUtil.applyOpenTelemetryOptions( - options, SentryOpenTelemetryMode.AGENTLESS_SPRING); + options.setOpenTelemetryMode(SentryOpenTelemetryMode.AGENTLESS_SPRING); }; } } diff --git a/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java b/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java index cd342a0f79..6a02422cc7 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java +++ b/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryAgentWithoutAutoInitConfiguration.java @@ -5,7 +5,6 @@ import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOpenTelemetryMode; import io.sentry.SentryOptions; -import io.sentry.opentelemetry.OpenTelemetryUtil; import org.jetbrains.annotations.NotNull; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -22,7 +21,7 @@ public class SentryOpenTelemetryAgentWithoutAutoInitConfiguration { return options -> { SentryIntegrationPackageStorage.getInstance() .addIntegration("SpringBootOpenTelemetryAgentWithoutAutoInit"); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, SentryOpenTelemetryMode.AGENT); + options.setOpenTelemetryMode(SentryOpenTelemetryMode.AGENT); }; } } diff --git a/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java b/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java index f74f5d94f3..0d95ddb19b 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java +++ b/sentry-spring/src/main/java/io/sentry/spring/opentelemetry/SentryOpenTelemetryNoAgentConfiguration.java @@ -7,7 +7,6 @@ import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryOpenTelemetryMode; import io.sentry.SentryOptions; -import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.opentelemetry.OtelSpanFactory; import io.sentry.opentelemetry.SentryAutoConfigurationCustomizerProvider; import org.jetbrains.annotations.NotNull; @@ -33,8 +32,7 @@ public static ISpanFactory openTelemetrySpanFactory(OpenTelemetry openTelemetry) SentryIntegrationPackageStorage.getInstance() .addIntegration("SpringBootOpenTelemetryNoAgent"); SentryAutoConfigurationCustomizerProvider.skipInit = true; - OpenTelemetryUtil.applyOpenTelemetryOptions( - options, SentryOpenTelemetryMode.AGENTLESS_SPRING); + options.setOpenTelemetryMode(SentryOpenTelemetryMode.AGENTLESS_SPRING); }; } } diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 75a7bd2751..5fb709943c 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -2785,6 +2785,8 @@ public final class io/sentry/SentryOpenTelemetryMode : java/lang/Enum { public static final field AGENT Lio/sentry/SentryOpenTelemetryMode; public static final field AGENTLESS Lio/sentry/SentryOpenTelemetryMode; public static final field AGENTLESS_SPRING Lio/sentry/SentryOpenTelemetryMode; + public static final field ALL_ORIGINS Lio/sentry/SentryOpenTelemetryMode; + public static final field AUTO Lio/sentry/SentryOpenTelemetryMode; public static fun valueOf (Ljava/lang/String;)Lio/sentry/SentryOpenTelemetryMode; public static fun values ()[Lio/sentry/SentryOpenTelemetryMode; } @@ -2797,6 +2799,7 @@ public class io/sentry/SentryOptions { public fun addContextTag (Ljava/lang/String;)V public fun addEventProcessor (Lio/sentry/EventProcessor;)V public fun addIgnoredExceptionForType (Ljava/lang/Class;)V + public fun addIgnoredSpanOrigin (Ljava/lang/String;)V public fun addInAppExclude (Ljava/lang/String;)V public fun addInAppInclude (Ljava/lang/String;)V public fun addIntegration (Lio/sentry/Integration;)V @@ -2854,6 +2857,7 @@ public class io/sentry/SentryOptions { public fun getMaxSpans ()I public fun getMaxTraceFileSize ()J public fun getModulesLoader ()Lio/sentry/internal/modules/IModulesLoader; + public fun getOpenTelemetryMode ()Lio/sentry/SentryOpenTelemetryMode; public fun getOptionsObservers ()Ljava/util/List; public fun getOutboxPath ()Ljava/lang/String; public fun getPerformanceCollectors ()Ljava/util/List; @@ -2979,6 +2983,7 @@ public class io/sentry/SentryOptions { public fun setMaxSpans (I)V public fun setMaxTraceFileSize (J)V public fun setModulesLoader (Lio/sentry/internal/modules/IModulesLoader;)V + public fun setOpenTelemetryMode (Lio/sentry/SentryOpenTelemetryMode;)V public fun setPrintUncaughtStackTrace (Z)V public fun setProfilesSampleRate (Ljava/lang/Double;)V public fun setProfilesSampler (Lio/sentry/SentryOptions$ProfilesSamplerCallback;)V @@ -4213,7 +4218,7 @@ public abstract interface class io/sentry/internal/viewhierarchy/ViewHierarchyEx public final class io/sentry/opentelemetry/OpenTelemetryUtil { public fun ()V - public static fun applyOpenTelemetryOptions (Lio/sentry/SentryOptions;Lio/sentry/SentryOpenTelemetryMode;)V + public static fun applyIgnoredSpanOrigins (Lio/sentry/SentryOptions;Lio/sentry/util/LoadClass;)V } public final class io/sentry/profilemeasurements/ProfileMeasurement : io/sentry/JsonSerializable, io/sentry/JsonUnknown { diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index e8317365ed..a71c5613af 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -11,6 +11,7 @@ import io.sentry.internal.modules.ManifestModulesLoader; import io.sentry.internal.modules.NoOpModulesLoader; import io.sentry.internal.modules.ResourcesModulesLoader; +import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.protocol.SentryId; import io.sentry.protocol.User; import io.sentry.transport.NoOpEnvelopeCache; @@ -490,6 +491,8 @@ private static void initConfigurations(final @NotNull SentryOptions options) { } logger.log(SentryLevel.INFO, "Initializing SDK with DSN: '%s'", options.getDsn()); + OpenTelemetryUtil.applyIgnoredSpanOrigins(options, new LoadClass()); + // TODO: read values from conf file, Build conf or system envs // eg release, distinctId, sentryClientName diff --git a/sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java b/sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java index 5121c013e5..5c452e4ca6 100644 --- a/sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java +++ b/sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java @@ -1,7 +1,30 @@ package io.sentry; +/** + * Configures the SDK to either automatically determine if OpenTelemetry is available, whether to + * use it and what way to use it in. + */ public enum SentryOpenTelemetryMode { + /** Let the SDK figure out what mode OpenTelemetry is in and whether to even use OpenTelemetry */ + AUTO, + /** + * For now this only means no span origins will be ignored. This does however not mean, the SDK + * won't try tro use OpenTelemetry if available. + * + *

Due to some parts of the SDK being initialized before any config mechanism is available, we + * cannot completely disable the OpenTelemetry parts with this setting. + */ + ALL_ORIGINS, + /** The `sentry-opentelemetry-agent` is used */ AGENT, + /** + * `sentry-opentelemetry-agentless` is used, meaning OpenTelemetry will be used but there is no + * auto instrumentation available. + */ AGENTLESS, + /** + * `sentry-opentelemetry-agentless-spring-boot` is used, meaning + * `opentelemetry-spring-boot-starter` and its auto instrumentation is used. + */ AGENTLESS_SPRING } diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 2ea882b3dc..21535a0fe5 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -513,6 +513,8 @@ public class SentryOptions { protected final @NotNull AutoClosableReentrantLock lock = new AutoClosableReentrantLock(); + private @NotNull SentryOpenTelemetryMode openTelemetryMode = SentryOpenTelemetryMode.AUTO; + /** * Adds an event processor * @@ -2193,6 +2195,13 @@ public void setIgnoredCheckIns(final @Nullable List ignoredCheckIns) { return ignoredSpanOrigins; } + public void addIgnoredSpanOrigin(final @NotNull String origin) { + if (this.ignoredSpanOrigins == null) { + this.ignoredSpanOrigins = new ArrayList<>(); + } + this.ignoredSpanOrigins.add(origin); + } + @ApiStatus.Experimental public void setIgnoredSpanOrigins(final @Nullable List ignoredSpanOrigins) { if (ignoredSpanOrigins == null) { @@ -2458,6 +2467,25 @@ public void setGlobalHubMode(final @Nullable Boolean globalHubMode) { return globalHubMode; } + /** + * Configures the SDK to either automatically determine if OpenTelemetry is available, whether to + * use it and what way to use it in. + * + *

See {@link SentryOpenTelemetryMode} + * + *

By default the SDK will use OpenTelemetry if available, preferring the agent. On Android + * OpenTelemetry is not used. + * + * @param openTelemetryMode the mode + */ + public void setOpenTelemetryMode(final @NotNull SentryOpenTelemetryMode openTelemetryMode) { + this.openTelemetryMode = openTelemetryMode; + } + + public @NotNull SentryOpenTelemetryMode getOpenTelemetryMode() { + return openTelemetryMode; + } + /** * Load the lazy fields. Useful to load in the background, so that results are already cached. DO * NOT CALL THIS METHOD ON THE MAIN THREAD. diff --git a/sentry/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java b/sentry/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java index b83a951a8d..b491ab5278 100644 --- a/sentry/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java +++ b/sentry/src/main/java/io/sentry/opentelemetry/OpenTelemetryUtil.java @@ -2,18 +2,49 @@ import io.sentry.SentryOpenTelemetryMode; import io.sentry.SentryOptions; +import io.sentry.util.LoadClass; +import io.sentry.util.Platform; import io.sentry.util.SpanUtils; +import java.util.Collections; +import java.util.List; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -@ApiStatus.Experimental +@ApiStatus.Internal public final class OpenTelemetryUtil { - public static void applyOpenTelemetryOptions( - final @Nullable SentryOptions options, final @NotNull SentryOpenTelemetryMode mode) { - if (options != null) { - options.setIgnoredSpanOrigins(SpanUtils.ignoredSpanOriginsForOpenTelemetry(mode)); + @ApiStatus.Internal + public static void applyIgnoredSpanOrigins( + final @NotNull SentryOptions options, final @NotNull LoadClass loadClass) { + if (Platform.isJvm()) { + final @NotNull List ignored = ignoredSpanOrigins(options, loadClass); + for (String origin : ignored) { + options.addIgnoredSpanOrigin(origin); + } } } + + private static @NotNull List ignoredSpanOrigins( + final @NotNull SentryOptions options, final @NotNull LoadClass loadClass) { + final @NotNull SentryOpenTelemetryMode openTelemetryMode = options.getOpenTelemetryMode(); + if (SentryOpenTelemetryMode.AUTO.equals(openTelemetryMode)) { + if (loadClass.isClassAvailable( + "io.sentry.opentelemetry.agent.AgentMarker", options.getLogger())) { + return SpanUtils.ignoredSpanOriginsForOpenTelemetry(SentryOpenTelemetryMode.AGENT); + } + if (loadClass.isClassAvailable( + "io.sentry.opentelemetry.agent.AgentlessMarker", options.getLogger())) { + return SpanUtils.ignoredSpanOriginsForOpenTelemetry(SentryOpenTelemetryMode.AGENTLESS); + } + if (loadClass.isClassAvailable( + "io.sentry.opentelemetry.agent.AgentlessSpringMarker", options.getLogger())) { + return SpanUtils.ignoredSpanOriginsForOpenTelemetry( + SentryOpenTelemetryMode.AGENTLESS_SPRING); + } + } else { + return SpanUtils.ignoredSpanOriginsForOpenTelemetry(openTelemetryMode); + } + + return Collections.emptyList(); + } } From e46efe8057413afc80dad72f7ea8140f57fcc820 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 17 Dec 2024 12:17:54 +0100 Subject: [PATCH 05/18] Add SentryOpenTelemetryMode.OFF --- .../core/AndroidOptionsInitializer.java | 3 ++- .../jakarta/it/SentrySpringIntegrationTest.kt | 2 +- .../boot/it/SentrySpringIntegrationTest.kt | 2 +- sentry/api/sentry.api | 2 +- sentry/src/main/java/io/sentry/Sentry.java | 18 ++++++++++++++++-- .../io/sentry/SentryOpenTelemetryMode.java | 13 +++++-------- .../src/main/java/io/sentry/SentryOptions.java | 2 -- 7 files changed, 26 insertions(+), 16 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java index 62900c25b8..5d4658bcf9 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java @@ -15,6 +15,7 @@ import io.sentry.SendFireAndForgetEnvelopeSender; import io.sentry.SendFireAndForgetOutboxSender; import io.sentry.SentryLevel; +import io.sentry.SentryOpenTelemetryMode; import io.sentry.android.core.cache.AndroidEnvelopeCache; import io.sentry.android.core.internal.debugmeta.AssetsDebugMetaLoader; import io.sentry.android.core.internal.gestures.AndroidViewGestureTargetLocator; @@ -101,7 +102,7 @@ static void loadDefaultAndMetadataOptions( options.setLogger(logger); options.setDefaultScopeType(ScopeType.CURRENT); - + options.setOpenTelemetryMode(SentryOpenTelemetryMode.OFF); options.setDateProvider(new SentryAndroidDateProvider()); // set a lower flush timeout on Android to avoid ANRs diff --git a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/it/SentrySpringIntegrationTest.kt b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/it/SentrySpringIntegrationTest.kt index fb433ff598..3e1ce2c2d0 100644 --- a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/it/SentrySpringIntegrationTest.kt +++ b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/it/SentrySpringIntegrationTest.kt @@ -250,7 +250,7 @@ open class App { open fun optionsCallback() = Sentry.OptionsConfiguration { options -> // due to OTel being on the classpath we need to set the default again options.spanFactory = DefaultSpanFactory() - options.openTelemetryMode = SentryOpenTelemetryMode.ALL_ORIGINS + options.openTelemetryMode = SentryOpenTelemetryMode.OFF } } diff --git a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/it/SentrySpringIntegrationTest.kt b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/it/SentrySpringIntegrationTest.kt index b6a2a18c0f..59b87ea0cf 100644 --- a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/it/SentrySpringIntegrationTest.kt +++ b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/it/SentrySpringIntegrationTest.kt @@ -251,7 +251,7 @@ open class App { // due to OTel being on the classpath we need to set the default again options.spanFactory = DefaultSpanFactory() // to test the actual spring implementation - options.openTelemetryMode = SentryOpenTelemetryMode.ALL_ORIGINS + options.openTelemetryMode = SentryOpenTelemetryMode.OFF } } diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 5fb709943c..ef446fd35b 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -2785,8 +2785,8 @@ public final class io/sentry/SentryOpenTelemetryMode : java/lang/Enum { public static final field AGENT Lio/sentry/SentryOpenTelemetryMode; public static final field AGENTLESS Lio/sentry/SentryOpenTelemetryMode; public static final field AGENTLESS_SPRING Lio/sentry/SentryOpenTelemetryMode; - public static final field ALL_ORIGINS Lio/sentry/SentryOpenTelemetryMode; public static final field AUTO Lio/sentry/SentryOpenTelemetryMode; + public static final field OFF Lio/sentry/SentryOpenTelemetryMode; public static fun valueOf (Ljava/lang/String;)Lio/sentry/SentryOpenTelemetryMode; public static fun values ()[Lio/sentry/SentryOpenTelemetryMode; } diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index a71c5613af..8a8f45d281 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -47,8 +47,7 @@ public final class Sentry { private Sentry() {} // TODO logger? - private static volatile @NotNull IScopesStorage scopesStorage = - ScopesStorageFactory.create(new LoadClass(), NoOpLogger.getInstance()); + private static volatile @NotNull IScopesStorage scopesStorage = NoOpScopesStorage.getInstance(); /** The root Scopes or NoOp if Sentry is disabled. */ private static volatile @NotNull IScopes rootScopes = NoOpScopes.getInstance(); @@ -322,6 +321,7 @@ private static void init(final @NotNull SentryOptions options, final boolean glo final IScope rootIsolationScope = new Scope(options); rootScopes = new Scopes(rootScope, rootIsolationScope, globalScope, "Sentry.init"); + initScopesStorage(options); getScopesStorage().set(rootScopes); initConfigurations(options); @@ -357,6 +357,15 @@ private static void init(final @NotNull SentryOptions options, final boolean glo } } + private static void initScopesStorage(SentryOptions options) { + getScopesStorage().close(); + if (SentryOpenTelemetryMode.OFF == options.getOpenTelemetryMode()) { + scopesStorage = new DefaultScopesStorage(); + } else { + scopesStorage = ScopesStorageFactory.create(new LoadClass(), options.getLogger()); + } + } + @SuppressWarnings("FutureReturnValueIgnored") private static void handleAppStartProfilingConfig( final @NotNull SentryOptions options, @@ -492,6 +501,11 @@ private static void initConfigurations(final @NotNull SentryOptions options) { logger.log(SentryLevel.INFO, "Initializing SDK with DSN: '%s'", options.getDsn()); OpenTelemetryUtil.applyIgnoredSpanOrigins(options, new LoadClass()); + if (SentryOpenTelemetryMode.OFF == options.getOpenTelemetryMode()) { + options.setSpanFactory(new DefaultSpanFactory()); + } else { + options.setSpanFactory(SpanFactoryFactory.create(new LoadClass(), NoOpLogger.getInstance())); + } // TODO: read values from conf file, Build conf or system envs // eg release, distinctId, sentryClientName diff --git a/sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java b/sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java index 5c452e4ca6..034cbb1be3 100644 --- a/sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java +++ b/sentry/src/main/java/io/sentry/SentryOpenTelemetryMode.java @@ -5,16 +5,13 @@ * use it and what way to use it in. */ public enum SentryOpenTelemetryMode { - /** Let the SDK figure out what mode OpenTelemetry is in and whether to even use OpenTelemetry */ - AUTO, /** - * For now this only means no span origins will be ignored. This does however not mean, the SDK - * won't try tro use OpenTelemetry if available. - * - *

Due to some parts of the SDK being initialized before any config mechanism is available, we - * cannot completely disable the OpenTelemetry parts with this setting. + * Let the SDK figure out what mode OpenTelemetry is in and whether to even use OpenTelemetry This + * is the default for non Android. */ - ALL_ORIGINS, + AUTO, + /** Do not try to use OpenTelemetry, even if it is available. This is the default for Android. */ + OFF, /** The `sentry-opentelemetry-agent` is used */ AGENT, /** diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 21535a0fe5..76256c4597 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -21,7 +21,6 @@ import io.sentry.transport.NoOpTransportGate; import io.sentry.util.AutoClosableReentrantLock; import io.sentry.util.LazyEvaluator; -import io.sentry.util.LoadClass; import io.sentry.util.Platform; import io.sentry.util.SampleRateUtils; import io.sentry.util.StringUtils; @@ -2637,7 +2636,6 @@ public SentryOptions() { private SentryOptions(final boolean empty) { experimental = new ExperimentalOptions(empty); if (!empty) { - setSpanFactory(SpanFactoryFactory.create(new LoadClass(), NoOpLogger.getInstance())); // SentryExecutorService should be initialized before any // SendCachedEventFireAndForgetIntegration executorService = new SentryExecutorService(); From 523114028d98dbfc171dfaded814a64fe06cd355 Mon Sep 17 00:00:00 2001 From: Lukas Bloder Date: Tue, 17 Dec 2024 14:26:05 +0100 Subject: [PATCH 06/18] fix HubAdapter and ScopeAdapter tests by calling Sentry.init so that the ScopesStorage is initialized --- sentry/src/test/java/io/sentry/HubAdapterTest.kt | 5 +++++ sentry/src/test/java/io/sentry/ScopesAdapterTest.kt | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/sentry/src/test/java/io/sentry/HubAdapterTest.kt b/sentry/src/test/java/io/sentry/HubAdapterTest.kt index f57c45ba4e..a70da6cb1a 100644 --- a/sentry/src/test/java/io/sentry/HubAdapterTest.kt +++ b/sentry/src/test/java/io/sentry/HubAdapterTest.kt @@ -19,6 +19,11 @@ class HubAdapterTest { @BeforeTest fun `set up`() { + Sentry.init( + SentryOptions().apply { + dsn = "https://key@localhost/proj" + } + ) Sentry.setCurrentScopes(scopes) } diff --git a/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt b/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt index db2ed593ca..8bd26a6232 100644 --- a/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt +++ b/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt @@ -19,6 +19,11 @@ class ScopesAdapterTest { @BeforeTest fun `set up`() { + Sentry.init( + SentryOptions().apply { + dsn = "https://key@localhost/proj" + } + ) Sentry.setCurrentScopes(scopes) } From 917b2e38b358b4909be5e79c3d082308bb75241a Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 17 Dec 2024 15:57:16 +0100 Subject: [PATCH 07/18] Hold a strong reference to OTel span if created via Sentry API --- .../api/sentry-opentelemetry-bootstrap.api | 52 +++ .../sentry/opentelemetry/OtelSpanFactory.java | 6 +- .../OtelStrongRefSpanWrapper.java | 306 ++++++++++++++++++ 3 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelStrongRefSpanWrapper.java diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api index 44614f17b4..df7db47c65 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api +++ b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/api/sentry-opentelemetry-bootstrap.api @@ -39,6 +39,58 @@ public final class io/sentry/opentelemetry/OtelSpanFactory : io/sentry/ISpanFact public fun createTransaction (Lio/sentry/TransactionContext;Lio/sentry/IScopes;Lio/sentry/TransactionOptions;Lio/sentry/TransactionPerformanceCollector;)Lio/sentry/ITransaction; } +public final class io/sentry/opentelemetry/OtelStrongRefSpanWrapper : io/sentry/opentelemetry/IOtelSpanWrapper { + public fun (Lio/opentelemetry/api/trace/Span;Lio/sentry/opentelemetry/IOtelSpanWrapper;)V + public fun finish ()V + public fun finish (Lio/sentry/SpanStatus;)V + public fun finish (Lio/sentry/SpanStatus;Lio/sentry/SentryDate;)V + public fun getContexts ()Lio/sentry/protocol/Contexts; + public fun getData ()Ljava/util/Map; + public fun getData (Ljava/lang/String;)Ljava/lang/Object; + public fun getDescription ()Ljava/lang/String; + public fun getFinishDate ()Lio/sentry/SentryDate; + public fun getMeasurements ()Ljava/util/Map; + public fun getOperation ()Ljava/lang/String; + public fun getSamplingDecision ()Lio/sentry/TracesSamplingDecision; + public fun getScopes ()Lio/sentry/IScopes; + public fun getSpanContext ()Lio/sentry/SpanContext; + public fun getStartDate ()Lio/sentry/SentryDate; + public fun getStatus ()Lio/sentry/SpanStatus; + public fun getTag (Ljava/lang/String;)Ljava/lang/String; + public fun getTags ()Ljava/util/Map; + public fun getThrowable ()Ljava/lang/Throwable; + public fun getTraceId ()Lio/sentry/protocol/SentryId; + public fun getTransactionName ()Ljava/lang/String; + public fun getTransactionNameSource ()Lio/sentry/protocol/TransactionNameSource; + public fun isFinished ()Z + public fun isNoOp ()Z + public fun isProfileSampled ()Ljava/lang/Boolean; + public fun isSampled ()Ljava/lang/Boolean; + public fun makeCurrent ()Lio/sentry/ISentryLifecycleToken; + public fun setContext (Ljava/lang/String;Ljava/lang/Object;)V + public fun setData (Ljava/lang/String;Ljava/lang/Object;)V + public fun setDescription (Ljava/lang/String;)V + public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;)V + public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;Lio/sentry/MeasurementUnit;)V + public fun setOperation (Ljava/lang/String;)V + public fun setStatus (Lio/sentry/SpanStatus;)V + public fun setTag (Ljava/lang/String;Ljava/lang/String;)V + public fun setThrowable (Ljava/lang/Throwable;)V + public fun setTransactionName (Ljava/lang/String;)V + public fun setTransactionName (Ljava/lang/String;Lio/sentry/protocol/TransactionNameSource;)V + public fun startChild (Lio/sentry/SpanContext;Lio/sentry/SpanOptions;)Lio/sentry/ISpan; + 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;Lio/sentry/SentryDate;Lio/sentry/Instrumenter;)Lio/sentry/ISpan; + public fun startChild (Ljava/lang/String;Ljava/lang/String;Lio/sentry/SentryDate;Lio/sentry/Instrumenter;Lio/sentry/SpanOptions;)Lio/sentry/ISpan; + public fun startChild (Ljava/lang/String;Ljava/lang/String;Lio/sentry/SpanOptions;)Lio/sentry/ISpan; + public fun storeInContext (Lio/opentelemetry/context/Context;)Lio/opentelemetry/context/Context; + public fun toBaggageHeader (Ljava/util/List;)Lio/sentry/BaggageHeader; + public fun toSentryTrace ()Lio/sentry/SentryTraceHeader; + public fun traceContext ()Lio/sentry/TraceContext; + public fun updateEndDate (Lio/sentry/SentryDate;)Z +} + public final class io/sentry/opentelemetry/OtelTransactionSpanForwarder : io/sentry/ITransaction { public fun (Lio/sentry/opentelemetry/IOtelSpanWrapper;)V public fun finish ()V diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelSpanFactory.java b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelSpanFactory.java index 402b83bbfa..547463dcdc 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelSpanFactory.java +++ b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelSpanFactory.java @@ -158,7 +158,11 @@ public OtelSpanFactory() { sentrySpan.getSpanContext().setOrigin(spanOptions.getOrigin()); } - return sentrySpan; + if (sentrySpan == null) { + return null; + } else { + return new OtelStrongRefSpanWrapper(otelSpan, sentrySpan); + } } private @NotNull Tracer getTracer() { diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelStrongRefSpanWrapper.java b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelStrongRefSpanWrapper.java new file mode 100644 index 0000000000..fb02bd8082 --- /dev/null +++ b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelStrongRefSpanWrapper.java @@ -0,0 +1,306 @@ +package io.sentry.opentelemetry; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; +import io.sentry.BaggageHeader; +import io.sentry.IScopes; +import io.sentry.ISentryLifecycleToken; +import io.sentry.ISpan; +import io.sentry.Instrumenter; +import io.sentry.MeasurementUnit; +import io.sentry.SentryDate; +import io.sentry.SentryTraceHeader; +import io.sentry.SpanContext; +import io.sentry.SpanOptions; +import io.sentry.SpanStatus; +import io.sentry.TraceContext; +import io.sentry.TracesSamplingDecision; +import io.sentry.protocol.Contexts; +import io.sentry.protocol.MeasurementValue; +import io.sentry.protocol.SentryId; +import io.sentry.protocol.TransactionNameSource; +import java.util.List; +import java.util.Map; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * This holds a strong reference to the OpenTelemetry span, preventing it from being garbage + * collected. + * + *

IMPORTANT: Only use this carefully. Please read below. + * + *

This class should only be used in cases where Sentry SDK is used to create an OpenTelemetry + * span under the hood that no one holds a reference to otherwise. + * + *

e.g. ITransaction transaction = Sentry.startTransaction(...) Sentry creates an OTel span under + * the hood, but no one would reference it unless this class is used and returned to the user. By + * doing this, we tie the OTel span to the returned Sentry span/transaction which the user can hold + * on to. + */ +@ApiStatus.Internal +public final class OtelStrongRefSpanWrapper implements IOtelSpanWrapper { + + @SuppressWarnings("UnusedVariable") + private final @NotNull Span otelSpan; + + private final @NotNull IOtelSpanWrapper delegate; + + public OtelStrongRefSpanWrapper(@NotNull Span otelSpan, IOtelSpanWrapper delegate) { + this.otelSpan = otelSpan; + this.delegate = delegate; + } + + @Override + public void setTransactionName(@NotNull String name) { + delegate.setTransactionName(name); + } + + @Override + public void setTransactionName(@NotNull String name, @NotNull TransactionNameSource nameSource) { + delegate.setTransactionName(name, nameSource); + } + + @Override + public @Nullable TransactionNameSource getTransactionNameSource() { + return delegate.getTransactionNameSource(); + } + + @Override + public @Nullable String getTransactionName() { + return delegate.getTransactionName(); + } + + @Override + public @NotNull SentryId getTraceId() { + return delegate.getTraceId(); + } + + @Override + public @NotNull Map getData() { + return delegate.getData(); + } + + @Override + public @NotNull Map getMeasurements() { + return delegate.getMeasurements(); + } + + @Override + public @Nullable Boolean isProfileSampled() { + return delegate.isProfileSampled(); + } + + @Override + public @NotNull IScopes getScopes() { + return delegate.getScopes(); + } + + @Override + public @NotNull Map getTags() { + return delegate.getTags(); + } + + @Override + public @NotNull Context storeInContext(Context context) { + return delegate.storeInContext(context); + } + + @Override + public @NotNull ISpan startChild(@NotNull String operation) { + return delegate.startChild(operation); + } + + @Override + public @NotNull ISpan startChild( + @NotNull String operation, @Nullable String description, @NotNull SpanOptions spanOptions) { + return delegate.startChild(operation, description, spanOptions); + } + + @Override + public @NotNull ISpan startChild( + @NotNull SpanContext spanContext, @NotNull SpanOptions spanOptions) { + return delegate.startChild(spanContext, spanOptions); + } + + @Override + public @NotNull ISpan startChild( + @NotNull String operation, + @Nullable String description, + @Nullable SentryDate timestamp, + @NotNull Instrumenter instrumenter) { + return delegate.startChild(operation, description, timestamp, instrumenter); + } + + @Override + public @NotNull ISpan startChild( + @NotNull String operation, + @Nullable String description, + @Nullable SentryDate timestamp, + @NotNull Instrumenter instrumenter, + @NotNull SpanOptions spanOptions) { + return delegate.startChild(operation, description, timestamp, instrumenter, spanOptions); + } + + @Override + public @NotNull ISpan startChild(@NotNull String operation, @Nullable String description) { + return delegate.startChild(operation, description); + } + + @Override + public @NotNull SentryTraceHeader toSentryTrace() { + return delegate.toSentryTrace(); + } + + @Override + public @Nullable TraceContext traceContext() { + return delegate.traceContext(); + } + + @Override + public @Nullable BaggageHeader toBaggageHeader(@Nullable List thirdPartyBaggageHeaders) { + return delegate.toBaggageHeader(thirdPartyBaggageHeaders); + } + + @Override + public void finish() { + delegate.finish(); + } + + @Override + public void finish(@Nullable SpanStatus status) { + delegate.finish(status); + } + + @Override + public void finish(@Nullable SpanStatus status, @Nullable SentryDate timestamp) { + delegate.finish(status, timestamp); + } + + @Override + public void setOperation(@NotNull String operation) { + delegate.setOperation(operation); + } + + @Override + public @NotNull String getOperation() { + return delegate.getOperation(); + } + + @Override + public void setDescription(@Nullable String description) { + delegate.setDescription(description); + } + + @Override + public @Nullable String getDescription() { + return delegate.getDescription(); + } + + @Override + public void setStatus(@Nullable SpanStatus status) { + delegate.setStatus(status); + } + + @Override + public @Nullable SpanStatus getStatus() { + return delegate.getStatus(); + } + + @Override + public void setThrowable(@Nullable Throwable throwable) { + delegate.setThrowable(throwable); + } + + @Override + public @Nullable Throwable getThrowable() { + return delegate.getThrowable(); + } + + @Override + public @NotNull SpanContext getSpanContext() { + return delegate.getSpanContext(); + } + + @Override + public void setTag(@NotNull String key, @NotNull String value) { + delegate.setTag(key, value); + } + + @Override + public @Nullable String getTag(@NotNull String key) { + return delegate.getTag(key); + } + + @Override + public boolean isFinished() { + return delegate.isFinished(); + } + + @Override + public void setData(@NotNull String key, @NotNull Object value) { + delegate.setData(key, value); + } + + @Override + public @Nullable Object getData(@NotNull String key) { + return delegate.getData(key); + } + + @Override + public void setMeasurement(@NotNull String name, @NotNull Number value) { + delegate.setMeasurement(name, value); + } + + @Override + public void setMeasurement( + @NotNull String name, @NotNull Number value, @NotNull MeasurementUnit unit) { + delegate.setMeasurement(name, value, unit); + } + + @Override + public boolean updateEndDate(@NotNull SentryDate date) { + return delegate.updateEndDate(date); + } + + @Override + public @NotNull SentryDate getStartDate() { + return delegate.getStartDate(); + } + + @Override + public @Nullable SentryDate getFinishDate() { + return delegate.getFinishDate(); + } + + @Override + public boolean isNoOp() { + return delegate.isNoOp(); + } + + @Override + public void setContext(@NotNull String key, @NotNull Object context) { + delegate.setContext(key, context); + } + + @Override + public @NotNull Contexts getContexts() { + return delegate.getContexts(); + } + + @Override + public @Nullable Boolean isSampled() { + return delegate.isSampled(); + } + + @Override + public @Nullable TracesSamplingDecision getSamplingDecision() { + return delegate.getSamplingDecision(); + } + + @Override + public @NotNull ISentryLifecycleToken makeCurrent() { + return delegate.makeCurrent(); + } +} From 77d60e45a212e60310137aec1388e40b712ae08c Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Wed, 18 Dec 2024 14:33:40 +0100 Subject: [PATCH 08/18] fix tests --- .../core/EnvelopeFileObserverIntegrationTest.kt | 7 ++++++- .../src/main/java/io/sentry/samples/console/Main.java | 4 ---- .../src/main/kotlin/io/sentry/test/Mocks.kt | 2 ++ sentry/src/test/java/io/sentry/HubAdapterTest.kt | 4 ++++ sentry/src/test/java/io/sentry/ScopesAdapterTest.kt | 4 ++++ sentry/src/test/java/io/sentry/ScopesTest.kt | 11 ++++++++++- 6 files changed, 26 insertions(+), 6 deletions(-) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverIntegrationTest.kt index 69b2eee2ec..9aa7382dcc 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/EnvelopeFileObserverIntegrationTest.kt @@ -52,7 +52,12 @@ class EnvelopeFileObserverIntegrationTest { @AfterTest fun shutdown() { - Files.delete(file.toPath()) + delete(file) + } + + private fun delete(f: File) { + f.listFiles()?.forEach { delete(it) } + Files.delete(f.toPath()) } @Test diff --git a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java index 842485cf26..c27aad737b 100644 --- a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java +++ b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java @@ -13,9 +13,7 @@ import io.sentry.Sentry; import io.sentry.SentryEvent; import io.sentry.SentryLevel; -import io.sentry.SentryOpenTelemetryMode; import io.sentry.SpanStatus; -import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.protocol.Message; import io.sentry.protocol.User; import java.util.Collections; @@ -30,8 +28,6 @@ public static void main(String[] args) throws InterruptedException { options.setDsn( "https://502f25099c204a2fbf4cb16edc5975d1@o447951.ingest.sentry.io/5428563"); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, SentryOpenTelemetryMode.AGENTLESS); - // All events get assigned to the release. See more at // https://docs.sentry.io/workflow/releases/ options.setRelease("io.sentry.samples.console@3.0.0+1"); diff --git a/sentry-test-support/src/main/kotlin/io/sentry/test/Mocks.kt b/sentry-test-support/src/main/kotlin/io/sentry/test/Mocks.kt index 26f0066beb..7296ca5441 100644 --- a/sentry-test-support/src/main/kotlin/io/sentry/test/Mocks.kt +++ b/sentry-test-support/src/main/kotlin/io/sentry/test/Mocks.kt @@ -6,6 +6,7 @@ import io.sentry.ISentryClient import io.sentry.ISentryExecutorService import io.sentry.Scope import io.sentry.Scopes +import io.sentry.Sentry import io.sentry.SentryOptions import io.sentry.backpressure.IBackpressureMonitor import org.mockito.kotlin.any @@ -83,6 +84,7 @@ fun createSentryClientMock(enabled: Boolean = true) = mock().also fun createTestScopes(options: SentryOptions? = null, enabled: Boolean = true, scope: IScope? = null, isolationScope: IScope? = null, globalScope: IScope? = null): Scopes { val optionsToUse = options ?: SentryOptions().also { it.dsn = "https://key@sentry.io/proj" } + Sentry.init(optionsToUse) val scopeToUse = scope ?: Scope(optionsToUse) val isolationScopeToUse = isolationScope ?: Scope(optionsToUse) val globalScopeToUse = globalScope ?: Scope(optionsToUse) diff --git a/sentry/src/test/java/io/sentry/HubAdapterTest.kt b/sentry/src/test/java/io/sentry/HubAdapterTest.kt index f57c45ba4e..de273238b5 100644 --- a/sentry/src/test/java/io/sentry/HubAdapterTest.kt +++ b/sentry/src/test/java/io/sentry/HubAdapterTest.kt @@ -19,6 +19,10 @@ class HubAdapterTest { @BeforeTest fun `set up`() { + Sentry.init { options -> + options.dsn = "https://key@host/proj" + options.shutdownTimeoutMillis = 20 + } Sentry.setCurrentScopes(scopes) } diff --git a/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt b/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt index db2ed593ca..12ef86dc5e 100644 --- a/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt +++ b/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt @@ -19,6 +19,10 @@ class ScopesAdapterTest { @BeforeTest fun `set up`() { + Sentry.init { options -> + options.dsn = "https://key@host/proj" + options.shutdownTimeoutMillis = 20 + } Sentry.setCurrentScopes(scopes) } diff --git a/sentry/src/test/java/io/sentry/ScopesTest.kt b/sentry/src/test/java/io/sentry/ScopesTest.kt index f0e9833cb8..bba4cb5db5 100644 --- a/sentry/src/test/java/io/sentry/ScopesTest.kt +++ b/sentry/src/test/java/io/sentry/ScopesTest.kt @@ -27,6 +27,7 @@ import org.mockito.kotlin.doThrow import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never +import org.mockito.kotlin.reset import org.mockito.kotlin.spy import org.mockito.kotlin.times import org.mockito.kotlin.verify @@ -78,7 +79,13 @@ class ScopesTest { @Test fun `when no dsn available, ctor throws illegal arg`() { - val ex = assertFailsWith { createScopes(SentryOptions()) } + val ex = assertFailsWith { + val options = SentryOptions() + val scopeToUse = Scope(options) + val isolationScopeToUse = Scope(options) + val globalScopeToUse = Scope(options) + Scopes(scopeToUse, isolationScopeToUse, globalScopeToUse, "test") + } assertEquals("Scopes requires a DSN to be instantiated. Considering using the NoOpScopes if no DSN is available.", ex.message) } @@ -91,6 +98,7 @@ class ScopesTest { options.setSerializer(mock()) options.addIntegration(integrationMock) val scopes = createScopes(options) + reset(integrationMock) scopes.forkedScopes("test") verifyNoMoreInteractions(integrationMock) } @@ -104,6 +112,7 @@ class ScopesTest { options.setSerializer(mock()) options.addIntegration(integrationMock) val scopes = createScopes(options) + reset(integrationMock) scopes.forkedCurrentScope("test") verifyNoMoreInteractions(integrationMock) } From 6b69f568485a2791c0dfcab9aede440a581e8b3e Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Wed, 18 Dec 2024 15:30:40 +0100 Subject: [PATCH 09/18] fix build --- .../src/main/java/io/sentry/samples/console/Main.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java index 842485cf26..c27aad737b 100644 --- a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java +++ b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java @@ -13,9 +13,7 @@ import io.sentry.Sentry; import io.sentry.SentryEvent; import io.sentry.SentryLevel; -import io.sentry.SentryOpenTelemetryMode; import io.sentry.SpanStatus; -import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.protocol.Message; import io.sentry.protocol.User; import java.util.Collections; @@ -30,8 +28,6 @@ public static void main(String[] args) throws InterruptedException { options.setDsn( "https://502f25099c204a2fbf4cb16edc5975d1@o447951.ingest.sentry.io/5428563"); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, SentryOpenTelemetryMode.AGENTLESS); - // All events get assigned to the release. See more at // https://docs.sentry.io/workflow/releases/ options.setRelease("io.sentry.samples.console@3.0.0+1"); From cb8746cf0d7729dbfade54d6fa7e2cd2519a4eb3 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Wed, 18 Dec 2024 15:33:02 +0100 Subject: [PATCH 10/18] changelog --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index caa4a295b5..f4c875a974 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,9 +9,11 @@ - To enable the auto configuration of it, please set `-Dotel.java.global-autoconfigure.enabled=true` on the `java` command, when starting your application. - You may also want to set `OTEL_LOGS_EXPORTER=none;OTEL_METRICS_EXPORTER=none;OTEL_TRACES_EXPORTER=none` env vars to not have the log flooded with error messages regarding OpenTelemetry features we don't use. - `OpenTelemetryUtil.applyOpenTelemetryOptions` now takes an enum instead of a boolean for its mode - - Use `AGENT` when using `sentry-opentelemetry-agent` - - Use `AGENTLESS` when using `sentry-opentelemetry-agentless` - - Use `AGENTLESS_SPRING` when using `sentry-opentelemetry-agentless-spring` +- Add `openTelemetryMode` option ([#3994](https://github.com/getsentry/sentry-java/pull/3994)) + - It defaults to `AUTO` meaning the SDK will figure out how to best configure itself for use with OpenTelemetry + - Use `AGENT` when using `sentry-opentelemetry-agent` + - Use `AGENTLESS` when using `sentry-opentelemetry-agentless` + - Use `AGENTLESS_SPRING` when using `sentry-opentelemetry-agentless-spring` ### Fixes From 400b60ee9e6efb9367e4347fee7bd8adadfa141e Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 19 Dec 2024 10:47:30 +0100 Subject: [PATCH 11/18] fix agentless due to late call to SpanFactoryFactory --- .../java/io/sentry/samples/console/Main.java | 4 ---- sentry/src/main/java/io/sentry/Sentry.java | 22 ++++++++++++------- .../main/java/io/sentry/SentryOptions.java | 2 ++ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java index 842485cf26..c27aad737b 100644 --- a/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java +++ b/sentry-samples/sentry-samples-console-opentelemetry-noagent/src/main/java/io/sentry/samples/console/Main.java @@ -13,9 +13,7 @@ import io.sentry.Sentry; import io.sentry.SentryEvent; import io.sentry.SentryLevel; -import io.sentry.SentryOpenTelemetryMode; import io.sentry.SpanStatus; -import io.sentry.opentelemetry.OpenTelemetryUtil; import io.sentry.protocol.Message; import io.sentry.protocol.User; import java.util.Collections; @@ -30,8 +28,6 @@ public static void main(String[] args) throws InterruptedException { options.setDsn( "https://502f25099c204a2fbf4cb16edc5975d1@o447951.ingest.sentry.io/5428563"); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, SentryOpenTelemetryMode.AGENTLESS); - // All events get assigned to the release. See more at // https://docs.sentry.io/workflow/releases/ options.setRelease("io.sentry.samples.console@3.0.0+1"); diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index 8a8f45d281..87657d4a1f 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -300,6 +300,8 @@ private static void init(final @NotNull SentryOptions options, final boolean glo "Sentry has been already initialized. Previous configuration will be overwritten."); } + initForOpenTelemetryMaybe(options); + // load lazy fields of the options in a separate thread try { options.getExecutorService().submit(() -> options.loadLazyFields()); @@ -321,7 +323,6 @@ private static void init(final @NotNull SentryOptions options, final boolean glo final IScope rootIsolationScope = new Scope(options); rootScopes = new Scopes(rootScope, rootIsolationScope, globalScope, "Sentry.init"); - initScopesStorage(options); getScopesStorage().set(rootScopes); initConfigurations(options); @@ -357,6 +358,18 @@ private static void init(final @NotNull SentryOptions options, final boolean glo } } + private static void initForOpenTelemetryMaybe(SentryOptions options) { + if (SentryOpenTelemetryMode.OFF == options.getOpenTelemetryMode()) { + options.setSpanFactory(new DefaultSpanFactory()); +// } else { + // enabling this causes issues with agentless where OTel spans seem to be randomly ended +// options.setSpanFactory(SpanFactoryFactory.create(new LoadClass(), NoOpLogger.getInstance())); + } + initScopesStorage(options); + OpenTelemetryUtil.applyIgnoredSpanOrigins(options, new LoadClass()); + } + + @SuppressWarnings("UnusedMethod") private static void initScopesStorage(SentryOptions options) { getScopesStorage().close(); if (SentryOpenTelemetryMode.OFF == options.getOpenTelemetryMode()) { @@ -500,13 +513,6 @@ private static void initConfigurations(final @NotNull SentryOptions options) { } logger.log(SentryLevel.INFO, "Initializing SDK with DSN: '%s'", options.getDsn()); - OpenTelemetryUtil.applyIgnoredSpanOrigins(options, new LoadClass()); - if (SentryOpenTelemetryMode.OFF == options.getOpenTelemetryMode()) { - options.setSpanFactory(new DefaultSpanFactory()); - } else { - options.setSpanFactory(SpanFactoryFactory.create(new LoadClass(), NoOpLogger.getInstance())); - } - // TODO: read values from conf file, Build conf or system envs // eg release, distinctId, sentryClientName diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 76256c4597..21535a0fe5 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -21,6 +21,7 @@ import io.sentry.transport.NoOpTransportGate; import io.sentry.util.AutoClosableReentrantLock; import io.sentry.util.LazyEvaluator; +import io.sentry.util.LoadClass; import io.sentry.util.Platform; import io.sentry.util.SampleRateUtils; import io.sentry.util.StringUtils; @@ -2636,6 +2637,7 @@ public SentryOptions() { private SentryOptions(final boolean empty) { experimental = new ExperimentalOptions(empty); if (!empty) { + setSpanFactory(SpanFactoryFactory.create(new LoadClass(), NoOpLogger.getInstance())); // SentryExecutorService should be initialized before any // SendCachedEventFireAndForgetIntegration executorService = new SentryExecutorService(); From d444ef7ddd04c2e5e4fb8c03e34a963a9ebb6a9e Mon Sep 17 00:00:00 2001 From: Sentry Github Bot Date: Thu, 19 Dec 2024 09:49:44 +0000 Subject: [PATCH 12/18] Format code --- sentry/src/main/java/io/sentry/Sentry.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index 87657d4a1f..fcd2175730 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -361,9 +361,10 @@ private static void init(final @NotNull SentryOptions options, final boolean glo private static void initForOpenTelemetryMaybe(SentryOptions options) { if (SentryOpenTelemetryMode.OFF == options.getOpenTelemetryMode()) { options.setSpanFactory(new DefaultSpanFactory()); -// } else { + // } else { // enabling this causes issues with agentless where OTel spans seem to be randomly ended -// options.setSpanFactory(SpanFactoryFactory.create(new LoadClass(), NoOpLogger.getInstance())); + // options.setSpanFactory(SpanFactoryFactory.create(new LoadClass(), + // NoOpLogger.getInstance())); } initScopesStorage(options); OpenTelemetryUtil.applyIgnoredSpanOrigins(options, new LoadClass()); From dacc35b1c5c9e63bc5d7a92a9a459572522963f6 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 19 Dec 2024 11:28:41 +0100 Subject: [PATCH 13/18] changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4c875a974..318def381c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ - You may also want to set `OTEL_LOGS_EXPORTER=none;OTEL_METRICS_EXPORTER=none;OTEL_TRACES_EXPORTER=none` env vars to not have the log flooded with error messages regarding OpenTelemetry features we don't use. - `OpenTelemetryUtil.applyOpenTelemetryOptions` now takes an enum instead of a boolean for its mode - Add `openTelemetryMode` option ([#3994](https://github.com/getsentry/sentry-java/pull/3994)) - - It defaults to `AUTO` meaning the SDK will figure out how to best configure itself for use with OpenTelemetry + - It defaults to `AUTO` meaning the SDK will figure out how to best configure itself for use with OpenTelemetry + - Use of OpenTelemetry can also be disabled completely by setting it to `OFF` ([#3995](https://github.com/getsentry/sentry-java/pull/3995)) + - In this case even if OpenTelemetry is present, the Sentry SDK will not use it - Use `AGENT` when using `sentry-opentelemetry-agent` - Use `AGENTLESS` when using `sentry-opentelemetry-agentless` - Use `AGENTLESS_SPRING` when using `sentry-opentelemetry-agentless-spring` From dd37382b0f3e36061959a89cbcff22bf5f7a2436 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 19 Dec 2024 12:57:15 +0100 Subject: [PATCH 14/18] fix order of scope storage close vs scopes close --- sentry/src/main/java/io/sentry/Sentry.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sentry/src/main/java/io/sentry/Sentry.java b/sentry/src/main/java/io/sentry/Sentry.java index fcd2175730..36800f99e8 100644 --- a/sentry/src/main/java/io/sentry/Sentry.java +++ b/sentry/src/main/java/io/sentry/Sentry.java @@ -300,8 +300,6 @@ private static void init(final @NotNull SentryOptions options, final boolean glo "Sentry has been already initialized. Previous configuration will be overwritten."); } - initForOpenTelemetryMaybe(options); - // load lazy fields of the options in a separate thread try { options.getExecutorService().submit(() -> options.loadLazyFields()); @@ -323,6 +321,7 @@ private static void init(final @NotNull SentryOptions options, final boolean glo final IScope rootIsolationScope = new Scope(options); rootScopes = new Scopes(rootScope, rootIsolationScope, globalScope, "Sentry.init"); + initForOpenTelemetryMaybe(options); getScopesStorage().set(rootScopes); initConfigurations(options); From f3056ff816d8e1ec3178746781a0c816c6ef6182 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 19 Dec 2024 13:23:54 +0100 Subject: [PATCH 15/18] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 318def381c..254bc8854f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ - Replace deprecated `SimpleInstrumentation` with `SimplePerformantInstrumentation` for graphql 22 ([#3974](https://github.com/getsentry/sentry-java/pull/3974)) - Cache requests for Spring using Springs `ContentCachingRequestWrapper` instead of our own Wrapper to also cache parameters ([#3641](https://github.com/getsentry/sentry-java/pull/3641)) - Previously only the body was cached which could lead to problems in the FilterChain as Request parameters were not available +- We now hold a strong reference to the underlying OpenTelemetry span when it is created through Sentry API ([#3997](https://github.com/getsentry/sentry-java/pull/3997)) + - This keeps it from being garbage collected too early ## 8.0.0-rc.2 From 46930d16ad6e7db9185591465afb10cdaf916567 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 20 Dec 2024 05:01:41 +0100 Subject: [PATCH 16/18] use initForTest --- sentry/src/test/java/io/sentry/HubAdapterTest.kt | 9 ++++----- sentry/src/test/java/io/sentry/ScopesAdapterTest.kt | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/sentry/src/test/java/io/sentry/HubAdapterTest.kt b/sentry/src/test/java/io/sentry/HubAdapterTest.kt index a70da6cb1a..76e79b0e48 100644 --- a/sentry/src/test/java/io/sentry/HubAdapterTest.kt +++ b/sentry/src/test/java/io/sentry/HubAdapterTest.kt @@ -3,6 +3,7 @@ package io.sentry import io.sentry.protocol.SentryTransaction import io.sentry.protocol.User import io.sentry.test.createSentryClientMock +import io.sentry.test.initForTest import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.eq @@ -19,11 +20,9 @@ class HubAdapterTest { @BeforeTest fun `set up`() { - Sentry.init( - SentryOptions().apply { - dsn = "https://key@localhost/proj" - } - ) + initForTest { + it.dsn = "https://key@localhost/proj" + } Sentry.setCurrentScopes(scopes) } diff --git a/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt b/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt index 8bd26a6232..ea274d438b 100644 --- a/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt +++ b/sentry/src/test/java/io/sentry/ScopesAdapterTest.kt @@ -3,6 +3,7 @@ package io.sentry import io.sentry.protocol.SentryTransaction import io.sentry.protocol.User import io.sentry.test.createSentryClientMock +import io.sentry.test.initForTest import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.eq @@ -19,11 +20,9 @@ class ScopesAdapterTest { @BeforeTest fun `set up`() { - Sentry.init( - SentryOptions().apply { - dsn = "https://key@localhost/proj" - } - ) + initForTest { + it.dsn = "https://key@localhost/proj" + } Sentry.setCurrentScopes(scopes) } From 8833fc9004585f11be64ca1813c18c7da27f95f3 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 20 Dec 2024 05:04:12 +0100 Subject: [PATCH 17/18] use initForTest --- sentry-test-support/src/main/kotlin/io/sentry/test/Mocks.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sentry-test-support/src/main/kotlin/io/sentry/test/Mocks.kt b/sentry-test-support/src/main/kotlin/io/sentry/test/Mocks.kt index 7296ca5441..b30fe3464f 100644 --- a/sentry-test-support/src/main/kotlin/io/sentry/test/Mocks.kt +++ b/sentry-test-support/src/main/kotlin/io/sentry/test/Mocks.kt @@ -6,7 +6,6 @@ import io.sentry.ISentryClient import io.sentry.ISentryExecutorService import io.sentry.Scope import io.sentry.Scopes -import io.sentry.Sentry import io.sentry.SentryOptions import io.sentry.backpressure.IBackpressureMonitor import org.mockito.kotlin.any @@ -84,7 +83,7 @@ fun createSentryClientMock(enabled: Boolean = true) = mock().also fun createTestScopes(options: SentryOptions? = null, enabled: Boolean = true, scope: IScope? = null, isolationScope: IScope? = null, globalScope: IScope? = null): Scopes { val optionsToUse = options ?: SentryOptions().also { it.dsn = "https://key@sentry.io/proj" } - Sentry.init(optionsToUse) + initForTest(optionsToUse) val scopeToUse = scope ?: Scope(optionsToUse) val isolationScopeToUse = isolationScope ?: Scope(optionsToUse) val globalScopeToUse = globalScope ?: Scope(optionsToUse) From b189087638d25bb517e39598622932d03006fb3d Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Fri, 20 Dec 2024 11:23:31 +0100 Subject: [PATCH 18/18] Update sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelStrongRefSpanWrapper.java Co-authored-by: Lukas Bloder --- .../java/io/sentry/opentelemetry/OtelStrongRefSpanWrapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelStrongRefSpanWrapper.java b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelStrongRefSpanWrapper.java index fb02bd8082..f2ea37b335 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelStrongRefSpanWrapper.java +++ b/sentry-opentelemetry/sentry-opentelemetry-bootstrap/src/main/java/io/sentry/opentelemetry/OtelStrongRefSpanWrapper.java @@ -47,7 +47,7 @@ public final class OtelStrongRefSpanWrapper implements IOtelSpanWrapper { private final @NotNull IOtelSpanWrapper delegate; - public OtelStrongRefSpanWrapper(@NotNull Span otelSpan, IOtelSpanWrapper delegate) { + public OtelStrongRefSpanWrapper(@NotNull Span otelSpan, @NotNull IOtelSpanWrapper delegate) { this.otelSpan = otelSpan; this.delegate = delegate; }