diff --git a/sentry-spring-boot-4/src/main/java/io/sentry/spring/boot4/SentryAutoConfiguration.java b/sentry-spring-boot-4/src/main/java/io/sentry/spring/boot4/SentryAutoConfiguration.java index 2429c1e744..62052497f1 100644 --- a/sentry-spring-boot-4/src/main/java/io/sentry/spring/boot4/SentryAutoConfiguration.java +++ b/sentry-spring-boot-4/src/main/java/io/sentry/spring/boot4/SentryAutoConfiguration.java @@ -11,6 +11,7 @@ import io.sentry.ScopesAdapter; import io.sentry.Sentry; import io.sentry.SentryIntegrationPackageStorage; +import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.protocol.SdkVersion; import io.sentry.quartz.SentryJobListener; @@ -163,7 +164,8 @@ static class OpenTelemetryNoAgentConfiguration {} final @NotNull List> optionsConfigurations, final @NotNull SentryProperties options, final @NotNull ObjectProvider spanFactory, - final @NotNull ObjectProvider gitProperties) { + final @NotNull ObjectProvider gitProperties, + final @NotNull Environment environment) { optionsConfigurations.forEach( optionsConfiguration -> optionsConfiguration.configure(options)); gitProperties.ifAvailable( @@ -185,9 +187,35 @@ static class OpenTelemetryNoAgentConfiguration {} // here we make sure that only classes that extend throwable are set on this field options.getIgnoredExceptionsForType().removeIf(it -> !Throwable.class.isAssignableFrom(it)); Sentry.init(options); + warnForLegacyLogsConfiguration(environment, options); return ScopesAdapter.getInstance(); } + private void warnForLegacyLogsConfiguration( + final @NotNull Environment environment, final @NotNull SentryOptions options) { + if (environment.containsProperty("sentry.logs.enabled")) { + final boolean enableLogs = + Boolean.TRUE.equals(environment.getProperty("sentry.logs.enabled", Boolean.class)); + if (enableLogs) { + options + .getLogger() + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property is no longer supported. Manual " + + "Sentry.logger() calls no longer require it, and automatic logging " + + "integrations now require their own opt-ins."); + } else { + options + .getLogger() + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property no longer disables manual Sentry.logger() " + + "calls. Automatic logging integrations remain disabled unless enabled " + + "through their own opt-ins."); + } + } + } + @Configuration(proxyBeanMethods = false) @ConditionalOnClass(MDC.class) @Open diff --git a/sentry-spring-boot-4/src/test/kotlin/io/sentry/spring/boot4/SentryAutoConfigurationTest.kt b/sentry-spring-boot-4/src/test/kotlin/io/sentry/spring/boot4/SentryAutoConfigurationTest.kt index da87abd5ee..c3a7556e3e 100644 --- a/sentry-spring-boot-4/src/test/kotlin/io/sentry/spring/boot4/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot-4/src/test/kotlin/io/sentry/spring/boot4/SentryAutoConfigurationTest.kt @@ -8,6 +8,7 @@ import io.sentry.EventProcessor import io.sentry.FilterString import io.sentry.Hint import io.sentry.IContinuousProfiler +import io.sentry.ILogger import io.sentry.IProfileConverter import io.sentry.IScopes import io.sentry.ITransportFactory @@ -56,7 +57,9 @@ import org.assertj.core.api.Assertions.assertThat import org.mockito.internal.util.MockUtil.isMock import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.eq import org.mockito.kotlin.mock +import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.quartz.JobExecutionContext @@ -194,6 +197,56 @@ class SentryAutoConfigurationTest { } } + @Test + fun `legacy logs property emits no warning when absent`() { + val logger = mock() + dsnEnabledRunner + .withPropertyValues("sentry.debug=true") + .withBean(ILogger::class.java, { logger }) + .withUserConfiguration(LoggerConfiguration::class.java) + .run { verify(logger, never()).log(eq(SentryLevel.WARNING), any()) } + } + + @Test + fun `legacy logs property true emits migration warning`() { + val logger = mock() + dsnEnabledRunner + .withPropertyValues("sentry.debug=true", "sentry.logs.enabled=true") + .withBean(ILogger::class.java, { logger }) + .withUserConfiguration(LoggerConfiguration::class.java) + .run { + verify(logger) + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property is no longer supported. Manual " + + "Sentry.logger() calls no longer require it, and automatic logging " + + "integrations now require their own opt-ins.", + *emptyArray(), + ) + assertThat(it.getBean(SentryProperties::class.java).logging.isEnableLogs).isFalse() + } + } + + @Test + fun `legacy logs property false emits migration warning`() { + val logger = mock() + dsnEnabledRunner + .withPropertyValues("sentry.debug=true", "sentry.logs.enabled=false") + .withBean(ILogger::class.java, { logger }) + .withUserConfiguration(LoggerConfiguration::class.java) + .run { + verify(logger) + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property no longer disables manual Sentry.logger() " + + "calls. Automatic logging integrations remain disabled unless enabled through " + + "their own opt-ins.", + *emptyArray(), + ) + assertThat(it.getBean(SentryProperties::class.java).logging.isEnableLogs).isFalse() + } + } + @Test fun `properties are applied to SentryOptions`() { contextRunner @@ -1284,6 +1337,13 @@ class SentryAutoConfigurationTest { @Bean open fun sentryTransport() = transport } + @Configuration(proxyBeanMethods = false) + open class LoggerConfiguration { + @Bean + open fun loggerConfiguration(logger: ILogger) = + Sentry.OptionsConfiguration { it.setLogger(logger) } + } + @Configuration(proxyBeanMethods = false) open class NoOpTransportConfiguration { diff --git a/sentry-spring-boot-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java b/sentry-spring-boot-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java index e1f8b02627..555f2dcbe3 100644 --- a/sentry-spring-boot-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java +++ b/sentry-spring-boot-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java @@ -11,6 +11,7 @@ import io.sentry.ScopesAdapter; import io.sentry.Sentry; import io.sentry.SentryIntegrationPackageStorage; +import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.protocol.SdkVersion; import io.sentry.quartz.SentryJobListener; @@ -165,7 +166,8 @@ static class OpenTelemetryNoAgentConfiguration {} final @NotNull List> optionsConfigurations, final @NotNull SentryProperties options, final @NotNull ObjectProvider spanFactory, - final @NotNull ObjectProvider gitProperties) { + final @NotNull ObjectProvider gitProperties, + final @NotNull Environment environment) { optionsConfigurations.forEach( optionsConfiguration -> optionsConfiguration.configure(options)); gitProperties.ifAvailable( @@ -187,9 +189,35 @@ static class OpenTelemetryNoAgentConfiguration {} // here we make sure that only classes that extend throwable are set on this field options.getIgnoredExceptionsForType().removeIf(it -> !Throwable.class.isAssignableFrom(it)); Sentry.init(options); + warnForLegacyLogsConfiguration(environment, options); return ScopesAdapter.getInstance(); } + private void warnForLegacyLogsConfiguration( + final @NotNull Environment environment, final @NotNull SentryOptions options) { + if (environment.containsProperty("sentry.logs.enabled")) { + final boolean enableLogs = + Boolean.TRUE.equals(environment.getProperty("sentry.logs.enabled", Boolean.class)); + if (enableLogs) { + options + .getLogger() + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property is no longer supported. Manual " + + "Sentry.logger() calls no longer require it, and automatic logging " + + "integrations now require their own opt-ins."); + } else { + options + .getLogger() + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property no longer disables manual Sentry.logger() " + + "calls. Automatic logging integrations remain disabled unless enabled " + + "through their own opt-ins."); + } + } + } + @Configuration(proxyBeanMethods = false) @ConditionalOnClass(MDC.class) @Open diff --git a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt index 4887ef837f..1ce6c8071e 100644 --- a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt @@ -9,6 +9,7 @@ import io.sentry.EventProcessor import io.sentry.FilterString import io.sentry.Hint import io.sentry.IContinuousProfiler +import io.sentry.ILogger import io.sentry.IProfileConverter import io.sentry.IScopes import io.sentry.ITransportFactory @@ -59,7 +60,9 @@ import org.assertj.core.api.Assertions.assertThat import org.mockito.internal.util.MockUtil.isMock import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.eq import org.mockito.kotlin.mock +import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.quartz.JobExecutionContext @@ -197,6 +200,56 @@ class SentryAutoConfigurationTest { } } + @Test + fun `legacy logs property emits no warning when absent`() { + val logger = mock() + dsnEnabledRunner + .withPropertyValues("sentry.debug=true") + .withBean(ILogger::class.java, { logger }) + .withUserConfiguration(LoggerConfiguration::class.java) + .run { verify(logger, never()).log(eq(SentryLevel.WARNING), any()) } + } + + @Test + fun `legacy logs property true emits migration warning`() { + val logger = mock() + dsnEnabledRunner + .withPropertyValues("sentry.debug=true", "sentry.logs.enabled=true") + .withBean(ILogger::class.java, { logger }) + .withUserConfiguration(LoggerConfiguration::class.java) + .run { + verify(logger) + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property is no longer supported. Manual " + + "Sentry.logger() calls no longer require it, and automatic logging " + + "integrations now require their own opt-ins.", + *emptyArray(), + ) + assertThat(it.getBean(SentryProperties::class.java).logging.isEnableLogs).isFalse() + } + } + + @Test + fun `legacy logs property false emits migration warning`() { + val logger = mock() + dsnEnabledRunner + .withPropertyValues("sentry.debug=true", "sentry.logs.enabled=false") + .withBean(ILogger::class.java, { logger }) + .withUserConfiguration(LoggerConfiguration::class.java) + .run { + verify(logger) + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property no longer disables manual Sentry.logger() " + + "calls. Automatic logging integrations remain disabled unless enabled through " + + "their own opt-ins.", + *emptyArray(), + ) + assertThat(it.getBean(SentryProperties::class.java).logging.isEnableLogs).isFalse() + } + } + @Test fun `properties are applied to SentryOptions`() { contextRunner @@ -1276,6 +1329,13 @@ class SentryAutoConfigurationTest { @Bean open fun sentryTransport() = transport } + @Configuration(proxyBeanMethods = false) + open class LoggerConfiguration { + @Bean + open fun loggerConfiguration(logger: ILogger) = + Sentry.OptionsConfiguration { it.setLogger(logger) } + } + @Configuration(proxyBeanMethods = false) open class NoOpTransportConfiguration { diff --git a/sentry-spring-boot/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java b/sentry-spring-boot/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java index f89f5c5bb3..0d63b68629 100644 --- a/sentry-spring-boot/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java +++ b/sentry-spring-boot/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java @@ -10,6 +10,7 @@ import io.sentry.ScopesAdapter; import io.sentry.Sentry; import io.sentry.SentryIntegrationPackageStorage; +import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.protocol.SdkVersion; import io.sentry.quartz.SentryJobListener; @@ -160,7 +161,8 @@ static class OpenTelemetryNoAgentConfiguration {} final @NotNull List> optionsConfigurations, final @NotNull SentryProperties options, final @NotNull ObjectProvider spanFactory, - final @NotNull ObjectProvider gitProperties) { + final @NotNull ObjectProvider gitProperties, + final @NotNull Environment environment) { optionsConfigurations.forEach( optionsConfiguration -> optionsConfiguration.configure(options)); gitProperties.ifAvailable( @@ -182,9 +184,35 @@ static class OpenTelemetryNoAgentConfiguration {} // here we make sure that only classes that extend throwable are set on this field options.getIgnoredExceptionsForType().removeIf(it -> !Throwable.class.isAssignableFrom(it)); Sentry.init(options); + warnForLegacyLogsConfiguration(environment, options); return ScopesAdapter.getInstance(); } + private void warnForLegacyLogsConfiguration( + final @NotNull Environment environment, final @NotNull SentryOptions options) { + if (environment.containsProperty("sentry.logs.enabled")) { + final boolean enableLogs = + Boolean.TRUE.equals(environment.getProperty("sentry.logs.enabled", Boolean.class)); + if (enableLogs) { + options + .getLogger() + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property is no longer supported. Manual " + + "Sentry.logger() calls no longer require it, and automatic logging " + + "integrations now require their own opt-ins."); + } else { + options + .getLogger() + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property no longer disables manual Sentry.logger() " + + "calls. Automatic logging integrations remain disabled unless enabled " + + "through their own opt-ins."); + } + } + } + @Configuration(proxyBeanMethods = false) @ConditionalOnClass(MDC.class) @Open diff --git a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt index 6a4a251474..b0ee03d657 100644 --- a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt @@ -9,6 +9,7 @@ import io.sentry.EventProcessor import io.sentry.FilterString import io.sentry.Hint import io.sentry.IContinuousProfiler +import io.sentry.ILogger import io.sentry.IProfileConverter import io.sentry.IScopes import io.sentry.ITransportFactory @@ -59,7 +60,9 @@ import org.assertj.core.api.Assertions.assertThat import org.mockito.internal.util.MockUtil.isMock import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.eq import org.mockito.kotlin.mock +import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.quartz.JobExecutionContext @@ -195,6 +198,56 @@ class SentryAutoConfigurationTest { } } + @Test + fun `legacy logs property emits no warning when absent`() { + val logger = mock() + dsnEnabledRunner + .withPropertyValues("sentry.debug=true") + .withBean(ILogger::class.java, { logger }) + .withUserConfiguration(LoggerConfiguration::class.java) + .run { verify(logger, never()).log(eq(SentryLevel.WARNING), any()) } + } + + @Test + fun `legacy logs property true emits migration warning`() { + val logger = mock() + dsnEnabledRunner + .withPropertyValues("sentry.debug=true", "sentry.logs.enabled=true") + .withBean(ILogger::class.java, { logger }) + .withUserConfiguration(LoggerConfiguration::class.java) + .run { + verify(logger) + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property is no longer supported. Manual " + + "Sentry.logger() calls no longer require it, and automatic logging " + + "integrations now require their own opt-ins.", + *emptyArray(), + ) + assertThat(it.getBean(SentryProperties::class.java).logging.isEnableLogs).isFalse() + } + } + + @Test + fun `legacy logs property false emits migration warning`() { + val logger = mock() + dsnEnabledRunner + .withPropertyValues("sentry.debug=true", "sentry.logs.enabled=false") + .withBean(ILogger::class.java, { logger }) + .withUserConfiguration(LoggerConfiguration::class.java) + .run { + verify(logger) + .log( + SentryLevel.WARNING, + "The 'sentry.logs.enabled' property no longer disables manual Sentry.logger() " + + "calls. Automatic logging integrations remain disabled unless enabled through " + + "their own opt-ins.", + *emptyArray(), + ) + assertThat(it.getBean(SentryProperties::class.java).logging.isEnableLogs).isFalse() + } + } + @Test fun `properties are applied to SentryOptions`() { contextRunner @@ -1209,6 +1262,13 @@ class SentryAutoConfigurationTest { @Bean open fun sentryTransport() = transport } + @Configuration(proxyBeanMethods = false) + open class LoggerConfiguration { + @Bean + open fun loggerConfiguration(logger: ILogger) = + Sentry.OptionsConfiguration { it.setLogger(logger) } + } + @Configuration(proxyBeanMethods = false) open class NoOpTransportConfiguration {