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 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..37851c1455 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,7 +8,6 @@ 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; @@ -39,7 +38,6 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) { options -> { options.setEnableExternalConfiguration(true); options.setInitPriority(InitPriority.HIGH); - OpenTelemetryUtil.applyOpenTelemetryOptions(options, 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 1085098eaa..fb433ff598 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 @@ -249,6 +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 } } 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 6dad6ca433..b6a2a18c0f 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 @@ -249,6 +250,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(); + } }