Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 8 additions & 1 deletion .github/workflows/system-tests-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ jobs:
fail-fast: false
matrix:
sample: [ "sentry-samples-spring-boot-jakarta" ]
agent: [ "0" ]
include:
- sample: "sentry-samples-spring-boot"
- sample: "sentry-samples-spring-boot-webflux-jakarta"
- sample: "sentry-samples-spring-boot-webflux"
- sample: "sentry-samples-spring-boot-jakarta-opentelemetry"
agent: "1"
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -56,9 +59,13 @@ jobs:
run: |
./gradlew :sentry-samples:${{ matrix.sample }}:bootJar

- name: Build agent jar
run: |
./gradlew :sentry-opentelemetry:sentry-opentelemetry-agent:assemble

- name: Start server and run integration test for sentry-cli commands
run: |
test/system-test-sentry-server-start.sh > sentry-mock-server.txt 2>&1 & test/system-test-spring-server-start.sh "${{ matrix.sample }}" > spring-server.txt 2>&1 & test/wait-for-spring.sh && ./gradlew :sentry-samples:${{ matrix.sample }}:systemTest
test/system-test-sentry-server-start.sh > sentry-mock-server.txt 2>&1 & test/system-test-spring-server-start.sh "${{ matrix.sample }}" "${{ matrix.agent }}" > spring-server.txt 2>&1 & test/wait-for-spring.sh && ./gradlew :sentry-samples:${{ matrix.sample }}:systemTest

- name: Upload test results
if: always()
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
- `globalHubMode` used to only be a param on `Sentry.init`. To make it easier to be used in e.g. Desktop environments, we now additionally added it as an option on SentryOptions that can also be set via `sentry.properties`.
- If both the param on `Sentry.init` and the option are set, the option will win. By default the option is set to `null` meaning whatever is passed to `Sentry.init` takes effect.

### Fixes

- Add `auto.graphql.graphql22` to ignored span origins when using OpenTelemetry ([#3828](https://github.com/getsentry/sentry-java/pull/3828))
- The Spring Boot 3 WebFlux sample now uses our GraphQL v22 integration ([#3828](https://github.com/getsentry/sentry-java/pull/3828))

### Behavioural Changes

- (Android) Enable Performance V2 by default ([#3824](https://github.com/getsentry/sentry-java/pull/3824))
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ apiValidation {
"sentry-samples-spring-jakarta",
"sentry-samples-spring-boot",
"sentry-samples-spring-boot-jakarta",
"sentry-samples-spring-boot-jakarta-opentelemetry",
"sentry-samples-spring-boot-webflux",
"sentry-samples-spring-boot-webflux-jakarta",
"sentry-uitest-android",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Sentry Sample Spring Boot 3.0+
Copy link
Collaborator

Choose a reason for hiding this comment

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

Sentry Sample Spring Boot 3.0+ and OpenTelemetry


Sample application showing how to use Sentry with [Spring boot](http://spring.io/projects/spring-boot) from version `3.0` onwards.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it would be good to add the fact, that this is a sample including OTEL, something like:
Sample application showing how to use Sentry with Spring boot from version 3.0 onwards and OpenTelemetry.

Also, we might want to add some guidance on how to add the otel agent in the readme wdyt?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We could also add some instructions on how to run the system-tests locally


## How to run?

To see events triggered in this sample application in your Sentry dashboard, go to `src/main/resources/application.properties` and replace the test DSN with your own DSN.

Then, execute a command from the module directory:

```
../../gradlew bootRun
```

Make an HTTP request that will trigger events:

```
curl -XPOST --user user:password http://localhost:8080/person/ -H "Content-Type:application/json" -d '{"firstName":"John","lastName":"Smith"}'
```

## GraphQL

The following queries can be used to test the GraphQL integration.

### Greeting
```
{
greeting(name: "crash")
}
```

### Greeting with variables

```
query GreetingQuery($name: String) {
greeting(name: $name)
}
```
variables:
```
{
"name": "crash"
}
```

### Project

```
query ProjectQuery($slug: ID!) {
project(slug: $slug) {
slug
name
repositoryUrl
status
}
}
```
variables:
```
{
"slug": "statuscrash"
}
```

### Mutation

```
mutation AddProjectMutation($slug: ID!) {
addProject(slug: $slug)
}
```
variables:
```
{
"slug": "nocrash",
"name": "nocrash"
}
```

### Subscription

```
subscription SubscriptionNotifyNewTask($slug: ID!) {
notifyNewTask(projectSlug: $slug) {
id
name
assigneeId
assignee {
id
name
}
}
}
```
variables:
```
{
"slug": "crash"
}
```

### Data loader

```
query TasksAndAssigneesQuery($slug: ID!) {
tasks(projectSlug: $slug) {
id
name
assigneeId
assignee {
id
name
}
}
}
```
variables:
```
{
"slug": "crash"
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id(Config.BuildPlugins.springBoot) version Config.springBoot3Version
id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion
kotlin("jvm")
kotlin("plugin.spring") version Config.kotlinVersion
id("com.apollographql.apollo3") version "3.8.2"
}

group = "io.sentry.sample.spring-boot-jakarta"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17

repositories {
mavenCentral()
}

configure<JavaPluginExtension> {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

tasks.withType<KotlinCompile>().configureEach {
kotlinOptions.jvmTarget = JavaVersion.VERSION_17.toString()
}

tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = JavaVersion.VERSION_17.toString()
}
}

dependencies {
implementation(Config.Libs.springBoot3StarterSecurity)
implementation(Config.Libs.springBoot3StarterActuator)
implementation(Config.Libs.springBoot3StarterWeb)
implementation(Config.Libs.springBoot3StarterWebsocket)
implementation(Config.Libs.springBoot3StarterGraphql)
implementation(Config.Libs.springBoot3StarterQuartz)
implementation(Config.Libs.springBoot3StarterWebflux)
implementation(Config.Libs.springBoot3StarterAop)
implementation(Config.Libs.aspectj)
implementation(Config.Libs.springBoot3Starter)
implementation(Config.Libs.kotlinReflect)
implementation(Config.Libs.springBootStarterJdbc)
implementation(kotlin(Config.kotlinStdLib, KotlinCompilerVersion.VERSION))
implementation(projects.sentrySpringBootStarterJakarta)
implementation(projects.sentryLogback)
implementation(projects.sentryGraphql22)
implementation(projects.sentryQuartz)
implementation(Config.Libs.OpenTelemetry.otelSdk)

// database query tracing
implementation(projects.sentryJdbc)
runtimeOnly(Config.TestLibs.hsqldb)
testImplementation(Config.Libs.springBoot3StarterTest) {
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
}
testImplementation(kotlin(Config.kotlinStdLib))
testImplementation(Config.TestLibs.kotlinTestJunit)
testImplementation("ch.qos.logback:logback-classic:1.3.5")
testImplementation(Config.Libs.slf4jApi2)
testImplementation(Config.Libs.apolloKotlin)
}

configure<SourceSetContainer> {
test {
java.srcDir("src/test/java")
}
}

tasks.register<Test>("systemTest").configure {
group = "verification"
description = "Runs the System tests"

// maxParallelForks = Runtime.getRuntime().availableProcessors() / 2
maxParallelForks = 1

// Cap JVM args per test
minHeapSize = "128m"
maxHeapSize = "1g"

filter {
includeTestsMatching("io.sentry.systemtest*")
}
}

tasks.named("test").configure {
require(this is Test)

filter {
excludeTestsMatching("io.sentry.systemtest.*")
}
}

apollo {
service("service") {
srcDir("src/test/graphql")
packageName.set("io.sentry.samples.graphql")
outputDirConnection {
connectToKotlinSourceSet("test")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.sentry.samples.spring.boot.jakarta;

import io.sentry.EventProcessor;
import io.sentry.Hint;
import io.sentry.SentryEvent;
import io.sentry.protocol.SentryRuntime;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.SpringBootVersion;
import org.springframework.stereotype.Component;

/**
* Custom {@link EventProcessor} implementation lets modifying {@link SentryEvent}s before they are
* sent to Sentry.
*/
@Component
public class CustomEventProcessor implements EventProcessor {
private final String springBootVersion;

public CustomEventProcessor(String springBootVersion) {
this.springBootVersion = springBootVersion;
}

public CustomEventProcessor() {
this(SpringBootVersion.getVersion());
}

@Override
public @NotNull SentryEvent process(@NotNull SentryEvent event, @NotNull Hint hint) {
final SentryRuntime runtime = new SentryRuntime();
runtime.setVersion(springBootVersion);
runtime.setName("Spring Boot");
event.getContexts().setRuntime(runtime);
return event;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.sentry.samples.spring.boot.jakarta;

import io.sentry.spring.jakarta.checkin.SentryCheckIn;
import io.sentry.spring.jakarta.tracing.SentryTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
* {@link SentryTransaction} added on the class level, creates transaction around each method
* execution of every method of the annotated class.
*/
@Component
@SentryTransaction(operation = "scheduled")
public class CustomJob {

private static final Logger LOGGER = LoggerFactory.getLogger(CustomJob.class);

@SentryCheckIn("monitor_slug_1")
@Scheduled(fixedRate = 3 * 60 * 1000L)
void execute() throws InterruptedException {
LOGGER.info("Executing scheduled job");
Thread.sleep(2000L);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.sentry.samples.spring.boot.jakarta;

public class Person {
private final String firstName;
private final String lastName;

public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

public String getFirstName() {
return firstName;
}

public String getLastName() {
return lastName;
}

@Override
public String toString() {
return "Person{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + '}';
}
}
Loading
Loading