Skip to content

Commit 5fd37fa

Browse files
authored
Auto add OpenTelemetryLinkErrorEventProcessor for Spring Boot (#2429)
1 parent 5610867 commit 5fd37fa

File tree

10 files changed

+123
-3
lines changed

10 files changed

+123
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
### Features
1414

1515
- Add logging for OpenTelemetry integration ([#2425](https://github.com/getsentry/sentry-java/pull/2425))
16+
- Auto add `OpenTelemetryLinkErrorEventProcessor` for Spring Boot ([#2429](https://github.com/getsentry/sentry-java/pull/2429))
1617

1718
### Dependencies
1819

sentry-opentelemetry/sentry-opentelemetry-agentcustomization/build.gradle.kts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ tasks.withType<KotlinCompile>().configureEach {
2020

2121
dependencies {
2222
compileOnly(projects.sentry)
23-
implementation(projects.sentryOpentelemetry.sentryOpentelemetryCore)
23+
implementation(projects.sentryOpentelemetry.sentryOpentelemetryCore) {
24+
exclude(group = "io.opentelemetry")
25+
exclude(group = "io.opentelemetry.javaagent")
26+
}
2427

2528
compileOnly(Config.Libs.OpenTelemetry.otelSdk)
2629
compileOnly(Config.Libs.OpenTelemetry.otelExtensionAutoconfigureSpi)

sentry-opentelemetry/sentry-opentelemetry-core/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ tasks.withType<KotlinCompile>().configureEach {
2121
dependencies {
2222
compileOnly(projects.sentry)
2323

24-
compileOnly(Config.Libs.OpenTelemetry.otelSdk)
24+
implementation(Config.Libs.OpenTelemetry.otelSdk)
2525
compileOnly(Config.Libs.OpenTelemetry.otelSemconv)
2626

2727
compileOnly(Config.CompileOnly.nopen)

sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ public void onEnd(final @NotNull ReadableSpan otelSpan) {
151151
.getLogger()
152152
.log(
153153
SentryLevel.DEBUG,
154-
"Unable to find Sentry span for OpenTelemetry span %s (trace %s).",
154+
"Unable to find Sentry span for OpenTelemetry span %s (trace %s). This may simply mean it is a Sentry request.",
155155
traceData.getSpanId(),
156156
traceData.getTraceId());
157157
return;

sentry-spring-boot-starter-jakarta/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ dependencies {
5353
compileOnly(Config.Libs.springBoot3StarterAop)
5454
compileOnly(Config.Libs.springBoot3StarterSecurity)
5555
compileOnly(Config.Libs.reactorCore)
56+
compileOnly(projects.sentryOpentelemetry.sentryOpentelemetryCore)
5657

5758
annotationProcessor(Config.AnnotationProcessors.springBootAutoConfigure)
5859
annotationProcessor(Config.AnnotationProcessors.springBootConfiguration)
@@ -77,6 +78,7 @@ dependencies {
7778
testImplementation(Config.Libs.springBoot3StarterWebflux)
7879
testImplementation(Config.Libs.springBoot3StarterSecurity)
7980
testImplementation(Config.Libs.springBoot3StarterAop)
81+
testImplementation(projects.sentryOpentelemetry.sentryOpentelemetryCore)
8082
}
8183

8284
configure<SourceSetContainer> {

sentry-spring-boot-starter-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import io.sentry.Integration;
99
import io.sentry.Sentry;
1010
import io.sentry.SentryOptions;
11+
import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor;
1112
import io.sentry.protocol.SdkVersion;
1213
import io.sentry.spring.jakarta.ContextTagsEventProcessor;
1314
import io.sentry.spring.jakarta.SentryExceptionResolver;
@@ -138,6 +139,19 @@ static class ContextTagsEventProcessorConfiguration {
138139
}
139140
}
140141

142+
@Configuration(proxyBeanMethods = false)
143+
@ConditionalOnProperty(name = "sentry.auto-init", havingValue = "false")
144+
@ConditionalOnClass(OpenTelemetryLinkErrorEventProcessor.class)
145+
@Open
146+
static class OpenTelemetryLinkErrorEventProcessorConfiguration {
147+
148+
@Bean
149+
@ConditionalOnMissingBean
150+
public @NotNull OpenTelemetryLinkErrorEventProcessor openTelemetryLinkErrorEventProcessor() {
151+
return new OpenTelemetryLinkErrorEventProcessor();
152+
}
153+
}
154+
141155
/** Registers beans specific to Spring MVC. */
142156
@Configuration(proxyBeanMethods = false)
143157
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)

sentry-spring-boot-starter-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import io.sentry.SentryEvent
1515
import io.sentry.SentryLevel
1616
import io.sentry.SentryOptions
1717
import io.sentry.checkEvent
18+
import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor
1819
import io.sentry.protocol.SentryTransaction
1920
import io.sentry.protocol.User
2021
import io.sentry.spring.jakarta.ContextTagsEventProcessor
@@ -683,6 +684,47 @@ class SentryAutoConfigurationTest {
683684
}
684685
}
685686

687+
@Test
688+
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath and auto init off, creates OpenTelemetryLinkErrorEventProcessor`() {
689+
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=false")
690+
.run {
691+
assertThat(it).hasSingleBean(OpenTelemetryLinkErrorEventProcessor::class.java)
692+
val options = it.getBean(SentryOptions::class.java)
693+
assertThat(options.eventProcessors).anyMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
694+
}
695+
}
696+
697+
@Test
698+
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath but auto init on, does not create OpenTelemetryLinkErrorEventProcessor`() {
699+
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=true")
700+
.run {
701+
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
702+
val options = it.getBean(SentryOptions::class.java)
703+
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
704+
}
705+
}
706+
707+
@Test
708+
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath but auto init default, does not create OpenTelemetryLinkErrorEventProcessor`() {
709+
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj")
710+
.run {
711+
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
712+
val options = it.getBean(SentryOptions::class.java)
713+
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
714+
}
715+
}
716+
717+
@Test
718+
fun `when OpenTelemetryLinkErrorEventProcessor is not on the classpath, does not create OpenTelemetryLinkErrorEventProcessor`() {
719+
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=false")
720+
.withClassLoader(FilteredClassLoader(OpenTelemetryLinkErrorEventProcessor::class.java))
721+
.run {
722+
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
723+
val options = it.getBean(SentryOptions::class.java)
724+
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
725+
}
726+
}
727+
686728
@Configuration(proxyBeanMethods = false)
687729
open class CustomOptionsConfigurationConfiguration {
688730

sentry-spring-boot-starter/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ dependencies {
4343
compileOnly(Config.Libs.springBootStarterAop)
4444
compileOnly(Config.Libs.springBootStarterSecurity)
4545
compileOnly(Config.Libs.reactorCore)
46+
compileOnly(projects.sentryOpentelemetry.sentryOpentelemetryCore)
4647

4748
annotationProcessor(Config.AnnotationProcessors.springBootAutoConfigure)
4849
annotationProcessor(Config.AnnotationProcessors.springBootConfiguration)
@@ -67,6 +68,7 @@ dependencies {
6768
testImplementation(Config.Libs.springBootStarterWebflux)
6869
testImplementation(Config.Libs.springBootStarterSecurity)
6970
testImplementation(Config.Libs.springBootStarterAop)
71+
testImplementation(projects.sentryOpentelemetry.sentryOpentelemetryCore)
7072
}
7173

7274
configure<SourceSetContainer> {

sentry-spring-boot-starter/src/main/java/io/sentry/spring/boot/SentryAutoConfiguration.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import io.sentry.Integration;
99
import io.sentry.Sentry;
1010
import io.sentry.SentryOptions;
11+
import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor;
1112
import io.sentry.protocol.SdkVersion;
1213
import io.sentry.spring.ContextTagsEventProcessor;
1314
import io.sentry.spring.SentryExceptionResolver;
@@ -139,6 +140,19 @@ static class ContextTagsEventProcessorConfiguration {
139140
}
140141
}
141142

143+
@Configuration(proxyBeanMethods = false)
144+
@ConditionalOnProperty(name = "sentry.auto-init", havingValue = "false")
145+
@ConditionalOnClass(OpenTelemetryLinkErrorEventProcessor.class)
146+
@Open
147+
static class OpenTelemetryLinkErrorEventProcessorConfiguration {
148+
149+
@Bean
150+
@ConditionalOnMissingBean
151+
public @NotNull OpenTelemetryLinkErrorEventProcessor openTelemetryLinkErrorEventProcessor() {
152+
return new OpenTelemetryLinkErrorEventProcessor();
153+
}
154+
}
155+
142156
/** Registers beans specific to Spring MVC. */
143157
@Configuration(proxyBeanMethods = false)
144158
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)

sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import io.sentry.SentryEvent
1515
import io.sentry.SentryLevel
1616
import io.sentry.SentryOptions
1717
import io.sentry.checkEvent
18+
import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor
1819
import io.sentry.protocol.SentryTransaction
1920
import io.sentry.protocol.User
2021
import io.sentry.spring.ContextTagsEventProcessor
@@ -683,6 +684,47 @@ class SentryAutoConfigurationTest {
683684
}
684685
}
685686

687+
@Test
688+
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath and auto init off, creates OpenTelemetryLinkErrorEventProcessor`() {
689+
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=false")
690+
.run {
691+
assertThat(it).hasSingleBean(OpenTelemetryLinkErrorEventProcessor::class.java)
692+
val options = it.getBean(SentryOptions::class.java)
693+
assertThat(options.eventProcessors).anyMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
694+
}
695+
}
696+
697+
@Test
698+
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath but auto init on, does not create OpenTelemetryLinkErrorEventProcessor`() {
699+
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=true")
700+
.run {
701+
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
702+
val options = it.getBean(SentryOptions::class.java)
703+
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
704+
}
705+
}
706+
707+
@Test
708+
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath but auto init default, does not create OpenTelemetryLinkErrorEventProcessor`() {
709+
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj")
710+
.run {
711+
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
712+
val options = it.getBean(SentryOptions::class.java)
713+
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
714+
}
715+
}
716+
717+
@Test
718+
fun `when OpenTelemetryLinkErrorEventProcessor is not on the classpath, does not create OpenTelemetryLinkErrorEventProcessor`() {
719+
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=false")
720+
.withClassLoader(FilteredClassLoader(OpenTelemetryLinkErrorEventProcessor::class.java))
721+
.run {
722+
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
723+
val options = it.getBean(SentryOptions::class.java)
724+
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
725+
}
726+
}
727+
686728
@Configuration(proxyBeanMethods = false)
687729
open class CustomOptionsConfigurationConfiguration {
688730

0 commit comments

Comments
 (0)