Skip to content

Commit

Permalink
Auto add OpenTelemetryLinkErrorEventProcessor for Spring Boot (#2429)
Browse files Browse the repository at this point in the history
  • Loading branch information
adinauer committed Dec 22, 2022
1 parent 5610867 commit 5fd37fa
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -13,6 +13,7 @@
### Features

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

### Dependencies

Expand Down
Expand Up @@ -20,7 +20,10 @@ tasks.withType<KotlinCompile>().configureEach {

dependencies {
compileOnly(projects.sentry)
implementation(projects.sentryOpentelemetry.sentryOpentelemetryCore)
implementation(projects.sentryOpentelemetry.sentryOpentelemetryCore) {
exclude(group = "io.opentelemetry")
exclude(group = "io.opentelemetry.javaagent")
}

compileOnly(Config.Libs.OpenTelemetry.otelSdk)
compileOnly(Config.Libs.OpenTelemetry.otelExtensionAutoconfigureSpi)
Expand Down
Expand Up @@ -21,7 +21,7 @@ tasks.withType<KotlinCompile>().configureEach {
dependencies {
compileOnly(projects.sentry)

compileOnly(Config.Libs.OpenTelemetry.otelSdk)
implementation(Config.Libs.OpenTelemetry.otelSdk)
compileOnly(Config.Libs.OpenTelemetry.otelSemconv)

compileOnly(Config.CompileOnly.nopen)
Expand Down
Expand Up @@ -151,7 +151,7 @@ public void onEnd(final @NotNull ReadableSpan otelSpan) {
.getLogger()
.log(
SentryLevel.DEBUG,
"Unable to find Sentry span for OpenTelemetry span %s (trace %s).",
"Unable to find Sentry span for OpenTelemetry span %s (trace %s). This may simply mean it is a Sentry request.",
traceData.getSpanId(),
traceData.getTraceId());
return;
Expand Down
2 changes: 2 additions & 0 deletions sentry-spring-boot-starter-jakarta/build.gradle.kts
Expand Up @@ -53,6 +53,7 @@ dependencies {
compileOnly(Config.Libs.springBoot3StarterAop)
compileOnly(Config.Libs.springBoot3StarterSecurity)
compileOnly(Config.Libs.reactorCore)
compileOnly(projects.sentryOpentelemetry.sentryOpentelemetryCore)

annotationProcessor(Config.AnnotationProcessors.springBootAutoConfigure)
annotationProcessor(Config.AnnotationProcessors.springBootConfiguration)
Expand All @@ -77,6 +78,7 @@ dependencies {
testImplementation(Config.Libs.springBoot3StarterWebflux)
testImplementation(Config.Libs.springBoot3StarterSecurity)
testImplementation(Config.Libs.springBoot3StarterAop)
testImplementation(projects.sentryOpentelemetry.sentryOpentelemetryCore)
}

configure<SourceSetContainer> {
Expand Down
Expand Up @@ -8,6 +8,7 @@
import io.sentry.Integration;
import io.sentry.Sentry;
import io.sentry.SentryOptions;
import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor;
import io.sentry.protocol.SdkVersion;
import io.sentry.spring.jakarta.ContextTagsEventProcessor;
import io.sentry.spring.jakarta.SentryExceptionResolver;
Expand Down Expand Up @@ -138,6 +139,19 @@ static class ContextTagsEventProcessorConfiguration {
}
}

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "sentry.auto-init", havingValue = "false")
@ConditionalOnClass(OpenTelemetryLinkErrorEventProcessor.class)
@Open
static class OpenTelemetryLinkErrorEventProcessorConfiguration {

@Bean
@ConditionalOnMissingBean
public @NotNull OpenTelemetryLinkErrorEventProcessor openTelemetryLinkErrorEventProcessor() {
return new OpenTelemetryLinkErrorEventProcessor();
}
}

/** Registers beans specific to Spring MVC. */
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
Expand Down
Expand Up @@ -15,6 +15,7 @@ import io.sentry.SentryEvent
import io.sentry.SentryLevel
import io.sentry.SentryOptions
import io.sentry.checkEvent
import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor
import io.sentry.protocol.SentryTransaction
import io.sentry.protocol.User
import io.sentry.spring.jakarta.ContextTagsEventProcessor
Expand Down Expand Up @@ -683,6 +684,47 @@ class SentryAutoConfigurationTest {
}
}

@Test
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath and auto init off, creates OpenTelemetryLinkErrorEventProcessor`() {
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=false")
.run {
assertThat(it).hasSingleBean(OpenTelemetryLinkErrorEventProcessor::class.java)
val options = it.getBean(SentryOptions::class.java)
assertThat(options.eventProcessors).anyMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
}
}

@Test
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath but auto init on, does not create OpenTelemetryLinkErrorEventProcessor`() {
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=true")
.run {
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
val options = it.getBean(SentryOptions::class.java)
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
}
}

@Test
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath but auto init default, does not create OpenTelemetryLinkErrorEventProcessor`() {
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj")
.run {
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
val options = it.getBean(SentryOptions::class.java)
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
}
}

@Test
fun `when OpenTelemetryLinkErrorEventProcessor is not on the classpath, does not create OpenTelemetryLinkErrorEventProcessor`() {
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=false")
.withClassLoader(FilteredClassLoader(OpenTelemetryLinkErrorEventProcessor::class.java))
.run {
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
val options = it.getBean(SentryOptions::class.java)
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
}
}

@Configuration(proxyBeanMethods = false)
open class CustomOptionsConfigurationConfiguration {

Expand Down
2 changes: 2 additions & 0 deletions sentry-spring-boot-starter/build.gradle.kts
Expand Up @@ -43,6 +43,7 @@ dependencies {
compileOnly(Config.Libs.springBootStarterAop)
compileOnly(Config.Libs.springBootStarterSecurity)
compileOnly(Config.Libs.reactorCore)
compileOnly(projects.sentryOpentelemetry.sentryOpentelemetryCore)

annotationProcessor(Config.AnnotationProcessors.springBootAutoConfigure)
annotationProcessor(Config.AnnotationProcessors.springBootConfiguration)
Expand All @@ -67,6 +68,7 @@ dependencies {
testImplementation(Config.Libs.springBootStarterWebflux)
testImplementation(Config.Libs.springBootStarterSecurity)
testImplementation(Config.Libs.springBootStarterAop)
testImplementation(projects.sentryOpentelemetry.sentryOpentelemetryCore)
}

configure<SourceSetContainer> {
Expand Down
Expand Up @@ -8,6 +8,7 @@
import io.sentry.Integration;
import io.sentry.Sentry;
import io.sentry.SentryOptions;
import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor;
import io.sentry.protocol.SdkVersion;
import io.sentry.spring.ContextTagsEventProcessor;
import io.sentry.spring.SentryExceptionResolver;
Expand Down Expand Up @@ -139,6 +140,19 @@ static class ContextTagsEventProcessorConfiguration {
}
}

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "sentry.auto-init", havingValue = "false")
@ConditionalOnClass(OpenTelemetryLinkErrorEventProcessor.class)
@Open
static class OpenTelemetryLinkErrorEventProcessorConfiguration {

@Bean
@ConditionalOnMissingBean
public @NotNull OpenTelemetryLinkErrorEventProcessor openTelemetryLinkErrorEventProcessor() {
return new OpenTelemetryLinkErrorEventProcessor();
}
}

/** Registers beans specific to Spring MVC. */
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
Expand Down
Expand Up @@ -15,6 +15,7 @@ import io.sentry.SentryEvent
import io.sentry.SentryLevel
import io.sentry.SentryOptions
import io.sentry.checkEvent
import io.sentry.opentelemetry.OpenTelemetryLinkErrorEventProcessor
import io.sentry.protocol.SentryTransaction
import io.sentry.protocol.User
import io.sentry.spring.ContextTagsEventProcessor
Expand Down Expand Up @@ -683,6 +684,47 @@ class SentryAutoConfigurationTest {
}
}

@Test
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath and auto init off, creates OpenTelemetryLinkErrorEventProcessor`() {
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=false")
.run {
assertThat(it).hasSingleBean(OpenTelemetryLinkErrorEventProcessor::class.java)
val options = it.getBean(SentryOptions::class.java)
assertThat(options.eventProcessors).anyMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
}
}

@Test
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath but auto init on, does not create OpenTelemetryLinkErrorEventProcessor`() {
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=true")
.run {
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
val options = it.getBean(SentryOptions::class.java)
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
}
}

@Test
fun `when OpenTelemetryLinkErrorEventProcessor is on the classpath but auto init default, does not create OpenTelemetryLinkErrorEventProcessor`() {
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj")
.run {
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
val options = it.getBean(SentryOptions::class.java)
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
}
}

@Test
fun `when OpenTelemetryLinkErrorEventProcessor is not on the classpath, does not create OpenTelemetryLinkErrorEventProcessor`() {
contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.auto-init=false")
.withClassLoader(FilteredClassLoader(OpenTelemetryLinkErrorEventProcessor::class.java))
.run {
assertThat(it).doesNotHaveBean(OpenTelemetryLinkErrorEventProcessor::class.java)
val options = it.getBean(SentryOptions::class.java)
assertThat(options.eventProcessors).noneMatch { processor -> processor.javaClass == OpenTelemetryLinkErrorEventProcessor::class.java }
}
}

@Configuration(proxyBeanMethods = false)
open class CustomOptionsConfigurationConfiguration {

Expand Down

0 comments on commit 5fd37fa

Please sign in to comment.