From 0cebcd4f359df7e6e1077cb4cfecbb670da3c9eb Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Thu, 20 Nov 2025 13:09:06 +0100 Subject: [PATCH 1/2] Document Spring Boot 4 --- docs/platforms/java/common/async/index.mdx | 121 +++++++++++++ .../java/guides/spring-boot/record-user.mdx | 30 +++ .../java/guides/spring/advanced-usage.mdx | 171 ++++++++++++++++++ .../automatic-instrumentation.mdx | 45 +++++ .../crons/setup/java.spring-boot.mdx | 28 +++ .../getting-started-config/java.spring.mdx | 62 ++++++- .../java.spring-boot.mdx | 13 ++ .../getting-started-install/java.spring.mdx | 18 +- .../java.spring-boot.mdx | 7 +- .../getting-started-primer/java.spring.mdx | 5 +- .../java.spring-boot.mdx | 60 ++++++ .../java.spring.mdx | 80 ++++++++ .../enable-tracing/java.spring.mdx | 24 +++ .../java.spring-boot.mdx | 66 +++++++ .../traces-sampler-as-sampler/java.spring.mdx | 66 +++++++ 15 files changed, 791 insertions(+), 5 deletions(-) diff --git a/docs/platforms/java/common/async/index.mdx b/docs/platforms/java/common/async/index.mdx index ac56253155f0cc..56195784f89f37 100644 --- a/docs/platforms/java/common/async/index.mdx +++ b/docs/platforms/java/common/async/index.mdx @@ -65,6 +65,32 @@ class AsyncWebMvcConfiguration implements WebMvcConfigurer { } ``` +```java {tabTitle:Java (Spring 7)} +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.AsyncTaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import io.sentry.spring7.SentryTaskDecorator; + +@Configuration +class AsyncWebMvcConfiguration implements WebMvcConfigurer { + + @Override + public void configureAsyncSupport(AsyncSupportConfigurer configurer) { + configurer.setTaskExecutor(asyncExecutor()); + } + + private AsyncTaskExecutor asyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setTaskDecorator(new SentryTaskDecorator()); + executor.initialize(); + return executor; + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import org.springframework.context.annotation.Configuration import org.springframework.core.task.AsyncTaskExecutor @@ -113,6 +139,30 @@ class AsyncWebMvcConfiguration : WebMvcConfigurer { } ``` +```kotlin {tabTitle:Kotlin (Spring 7)} +import org.springframework.context.annotation.Configuration +import org.springframework.core.task.AsyncTaskExecutor +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer + +import io.sentry.spring7.SentryTaskDecorator + +@Configuration +class AsyncWebMvcConfiguration : WebMvcConfigurer { + override fun configureAsyncSupport(configurer: AsyncSupportConfigurer) { + configurer.setTaskExecutor(asyncExecutor()) + } + + private fun asyncExecutor(): AsyncTaskExecutor { + val executor = ThreadPoolTaskExecutor() + executor.setTaskDecorator(SentryTaskDecorator()) + executor.initialize() + return executor + } +} +``` + Alternatively, if there is a single bean of type `TaskDecorator` in the context, instead of custom `WebMvcConfigurer`, it is enough to create a `SentryTaskDecorator` bean. @@ -149,6 +199,22 @@ class SentryConfig { } ``` +```java {tabTitle:Java (Spring 7)} +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import io.sentry.spring7.SentryTaskDecorator; + +@Configuration +class SentryConfig { + + @Bean + public SentryTaskDecorator sentryTaskDecorator() { + return new SentryTaskDecorator(); + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -177,6 +243,20 @@ class SentryConfig { } ``` +```kotlin {tabTitle:Kotlin (Spring 7)} +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +import io.sentry.spring7.SentryTaskDecorator + +@Configuration +class SentryConfig { + + @Bean + fun sentryTaskDecorator() = SentryTaskDecorator() +} +``` + ## Configuring @Async Methods Task Executor @@ -225,6 +305,27 @@ class AsyncMethodConfiguration extends AsyncConfigurerSupport { } ``` +```java {tabTitle:Java (Spring 7)} +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurerSupport; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import io.sentry.spring7.SentryTaskDecorator; + +import java.util.concurrent.Executor; + +@Configuration +class AsyncMethodConfiguration extends AsyncConfigurerSupport { + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setTaskDecorator(new SentryTaskDecorator()); + executor.initialize(); + return executor; + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import org.springframework.context.annotation.Configuration import org.springframework.scheduling.annotation.AsyncConfigurerSupport @@ -264,3 +365,23 @@ class AsyncMethodConfiguration : AsyncConfigurerSupport() { } } ``` + +```kotlin {tabTitle:Kotlin (Spring 7)} +import org.springframework.context.annotation.Configuration +import org.springframework.scheduling.annotation.AsyncConfigurerSupport +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor + +import io.sentry.spring7.SentryTaskDecorator + +import java.util.concurrent.Executor + +@Configuration +class AsyncMethodConfiguration : AsyncConfigurerSupport() { + override fun getAsyncExecutor(): Executor { + val executor = ThreadPoolTaskExecutor() + executor.setTaskDecorator(SentryTaskDecorator()) + executor.initialize() + return executor + } +} +``` diff --git a/docs/platforms/java/guides/spring-boot/record-user.mdx b/docs/platforms/java/guides/spring-boot/record-user.mdx index 2bfd90a7635a5d..02696997a448d7 100644 --- a/docs/platforms/java/guides/spring-boot/record-user.mdx +++ b/docs/platforms/java/guides/spring-boot/record-user.mdx @@ -57,6 +57,21 @@ class CustomSentryUserProvider implements SentryUserProvider { } ``` +```java {tabTitle:Java (Spring Boot 4)} +import org.springframework.stereotype.Component; +import io.sentry.protocol.User; +import io.sentry.spring7.SentryUserProvider; + +@Component +class CustomSentryUserProvider implements SentryUserProvider { + public User provideUser() { + User user = new User(); + // ... set user information + return user + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring Boot 2)} import org.springframework.stereotype.Component import io.sentry.protocol.User @@ -86,3 +101,18 @@ class CustomSentryUserProvider : SentryUserProvider { } } ``` + +```kotlin {tabTitle:Kotlin (Spring Boot 4)} +import org.springframework.stereotype.Component +import io.sentry.protocol.User +import io.sentry.spring7.SentryUserProvider + +@Component +class CustomSentryUserProvider : SentryUserProvider { + override fun provideUser(): User? { + val user = User() + // ... set user information + return user + } +} +``` diff --git a/docs/platforms/java/guides/spring/advanced-usage.mdx b/docs/platforms/java/guides/spring/advanced-usage.mdx index d186f0d8023fc0..1763641d4f3636 100644 --- a/docs/platforms/java/guides/spring/advanced-usage.mdx +++ b/docs/platforms/java/guides/spring/advanced-usage.mdx @@ -33,6 +33,16 @@ class SentryConfiguration { } ``` +```Java {tabTitle:Java (Spring 7)} +import org.springframework.context.annotation.Configuration; +import io.sentry.spring7.EnableSentry; + +@EnableSentry(dsn = "___PUBLIC_DSN___", sendDefaultPii = true) +@Configuration +class SentryConfiguration { +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import org.springframework.context.annotation.Configuration import io.sentry.spring.EnableSentry @@ -51,6 +61,15 @@ import io.sentry.spring.jakarta.EnableSentry class SentryConfiguration ``` +```kotlin {tabTitle:Kotlin (Spring 7)} +import org.springframework.context.annotation.Configuration +import io.sentry.spring7.EnableSentry + +@EnableSentry(dsn = "...", sendDefaultPii = true) +@Configuration +class SentryConfiguration +``` + 2. Register the servlet filter bean `SentryUserFilter`: ```java {tabTitle:Java (Spring 5)} @@ -91,6 +110,25 @@ public class SentryFilterConfig { } ``` +```java {tabTitle:Java (Spring 7)} +import io.sentry.IHub; +import io.sentry.spring7.SentryUserFilter; +import io.sentry.spring7.SentryUserProvider; +import java.util.List; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SentryFilterConfig { + + @Bean + public SentryUserFilter sentryUserFilter( + final IHub hub, final List sentryUserProviders) { + return new SentryUserFilter(hub, sentryUserProviders); + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import io.sentry.IHub import io.sentry.spring.SentryUserProvider @@ -119,6 +157,20 @@ class SentryFilterConfig { } ``` +```kotlin {tabTitle:Kotlin (Spring 7)} +import io.sentry.IHub +import io.sentry.spring7.SentryUserProvider +import io.sentry.spring7.SentryUserFilter +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class SentryFilterConfig { + @Bean + fun sentryUserFilter(hub: IHub, sentryUserProviders: List) = SentryUserFilter(hub, sentryUserProviders) +} +``` + 3. Configure `SentryUserFilter` in `web.xml` or `WebApplicationInitializer` using `DelegatingFilterProxy`: ```java {tabTitle:Java (Spring 5)} @@ -183,6 +235,37 @@ public class AppInitializer extends AbstractAnnotationConfigDispatcherServletIni } ``` +```java {tabTitle:Java (Spring 7)} +import jakarta.servlet.Filter; +import org.springframework.web.filter.DelegatingFilterProxy; +import org.springframework.web.filter.RequestContextFilter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + + // ... + + @Override + protected Filter[] getServletFilters() { + // filter required by Spring Security + DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy(); + springSecurityFilterChain.setTargetBeanName("springSecurityFilterChain"); + + // sets request on RequestContextHolder + // alternatively configure RequestContextListener + RequestContextFilter requestContextFilter = new RequestContextFilter(); + + // sets Sentry user on the scope + DelegatingFilterProxy sentryUserFilterProxy = new DelegatingFilterProxy(); + sentryUserFilterProxy.setTargetBeanName("sentryUserFilter"); + + return new Filter[] { + springSecurityFilterChain, requestContextFilter, sentryUserFilterProxy + }; + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import org.springframework.web.filter.DelegatingFilterProxy import org.springframework.web.filter.RequestContextFilter @@ -241,6 +324,35 @@ class AppInitializer : AbstractAnnotationConfigDispatcherServletInitializer() { } ``` +```kotlin {tabTitle:Kotlin (Spring 7)} +import org.springframework.web.filter.DelegatingFilterProxy +import org.springframework.web.filter.RequestContextFilter +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer +import jakarta.servlet.Filter + +class AppInitializer : AbstractAnnotationConfigDispatcherServletInitializer() { + + // ... + + override fun getServletFilters(): Array { + // filter required by Spring Security + val springSecurityFilterChain = DelegatingFilterProxy() + springSecurityFilterChain.setTargetBeanName("springSecurityFilterChain") + + // sets request on RequestContextHolder + // alternatively configure RequestContextListener + val requestContextFilter = RequestContextFilter() + + // sets Sentry user on the scope + val sentryUserFilterProxy = DelegatingFilterProxy() + sentryUserFilterProxy.setTargetBeanName("sentryUserFilter") + return arrayOf( + springSecurityFilterChain, requestContextFilter, sentryUserFilterProxy + ) + } +} +``` + By default, the username is retrieved from `HttpServletRequest#userPrincipal`. To retrieve the username from Spring Security context, register the `SpringSecuritySentryUserProvider` bean: ```java {tabTitle:Java (Spring 5)} @@ -275,6 +387,22 @@ class SecuritySentryConfig { } ``` +```java {tabTitle:Java (Spring 7)} +import io.sentry.SentryOptions; +import io.sentry.spring7.SpringSecuritySentryUserProvider; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +class SecuritySentryConfig { + @Bean + public SpringSecuritySentryUserProvider springSecuritySentryUserProvider( + SentryOptions sentryOptions) { + return new SpringSecuritySentryUserProvider(sentryOptions); + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import io.sentry.SentryOptions import io.sentry.spring.SpringSecuritySentryUserProvider @@ -301,6 +429,19 @@ class SecuritySentryConfig { } ``` +```kotlin {tabTitle:Kotlin (Spring 7)} +import io.sentry.SentryOptions +import io.sentry.spring7.SpringSecuritySentryUserProvider +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class SecuritySentryConfig { + @Bean + fun springSecuritySentryUserProvider(sentryOptions: SentryOptions) = SpringSecuritySentryUserProvider(sentryOptions) +} +``` + ## Recording Custom User Information To record custom user information, you can register a bean that implements `SentryUserProvider` interface. @@ -335,6 +476,21 @@ class CustomSentryUserProvider implements SentryUserProvider { } ``` +```java {tabTitle:Java (Spring 7)} +import org.springframework.stereotype.Component; +import io.sentry.protocol.User; +import io.sentry.spring7.SentryUserProvider; + +@Component +class CustomSentryUserProvider implements SentryUserProvider { + public User provideUser() { + User user = User(); + // ... set user information + return user + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import org.springframework.stereotype.Component import io.sentry.protocol.User @@ -364,3 +520,18 @@ class CustomSentryUserProvider : SentryUserProvider { } } ``` + +```kotlin {tabTitle:Kotlin (Spring 7)} +import org.springframework.stereotype.Component +import io.sentry.protocol.User +import io.sentry.spring7.SentryUserProvider + +@Component +class CustomSentryUserProvider : SentryUserProvider { + override fun provideUser(): User? { + val user = User() + // ... set user information + return user + } +} +``` diff --git a/docs/platforms/java/guides/spring/tracing/instrumentation/automatic-instrumentation.mdx b/docs/platforms/java/guides/spring/tracing/instrumentation/automatic-instrumentation.mdx index c4cbc06b0bd532..786cb1fdccc719 100644 --- a/docs/platforms/java/guides/spring/tracing/instrumentation/automatic-instrumentation.mdx +++ b/docs/platforms/java/guides/spring/tracing/instrumentation/automatic-instrumentation.mdx @@ -96,6 +96,29 @@ class AppConfig { } ``` +```java {tabTitle:Java (Spring 7)} +import io.sentry.IScopes; +import io.sentry.spring7.tracing.SentrySpanClientHttpRequestInterceptor; +import java.util.Collections; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriTemplateHandler; + +@Configuration +class AppConfig { + + @Bean + RestTemplate restTemplate(IScopes scopes) { + RestTemplate restTemplate = new RestTemplate(); + SentrySpanClientHttpRequestInterceptor sentryRestTemplateInterceptor = + new SentrySpanClientHttpRequestInterceptor(scopes); + restTemplate.setInterceptors(Collections.singletonList(sentryRestTemplateInterceptor)); + return restTemplate; + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import io.sentry.IScopes import io.sentry.spring.tracing.SentrySpanClientHttpRequestInterceptor @@ -139,3 +162,25 @@ class AppConfig { } } ``` + +```kotlin {tabTitle:Kotlin (Spring 7)} +import io.sentry.IScopes +import io.sentry.spring7.tracing.SentrySpanClientHttpRequestInterceptor +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.web.client.RestTemplate +import org.springframework.web.util.UriTemplateHandler + +@Configuration +class AppConfig { + + @Bean + fun restTemplate(scopes: IScopes): RestTemplate { + val sentryRestTemplateInterceptor = SentrySpanClientHttpRequestInterceptor(scopes) + + return RestTemplate().apply { + interceptors = listOf(sentryRestTemplateInterceptor) + } + } +} +``` diff --git a/platform-includes/crons/setup/java.spring-boot.mdx b/platform-includes/crons/setup/java.spring-boot.mdx index 73a9b6af2ce6df..fdf6d40167986a 100644 --- a/platform-includes/crons/setup/java.spring-boot.mdx +++ b/platform-includes/crons/setup/java.spring-boot.mdx @@ -18,6 +18,20 @@ public class CustomJob { } ``` +```java {tabTitle:Java (Spring Boot 4)} +import io.sentry.spring7.checkin.SentryCheckIn; + +@Component +public class CustomJob { + + @Scheduled(fixedRate = 3 * 60 * 1000L) + @SentryCheckIn("") // 👈 + void execute() throws InterruptedException { + // your task code + } +} +``` + ```java {tabTitle:Java (Spring Boot 2)} import io.sentry.spring.checkin.SentryCheckIn; @@ -50,6 +64,20 @@ public class CustomJob { } ``` +```java {tabTitle:Java (Spring Boot 4)} +import io.sentry.spring7.checkin.SentryCheckIn; + +@Component +public class CustomJob { + + @Scheduled(fixedRate = 3 * 60 * 1000L) + @SentryCheckIn(monitorSlug = "", heartbeat = true) // 👈 + void execute() throws InterruptedException { + // your task code + } +} +``` + ```java {tabTitle:Java (Spring Boot 2)} import io.sentry.spring.checkin.SentryCheckIn; diff --git a/platform-includes/getting-started-config/java.spring.mdx b/platform-includes/getting-started-config/java.spring.mdx index 247bf30a25d6ee..8747a1d507de0e 100644 --- a/platform-includes/getting-started-config/java.spring.mdx +++ b/platform-includes/getting-started-config/java.spring.mdx @@ -1,6 +1,6 @@ Configuration should happen as early as possible in your application's lifecycle. -The `sentry-spring` and `sentry-spring-jakarta` libraries provide an `@EnableSentry` annotation that registers all required Spring beans. `@EnableSentry` can be placed on any class annotated with [@Configuration](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html) including the main entry class in Spring Boot applications annotated with [@SpringBootApplication](https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/SpringBootApplication.html). +The `sentry-spring`, `sentry-spring-jakarta`, and `sentry-spring-7` libraries provide an `@EnableSentry` annotation that registers all required Spring beans. `@EnableSentry` can be placed on any class annotated with [@Configuration](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html) including the main entry class in Spring Boot applications annotated with [@SpringBootApplication](https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/SpringBootApplication.html). ```java {tabTitle:Java (Spring 5)} @@ -33,6 +33,21 @@ class SentryConfiguration { } ``` +```java {tabTitle:Java (Spring 7)} +import io.sentry.spring7.EnableSentry; +// NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry +// project/dashboard +@EnableSentry( + dsn = "___PUBLIC_DSN___", + // Add data like request headers and IP for users, + // see https://docs.sentry.io/platforms/java/guides/spring/data-management/data-collected/ for more info + sendDefaultPii = true +) +@Configuration +class SentryConfiguration { +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import io.sentry.spring.EnableSentry // NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry @@ -61,6 +76,20 @@ import io.sentry.spring.jakarta.EnableSentry class SentryConfiguration ``` +```kotlin {tabTitle:Kotlin (Spring 7)} +import io.sentry.spring7.EnableSentry +// NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry +// project/dashboard +@EnableSentry( + dsn = "___PUBLIC_DSN___", + // Add data like request headers and IP for users, + // see https://docs.sentry.io/platforms/java/guides/spring/data-management/data-collected/ for more info + sendDefaultPii = true +) +@Configuration +class SentryConfiguration +``` + The DSN can be also provided through the system property `sentry.dsn`, environment variable `SENTRY_DSN` or the `dsn` property in `sentry.properties` file. [See the configuration page](/platforms/java/configuration/) for more details on external configuration. Once this integration is configured you can _also_ use Sentry’s static API, [as shown on the usage page](usage/), to record breadcrumbs, set the current user, or manually send events, for example. @@ -100,6 +129,22 @@ class SentryConfiguration { } ``` +```java {tabTitle:Java (Spring 7)} +import io.sentry.spring7.EnableSentry; +import org.springframework.core.Ordered; +// NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry +// project/dashboard +@EnableSentry( + dsn = "___PUBLIC_DSN___", + // Add data like request headers and IP for users, + // see https://docs.sentry.io/platforms/java/guides/spring/data-management/data-collected/ for more info + sendDefaultPii = true, + exceptionResolverOrder = Ordered.LOWEST_PRECEDENCE +) +class SentryConfiguration { +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import io.sentry.spring.EnableSentry import org.springframework.core.Ordered @@ -130,6 +175,21 @@ import org.springframework.core.Ordered class SentryConfiguration ``` +```kotlin {tabTitle:Kotlin (Spring 7)} +import io.sentry.spring7.EnableSentry +import org.springframework.core.Ordered +// NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry +// project/dashboard +@EnableSentry( + dsn = "___PUBLIC_DSN___", + // Add data like request headers and IP for users, + // see https://docs.sentry.io/platforms/java/guides/spring/data-management/data-collected/ for more info + sendDefaultPii = true, + exceptionResolverOrder = Ordered.LOWEST_PRECEDENCE +) +class SentryConfiguration +``` + The SDK can be configured using a `sentry.properties` file: diff --git a/platform-includes/getting-started-install/java.spring-boot.mdx b/platform-includes/getting-started-install/java.spring-boot.mdx index 70653aee7b55b6..90f0a766308012 100644 --- a/platform-includes/getting-started-install/java.spring-boot.mdx +++ b/platform-includes/getting-started-install/java.spring-boot.mdx @@ -51,6 +51,10 @@ implementation 'io.sentry:sentry-spring-boot-starter:{{@inject packages.version( implementation 'io.sentry:sentry-spring-boot-starter-jakarta:{{@inject packages.version('sentry.java.spring-boot.jakarta', '6.7.0') }}' ``` +```groovy {tabTitle:Gradle (Spring Boot 4)} +implementation 'io.sentry:sentry-spring-boot-4:{{@inject packages.version('sentry.java.spring-boot-4', '8.15.1') }}' +``` + ```xml {tabTitle:Maven (Spring Boot 2)} io.sentry @@ -65,6 +69,15 @@ implementation 'io.sentry:sentry-spring-boot-starter-jakarta:{{@inject packages. sentry-spring-boot-starter-jakarta {{@inject packages.version('sentry.java.spring-boot.jakarta', '6.7.0') }} +``` + +```xml {tabTitle:Maven (Spring Boot 4)} + + io.sentry + sentry-spring-boot-4 + {{@inject packages.version('sentry.java.spring-boot-4', '8.15.1') }} + +``` diff --git a/platform-includes/getting-started-install/java.spring.mdx b/platform-includes/getting-started-install/java.spring.mdx index 4ee49cd6135d2f..b37dca0f8295fe 100644 --- a/platform-includes/getting-started-install/java.spring.mdx +++ b/platform-includes/getting-started-install/java.spring.mdx @@ -51,6 +51,10 @@ implementation 'io.sentry:sentry-spring:{{@inject packages.version('sentry.java. implementation 'io.sentry:sentry-spring-jakarta:{{@inject packages.version('sentry.java.spring.jakarta', '6.7.0') }}' ``` +```groovy {tabTitle:Gradle (Spring 7)} +implementation 'io.sentry:sentry-spring-7:{{@inject packages.version('sentry.java.spring-7', '8.15.1') }}' +``` + ```xml {tabTitle:Maven (Spring 5)} io.sentry @@ -67,6 +71,14 @@ implementation 'io.sentry:sentry-spring-jakarta:{{@inject packages.version('sent ``` +```xml {tabTitle:Maven (Spring 7)} + + io.sentry + sentry-spring-7 + {{@inject packages.version('sentry.java.spring-7', '8.15.1') }} + +``` + ```scala {tabTitle: SBT (Spring 5)} libraryDependencies += "io.sentry" % "sentry-spring" % "{{@inject packages.version('sentry.java.spring', '4.2.0') }}" ``` @@ -75,7 +87,11 @@ libraryDependencies += "io.sentry" % "sentry-spring" % "{{@inject packages.versi libraryDependencies += "io.sentry" % "sentry-spring-jakarta" % "{{@inject packages.version('sentry.java.spring.jakarta', '6.7.0') }}" ``` -For other dependency managers see the [central Maven repository (Spring 5)](https://search.maven.org/artifact/io.sentry/sentry-spring) and [central Maven repository (Spring 6)](https://search.maven.org/artifact/io.sentry/sentry-spring-jakarta). +```scala {tabTitle: SBT (Spring 7)} +libraryDependencies += "io.sentry" % "sentry-spring-7" % "{{@inject packages.version('sentry.java.spring-7', '8.15.1') }}" +``` + +For other dependency managers see the [central Maven repository (Spring 5)](https://search.maven.org/artifact/io.sentry/sentry-spring), [central Maven repository (Spring 6)](https://search.maven.org/artifact/io.sentry/sentry-spring-jakarta), and [central Maven repository (Spring 7)](https://search.maven.org/artifact/io.sentry/sentry-spring-7). diff --git a/platform-includes/getting-started-primer/java.spring-boot.mdx b/platform-includes/getting-started-primer/java.spring-boot.mdx index 6d356260d9434f..873056beab061e 100644 --- a/platform-includes/getting-started-primer/java.spring-boot.mdx +++ b/platform-includes/getting-started-primer/java.spring-boot.mdx @@ -1,11 +1,14 @@ -There are two variants of Sentry available for Spring Boot. If you're using our Gradle plugin it will pick the right dependency for you. If you're manually adding the dependency and using Spring Boot 2, use `sentry-spring-boot-starter` ([GitHub](https://github.com/getsentry/sentry-java/tree/main/sentry-spring-boot-starter)). If you're using Spring Boot 3, use `sentry-spring-boot-starter-jakarta` instead ([GitHub](https://github.com/getsentry/sentry-java/tree/main/sentry-spring-boot-starter-jakarta)). +There are multiple variants of Sentry available for Spring Boot. If you're using our Gradle plugin it will pick the right dependency for you. If you're manually adding the dependency: +- For Spring Boot 2, use `sentry-spring-boot-starter` ([GitHub](https://github.com/getsentry/sentry-java/tree/main/sentry-spring-boot-starter)) +- For Spring Boot 3, use `sentry-spring-boot-starter-jakarta` ([GitHub](https://github.com/getsentry/sentry-java/tree/main/sentry-spring-boot-starter-jakarta)) +- For Spring Boot 4, use `sentry-spring-boot-4` ([GitHub](https://github.com/getsentry/sentry-java/tree/main/sentry-spring-boot-4)) Sentry's integration with [Spring Boot](https://spring.io/projects/spring-boot) supports Spring Boot 2.1.0 and above to report unhandled exceptions as well as release and registration of beans. If you're on an older version, use [our legacy integration](/platforms/java/legacy/spring/). The minimum version of Spring Boot supported by the Sentry WebFlux integration is, instead, 2.2.5.RELEASE. -The `sentry-spring-boot-starter` and `sentry-spring-boot-starter-jakarta` libraries enhance [Sentry Spring](/platforms/java/guides/spring/) to: +The `sentry-spring-boot-starter`, `sentry-spring-boot-starter-jakarta`, and `sentry-spring-boot-4` libraries enhance [Sentry Spring](/platforms/java/guides/spring/) to: - manage a fine-grained configuration using `application.properties` or `application.yaml` - automatically include the release when [Spring Boot Git integration is configured](https://docs.spring.io/spring-boot/how-to/build.html#howto.build.generate-git-info) diff --git a/platform-includes/getting-started-primer/java.spring.mdx b/platform-includes/getting-started-primer/java.spring.mdx index b07172dae9b521..a30e3ef4084e16 100644 --- a/platform-includes/getting-started-primer/java.spring.mdx +++ b/platform-includes/getting-started-primer/java.spring.mdx @@ -1,6 +1,9 @@ -There are two variants of Sentry available for Spring. If you're using Spring 5, use `sentry-spring` ([GitHub](https://github.com/getsentry/sentry-java/tree/master/sentry-spring)). If you're using Spring 6, use `sentry-spring-jakarta` instead ([GitHub](https://github.com/getsentry/sentry-java/tree/master/sentry-spring-jakarta)). +There are multiple variants of Sentry available for Spring: +- For Spring 5, use `sentry-spring` ([GitHub](https://github.com/getsentry/sentry-java/tree/master/sentry-spring)) +- For Spring 6, use `sentry-spring-jakarta` ([GitHub](https://github.com/getsentry/sentry-java/tree/master/sentry-spring-jakarta)) +- For Spring 7, use `sentry-spring-7` ([GitHub](https://github.com/getsentry/sentry-java/tree/main/sentry-spring-7)) Sentry's integration with [Spring](https://spring.io/projects/spring-framework) supports Spring Framework 5.1.2 and above to report unhandled exceptions and optional user information. If you're on an older version, use [our legacy integration](/platforms/java/legacy/spring/). The minimum version of Spring Framework supported by the Sentry WebFlux integration is, instead, 5.2.4. diff --git a/platform-includes/performance/enable-manual-instrumentation/java.spring-boot.mdx b/platform-includes/performance/enable-manual-instrumentation/java.spring-boot.mdx index 47bb62d25eddc1..104fabbcf1017e 100644 --- a/platform-includes/performance/enable-manual-instrumentation/java.spring-boot.mdx +++ b/platform-includes/performance/enable-manual-instrumentation/java.spring-boot.mdx @@ -49,6 +49,22 @@ class ScheduledJob { } ``` +```java {tabTitle:Java (Spring Boot 4)} +import org.springframework.stereotype.Component; +import org.springframework.scheduling.annotation.Scheduled; +import io.sentry.spring7.tracing.SentryTransaction; + +@Component +class ScheduledJob { + + @Scheduled(...) + @SentryTransaction(operation = "task") + void execute() { + ... + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring Boot 2)} import org.springframework.stereotype.Component import org.springframework.scheduling.annotation.Scheduled @@ -81,6 +97,22 @@ class ScheduledJob { } ``` +```kotlin {tabTitle:Kotlin (Spring Boot 4)} +import org.springframework.stereotype.Component +import org.springframework.scheduling.annotation.Scheduled +import io.sentry.spring7.tracing.SentryTransaction + +@Component +class ScheduledJob { + + @Scheduled(...) + @SentryTransaction(operation = "task") + fun execute() { + ... + } +} +``` + `@SentryTransaction` can be configured with custom `name`. If not defined, `name` will be resolved from the class, and the method name. `@SentryTransaction` can be also placed on a class or an interface - it turns every method execution from the annotated type into a transaction. @@ -119,6 +151,20 @@ class PersonService { } ``` +```java {tabTitle:Java (Spring Boot 4)} +import org.springframework.stereotype.Component; +import io.sentry.spring7.tracing.SentrySpan; + +@Component +class PersonService { + + @SentrySpan + Person findById(Long id) { + ... + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring Boot 2)} import org.springframework.stereotype.Component import io.sentry.spring.tracing.SentrySpan @@ -147,6 +193,20 @@ class PersonService { } ``` +```kotlin {tabTitle:Kotlin (Spring Boot 4)} +import org.springframework.stereotype.Component +import io.sentry.spring7.tracing.SentrySpan + +@Component +class PersonService { + + @SentrySpan(operation = "task") + fun findById(id: Long): Person { + ... + } +} +``` + `@SentrySpan` can be configured with custom `description` property. If not defined, `operation` will be resolved from the class, and the method name. `@SentrySpan` can be also placed on a class or an interface - it turns every method execution from the annotated type into a span. diff --git a/platform-includes/performance/enable-manual-instrumentation/java.spring.mdx b/platform-includes/performance/enable-manual-instrumentation/java.spring.mdx index 00cf47db316f0a..69bf308b463c1f 100644 --- a/platform-includes/performance/enable-manual-instrumentation/java.spring.mdx +++ b/platform-includes/performance/enable-manual-instrumentation/java.spring.mdx @@ -42,6 +42,16 @@ class SentryConfig { } ``` +```java {tabTitle:Java (Spring 7)} +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import io.sentry.spring7.tracing.SentryTracingConfiguration; + +@Import(SentryTracingConfiguration.class) +class SentryConfig { +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import @@ -62,6 +72,16 @@ class SentryConfig { } ``` +```kotlin {tabTitle:Kotlin (Spring 7)} +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Import +import io.sentry.spring7.tracing.SentryTracingConfiguration + +@Import(SentryTracingConfiguration::class) +class SentryConfig { +} +``` + Methods executed outside of Spring MVC request processing can be turned into transactions by annotating them with `@SentryTransaction` annotation: ```java {tabTitle:Java (Spring 5)} @@ -96,6 +116,22 @@ class ScheduledJob { } ``` +```java {tabTitle:Java (Spring 7)} +import org.springframework.stereotype.Component; +import org.springframework.scheduling.annotation.Scheduled; +import io.sentry.spring7.tracing.SentryTransaction; + +@Component +class ScheduledJob { + + @Scheduled(...) + @SentryTransaction(operation = "task") + void execute() { + ... + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import org.springframework.stereotype.Component import org.springframework.scheduling.annotation.Scheduled @@ -128,6 +164,22 @@ class ScheduledJob { } ``` +```kotlin {tabTitle:Kotlin (Spring 7)} +import org.springframework.stereotype.Component +import org.springframework.scheduling.annotation.Scheduled +import io.sentry.spring7.tracing.SentryTransaction + +@Component +class ScheduledJob { + + @Scheduled(...) + @SentryTransaction(operation = "task") + fun execute() { + ... + } +} +``` + `@SentryTransaction` can be configured with custom `name`. If not defined, `name` will be resolved from the class, and the method name. `@SentryTransaction` can be also placed on a class or an interface - it turns every method execution from the annotated type into a transaction. @@ -166,6 +218,20 @@ class PersonService { } ``` +```java {tabTitle:Java (Spring 7)} +import org.springframework.stereotype.Component; +import io.sentry.spring7.tracing.SentrySpan; + +@Component +class PersonService { + + @SentrySpan + Person findById(Long id) { + ... + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import org.springframework.stereotype.Component import io.sentry.spring.tracing.SentrySpan @@ -194,6 +260,20 @@ class PersonService { } ``` +```kotlin {tabTitle:Kotlin (Spring 7)} +import org.springframework.stereotype.Component +import io.sentry.spring7.tracing.SentrySpan + +@Component +class PersonService { + + @SentrySpan(operation = "task") + fun findById(id: Long): Person { + ... + } +} +``` + `@SentrySpan` can be configured with custom `description` property. If not defined, `operation` will be resolved from the class, and the method name. `@SentrySpan` can be also placed on a class or an interface - it turns every method execution from the annotated type into a span. diff --git a/platform-includes/performance/enable-tracing/java.spring.mdx b/platform-includes/performance/enable-tracing/java.spring.mdx index 16fcceb92401a3..28c2beaea093ea 100644 --- a/platform-includes/performance/enable-tracing/java.spring.mdx +++ b/platform-includes/performance/enable-tracing/java.spring.mdx @@ -28,6 +28,20 @@ public class AppInitializer extends AbstractAnnotationConfigDispatcherServletIni } ``` +```java {tabTitle:Java (Spring 7)} +import io.sentry.spring7.tracing.SentryTracingFilter; +import jakarta.servlet.Filter; +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; + +public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + // ... + @Override + protected Filter[] getServletFilters() { + return new Filter[] {new SentryTracingFilter()}; + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring 5)} import io.sentry.spring.tracing.SentryTracingFilter import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer @@ -47,3 +61,13 @@ class AppInitializer : AbstractAnnotationConfigDispatcherServletInitializer() { override fun getServletFilters() = arrayOf(SentryTracingFilter()) } ``` + +```kotlin {tabTitle:Kotlin (Spring 7)} +import io.sentry.spring7.tracing.SentryTracingFilter +import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer + +class AppInitializer : AbstractAnnotationConfigDispatcherServletInitializer() { + // ... + override fun getServletFilters() = arrayOf(SentryTracingFilter()) +} +``` diff --git a/platform-includes/performance/traces-sampler-as-sampler/java.spring-boot.mdx b/platform-includes/performance/traces-sampler-as-sampler/java.spring-boot.mdx index a34f1eb7589175..ce8287cbbc8da1 100644 --- a/platform-includes/performance/traces-sampler-as-sampler/java.spring-boot.mdx +++ b/platform-includes/performance/traces-sampler-as-sampler/java.spring-boot.mdx @@ -56,6 +56,35 @@ class CustomTracesSamplerCallback implements TracesSamplerCallback { } ``` +```java {tabTitle:Java (Spring Boot 4)} +import io.sentry.SamplingContext; +import io.sentry.SentryOptions.TracesSamplerCallback; +import org.springframework.stereotype.Component; +import jakarta.servlet.http.HttpServletRequest; + +@Component +class CustomTracesSamplerCallback implements TracesSamplerCallback { + @Override + public Double sample(SamplingContext context) { + HttpServletRequest request = (HttpServletRequest) context.getCustomSamplingContext().get("request"); + String url = request.getRequestURI(); + if ("/payment".equals(url)) { + // These are important - take a big sample + return 0.5; + } else if ("/search".equals(url)) { + // Search is less important and happen much more frequently - only take 1% + return 0.01; + } else if ("/health".equals(url)) { + // The health check endpoint is just noise - drop all transactions + return 0d; + } else { + // Default sample rate + return 0.1; + } + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring Boot 2)} import io.sentry.SamplingContext import io.sentry.SentryOptions.TracesSamplerCallback @@ -129,3 +158,40 @@ class CustomTracesSamplerCallback : TracesSamplerCallback { } } ``` + +```kotlin {tabTitle:Kotlin (Spring Boot 4)} +import io.sentry.SamplingContext +import io.sentry.SentryOptions.TracesSamplerCallback +import org.springframework.stereotype.Component +import jakarta.servlet.http.HttpServletRequest + +@Component +class CustomTracesSamplerCallback : TracesSamplerCallback { + override fun sample(context: SamplingContext): Double? { + val customSamplingContext = context.customSamplingContext + if (customSamplingContext != null) { + val request = customSamplingContext["request"] as HttpServletRequest + return when (request.requestURI) { + "/payment" -> { + // These are important - take a big sample + 0.5 + } + "/search" -> { + // Search is less important and happen much more frequently - only take 1% + 0.01 + } + "/health" -> { + // The health check endpoint is just noise - drop all transactions + 0.0 + } + else -> { + // Default sample rate + 0.1 + } + } + } else { + return 0.1 + } + } +} +``` diff --git a/platform-includes/performance/traces-sampler-as-sampler/java.spring.mdx b/platform-includes/performance/traces-sampler-as-sampler/java.spring.mdx index af14eaf14663ee..436fd0463dc532 100644 --- a/platform-includes/performance/traces-sampler-as-sampler/java.spring.mdx +++ b/platform-includes/performance/traces-sampler-as-sampler/java.spring.mdx @@ -56,6 +56,35 @@ class CustomTracesSamplerCallback implements TracesSamplerCallback { } ``` +```java {tabTitle:Java (Spring 7)} +import io.sentry.SamplingContext; +import io.sentry.SentryOptions.TracesSamplerCallback; +import org.springframework.stereotype.Component; +import jakarta.servlet.http.HttpServletRequest; + +@Component +class CustomTracesSamplerCallback implements TracesSamplerCallback { + @Override + public Double sample(SamplingContext context) { + HttpServletRequest request = (HttpServletRequest) context.getCustomSamplingContext().get("request"); + String url = request.getRequestURI(); + if ("/payment".equals(url)) { + // These are important - take a big sample + return 0.5; + } else if ("/search".equals(url)) { + // Search is less important and happen much more frequently - only take 1% + return 0.01; + } else if ("/health".equals(url)) { + // The health check endpoint is just noise - drop all transactions + return 0d; + } else { + // Default sample rate + return 0.1; + } + } +} +``` + ```kotlin {tabTitle:Kotlin (Spring Boot 2)} import io.sentry.SamplingContext import io.sentry.SentryOptions.TracesSamplerCallback @@ -129,3 +158,40 @@ class CustomTracesSamplerCallback : TracesSamplerCallback { } } ``` + +```kotlin {tabTitle:Kotlin (Spring Boot 4)} +import io.sentry.SamplingContext +import io.sentry.SentryOptions.TracesSamplerCallback +import org.springframework.stereotype.Component +import jakarta.servlet.http.HttpServletRequest + +@Component +class CustomTracesSamplerCallback : TracesSamplerCallback { + override fun sample(context: SamplingContext): Double? { + val customSamplingContext = context.customSamplingContext + if (customSamplingContext != null) { + val request = customSamplingContext["request"] as HttpServletRequest + return when (request.requestURI) { + "/payment" -> { + // These are important - take a big sample + 0.5 + } + "/search" -> { + // Search is less important and happen much more frequently - only take 1% + 0.01 + } + "/health" -> { + // The health check endpoint is just noise - drop all transactions + 0.0 + } + else -> { + // Default sample rate + 0.1 + } + } + } else { + return 0.1 + } + } +} +``` From 219b70fa6871afba57702a65a71e0c22c50f0083 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 24 Nov 2025 10:50:16 +0100 Subject: [PATCH 2/2] change Spring Boot to Spring --- .../performance/traces-sampler-as-sampler/java.spring.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform-includes/performance/traces-sampler-as-sampler/java.spring.mdx b/platform-includes/performance/traces-sampler-as-sampler/java.spring.mdx index 436fd0463dc532..14599b99f8ffc5 100644 --- a/platform-includes/performance/traces-sampler-as-sampler/java.spring.mdx +++ b/platform-includes/performance/traces-sampler-as-sampler/java.spring.mdx @@ -85,7 +85,7 @@ class CustomTracesSamplerCallback implements TracesSamplerCallback { } ``` -```kotlin {tabTitle:Kotlin (Spring Boot 2)} +```kotlin {tabTitle:Kotlin (Spring 5)} import io.sentry.SamplingContext import io.sentry.SentryOptions.TracesSamplerCallback import org.springframework.stereotype.Component @@ -122,7 +122,7 @@ class CustomTracesSamplerCallback : TracesSamplerCallback { } ``` -```kotlin {tabTitle:Kotlin (Spring Boot 3)} +```kotlin {tabTitle:Kotlin (Spring 6)} import io.sentry.SamplingContext import io.sentry.SentryOptions.TracesSamplerCallback import org.springframework.stereotype.Component @@ -159,7 +159,7 @@ class CustomTracesSamplerCallback : TracesSamplerCallback { } ``` -```kotlin {tabTitle:Kotlin (Spring Boot 4)} +```kotlin {tabTitle:Kotlin (Spring 7)} import io.sentry.SamplingContext import io.sentry.SentryOptions.TracesSamplerCallback import org.springframework.stereotype.Component