Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .craft.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ targets:
maven:io.sentry:sentry:
maven:io.sentry:sentry-spring:
maven:io.sentry:sentry-spring-jakarta:
# maven:io.sentry:sentry-spring-7:
maven:io.sentry:sentry-spring-boot:
maven:io.sentry:sentry-spring-boot-jakarta:
maven:io.sentry:sentry-spring-boot-starter:
maven:io.sentry:sentry-spring-boot-starter-jakarta:
# maven:io.sentry:sentry-spring-boot-4:
# maven:io.sentry:sentry-spring-boot-4-starter:
maven:io.sentry:sentry-servlet:
maven:io.sentry:sentry-servlet-jakarta:
maven:io.sentry:sentry-logback:
Expand Down
3 changes: 3 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report_java.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ body:
- sentry-spring-boot-jakarta
- sentry-spring-boot-starter
- sentry-spring-boot-starter-jakarta
- sentry-spring-boot-4
- sentry-spring-boot-4-starter
- sentry-spring
- sentry-spring-jakarta
- sentry-spring-7
- sentry-logback
- sentry-log4j2
- sentry-graphql
Expand Down
15 changes: 15 additions & 0 deletions .github/workflows/system-tests-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,21 @@ jobs:
- sample: "sentry-samples-console"
agent: "false"
agent-auto-init: "true"
- sample: "sentry-samples-spring-boot-jakarta"
agent: "false"
agent-auto-init: "true"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason this sample was not added before to the system-tests-backend (since the sample is not added by this PR)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, this shouldn't be here. It's a duplicate since it's already there:

      matrix:
        sample: [ "sentry-samples-spring-boot-jakarta" ]
        agent: [ "false" ]
        agent-auto-init: [ "true" ]

- sample: "sentry-samples-spring-boot-4-webflux"
agent: "false"
agent-auto-init: "true"
- sample: "sentry-samples-spring-boot-4-opentelemetry-noagent"
agent: "false"
agent-auto-init: "true"
- sample: "sentry-samples-spring-boot-4-opentelemetry"
agent: "true"
agent-auto-init: "true"
- sample: "sentry-samples-spring-boot-4-opentelemetry"
agent: "true"
agent-auto-init: "false"
steps:
- uses: actions/checkout@v4
with:
Expand Down
5 changes: 5 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ apiValidation {
"sentry-samples-servlet",
"sentry-samples-spring",
"sentry-samples-spring-jakarta",
"sentry-samples-spring-7",
"sentry-samples-spring-boot",
"sentry-samples-spring-boot-opentelemetry",
"sentry-samples-spring-boot-opentelemetry-noagent",
Expand All @@ -69,6 +70,10 @@ apiValidation {
"sentry-samples-spring-boot-jakarta-opentelemetry-noagent",
"sentry-samples-spring-boot-webflux",
"sentry-samples-spring-boot-webflux-jakarta",
"sentry-samples-spring-boot-4",
"sentry-samples-spring-boot-4-opentelemetry",
"sentry-samples-spring-boot-4-opentelemetry-noagent",
"sentry-samples-spring-boot-4-webflux",
"sentry-samples-ktor-client",
"sentry-uitest-android",
"sentry-uitest-android-benchmark",
Expand Down
3 changes: 3 additions & 0 deletions buildSrc/src/main/java/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,13 @@ object Config {
val SENTRY_LOG4J2_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.log4j2"
val SENTRY_SPRING_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring"
val SENTRY_SPRING_JAKARTA_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring.jakarta"
val SENTRY_SPRING_7_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-7"
val SENTRY_SPRING_BOOT_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot"
val SENTRY_SPRING_BOOT_STARTER_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot-starter"
val SENTRY_SPRING_BOOT_JAKARTA_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot.jakarta"
val SENTRY_SPRING_BOOT_STARTER_JAKARTA_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot-starter.jakarta"
val SENTRY_SPRING_BOOT_4_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot-4"
val SENTRY_SPRING_BOOT_4_STARTER_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot-4-starter"
val SENTRY_OPENTELEMETRY_BOOTSTRAP_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.opentelemetry.bootstrap"
val SENTRY_OPENTELEMETRY_CORE_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.opentelemetry.core"
val SENTRY_OPENTELEMETRY_AGENT_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.opentelemetry.agent"
Expand Down
20 changes: 20 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jacoco = "0.8.7"
jackson = "2.18.3"
jetbrainsCompose = "1.6.11"
kotlin = "1.9.24"
kotlinSpring7 = "2.2.0"
kotlin-compatible-version = "1.6"
ktorClient = "3.0.0"
logback = "1.2.9"
Expand All @@ -30,6 +31,7 @@ retrofit = "2.9.0"
slf4j = "1.7.30"
springboot2 = "2.7.18"
springboot3 = "3.5.0"
springboot4 = "4.0.0-M1"
# Android
targetSdk = "34"
compileSdk = "34"
Expand All @@ -53,6 +55,7 @@ kover = { id = "org.jetbrains.kotlinx.kover", version = "0.7.3" }
vanniktech-maven-publish = { id = "com.vanniktech.maven.publish", version = "0.30.0" }
springboot2 = { id = "org.springframework.boot", version.ref = "springboot2" }
springboot3 = { id = "org.springframework.boot", version.ref = "springboot3" }
springboot4 = { id = "org.springframework.boot", version.ref = "springboot4" }
spring-dependency-management = { id = "io.spring.dependency-management", version = "1.0.11.RELEASE" }
gretty = { id = "org.gretty", version = "4.0.0" }

Expand Down Expand Up @@ -94,6 +97,7 @@ jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", ver
jackson-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" }
jetbrains-annotations = { module = "org.jetbrains:annotations", version = "23.0.0" }
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
kotlin-test-junit-spring7 = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlinSpring7" }
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktorClient" }
Expand Down Expand Up @@ -150,6 +154,20 @@ springboot3-starter-aop = { module = "org.springframework.boot:spring-boot-start
springboot3-starter-security = { module = "org.springframework.boot:spring-boot-starter-security", version.ref = "springboot3" }
springboot3-starter-jdbc = { module = "org.springframework.boot:spring-boot-starter-jdbc", version.ref = "springboot3" }
springboot3-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator", version.ref = "springboot3" }
springboot4-otel = { module = "io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter", version.ref = "otelInstrumentation" }
springboot4-starter = { module = "org.springframework.boot:spring-boot-starter", version.ref = "springboot4" }
springboot4-starter-graphql = { module = "org.springframework.boot:spring-boot-starter-graphql", version.ref = "springboot4" }
springboot4-starter-quartz = { module = "org.springframework.boot:spring-boot-starter-quartz", version.ref = "springboot4" }
springboot4-starter-test = { module = "org.springframework.boot:spring-boot-starter-test", version.ref = "springboot4" }
springboot4-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "springboot4" }
springboot4-starter-websocket = { module = "org.springframework.boot:spring-boot-starter-websocket", version.ref = "springboot4" }
springboot4-starter-webflux = { module = "org.springframework.boot:spring-boot-starter-webflux", version.ref = "springboot4" }
springboot4-starter-aop = { module = "org.springframework.boot:spring-boot-starter-aop", version.ref = "springboot4" }
springboot4-starter-security = { module = "org.springframework.boot:spring-boot-starter-security", version.ref = "springboot4" }
springboot4-starter-restclient = { module = "org.springframework.boot:spring-boot-starter-restclient", version.ref = "springboot4" }
springboot4-starter-webclient = { module = "org.springframework.boot:spring-boot-starter-webclient", version.ref = "springboot4" }
springboot4-starter-jdbc = { module = "org.springframework.boot:spring-boot-starter-jdbc", version.ref = "springboot4" }
springboot4-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator", version.ref = "springboot4" }
timber = { module = "com.jakewharton.timber:timber", version = "4.7.1" }

# test libraries
Expand All @@ -163,12 +181,14 @@ androidx-test-orchestrator = { module = "androidx.test:orchestrator", version =
androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidxTestCore" }
androidx-test-runner = { module = "androidx.test:runner", version = "1.6.2" }
awaitility-kotlin = { module = "org.awaitility:awaitility-kotlin", version = "4.1.1" }
awaitility-kotlin-spring7 = { module = "org.awaitility:awaitility-kotlin", version = "4.3.0" }
awaitility3-kotlin = { module = "org.awaitility:awaitility-kotlin", version = "3.1.6" }
hsqldb = { module = "org.hsqldb:hsqldb", version = "2.6.1" }
javafaker = { module = "com.github.javafaker:javafaker", version = "1.0.2" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
leakcanary-instrumentation = { module = "com.squareup.leakcanary:leakcanary-android-instrumentation", version = "2.14" }
mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version = "4.1.0" }
mockito-kotlin-spring7 = { module = "org.mockito.kotlin:mockito-kotlin", version = "6.0.0" }
mockito-inline = { module = "org.mockito:mockito-inline", version = "4.8.0" }
msgpack = { module = "org.msgpack:msgpack-core", version = "0.9.8" }
okhttp-mockwebserver = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "okhttp" }
Expand Down
19 changes: 19 additions & 0 deletions sentry-samples/sentry-samples-spring-7/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Sentry Sample Spring 6.0+

Sample application showing how to use Sentry with [Spring](http://spring.io/) from version `6.0` onwards.

## How to run?

To see events triggered in this sample application in your Sentry dashboard, go to `src/main/java/io/sentry/samples/spring/jakarta/SentryConfig.java` and replace the test DSN with your own DSN.

Then, execute a command from the module directory:

```
../../gradlew appRun
```

Make an HTTP request that will trigger events:

```
curl -XPOST --user user:password http://localhost:8080/sentry-samples-spring-jakarta/person/ -H "Content-Type:application/json" -d '{"firstName":"John","lastName":"Smith"}'
```
52 changes: 52 additions & 0 deletions sentry-samples/sentry-samples-spring-7/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.boot.gradle.plugin.SpringBootPlugin

plugins {
alias(libs.plugins.springboot4) apply false
alias(libs.plugins.spring.dependency.management)
kotlin("jvm")
alias(libs.plugins.kotlin.spring)
id("war")
alias(libs.plugins.gretty)
}

group = "io.sentry.sample.spring-7"

version = "0.0.1-SNAPSHOT"

java.sourceCompatibility = JavaVersion.VERSION_17

java.targetCompatibility = JavaVersion.VERSION_17

repositories { mavenCentral() }

dependencyManagement { imports { mavenBom(SpringBootPlugin.BOM_COORDINATES) } }

dependencies {
implementation(Config.Libs.springWeb)
implementation(Config.Libs.springAop)
implementation(Config.Libs.aspectj)
implementation(Config.Libs.springSecurityWeb)
implementation(Config.Libs.springSecurityConfig)
implementation(Config.Libs.kotlinReflect)
implementation(kotlin(Config.kotlinStdLib, KotlinCompilerVersion.VERSION))
implementation(projects.sentrySpring7)
implementation(projects.sentryLogback)
implementation(libs.jackson.databind)
implementation(libs.logback.classic)
implementation(libs.servlet.jakarta.api)
implementation(libs.slf4j2.api)
testImplementation(libs.springboot.starter.test) {
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
}
}

tasks.withType<Test>().configureEach { useJUnitPlatform() }

tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = JavaVersion.VERSION_17.toString()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.sentry.samples.spring.jakarta;

import io.sentry.IScopes;
import io.sentry.spring.jakarta.SentryUserFilter;
import io.sentry.spring.jakarta.SentryUserProvider;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(SentryConfig.class)
public class AppConfig {

@Bean
SentryUserFilter sentryUserFilter(
final IScopes scopes, final List<SentryUserProvider> sentryUserProviders) {
return new SentryUserFilter(scopes, sentryUserProviders);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.sentry.samples.spring.jakarta;

import io.sentry.spring.jakarta.tracing.SentryTracingFilter;
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 String[] getServletMappings() {
return new String[] {"/*"};
}

@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {AppConfig.class, SecurityConfiguration.class};
}

@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {WebConfig.class};
}

@Override
protected Filter[] getServletFilters() {
// creates Sentry transactions around incoming HTTP requests
SentryTracingFilter sentryTracingFilter = new SentryTracingFilter();

// filter required by Spring Security
DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy();
springSecurityFilterChain.setTargetBeanName("springSecurityFilterChain");
// sets request on RequestContextHolder
RequestContextFilter requestContextFilter = new RequestContextFilter();

// sets Sentry user on the scope
DelegatingFilterProxy sentryUserFilterProxy = new DelegatingFilterProxy();
sentryUserFilterProxy.setTargetBeanName("sentryUserFilter");

return new Filter[] {
sentryTracingFilter, springSecurityFilterChain, requestContextFilter, sentryUserFilterProxy
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.sentry.samples.spring.jakarta;

import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

// this API is meant to be consumed by non-browser clients thus the CSRF protection is not needed.
@SuppressWarnings({"lgtm[java/spring-disabled-csrf-protection]", "removal"})
@Bean
public SecurityFilterChain filterChain(final @NotNull HttpSecurity http) throws Exception {
http.csrf().disable().authorizeHttpRequests().anyRequest().authenticated().and().httpBasic();

return http.build();
}

@Bean
public @NotNull InMemoryUserDetailsManager userDetailsService() {
final PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();

final UserDetails user =
User.builder()
.passwordEncoder(encoder::encode)
.username("user")
.password("password")
.roles("USER")
.build();

return new InMemoryUserDetailsManager(user);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.sentry.samples.spring.jakarta;

import io.sentry.SentryOptions;
import io.sentry.SentryOptions.TracesSamplerCallback;
import io.sentry.spring.jakarta.EnableSentry;
import io.sentry.spring.jakarta.tracing.SentryTracingConfiguration;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;

// NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in your Sentry
// project/dashboard
@EnableSentry(
dsn = "https://[email protected]/5428563",
sendDefaultPii = true,
maxRequestBodySize = SentryOptions.RequestSize.MEDIUM)
@Import(SentryTracingConfiguration.class)
public class SentryConfig {

/**
* Configures callback used to determine if transaction should be sampled.
*
* @return traces sampler callback
*/
@Bean
TracesSamplerCallback tracesSamplerCallback() {
return samplingContext -> {
HttpServletRequest request =
(HttpServletRequest) samplingContext.getCustomSamplingContext().get("request");
if ("/error".equals(request.getRequestURI())) {
return 0.5d;
} else {
return 1.0d;
}
};
}
}
Loading
Loading