Skip to content

Commit 2beca0a

Browse files
committed
Use SpringServletTransactionNameProvider as fallback
1 parent 7435268 commit 2beca0a

File tree

14 files changed

+246
-8
lines changed

14 files changed

+246
-8
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import io.sentry.spring.jakarta.exception.SentryExceptionParameterAdviceConfiguration;
3333
import io.sentry.spring.jakarta.opentelemetry.SentryOpenTelemetryAgentWithoutAutoInitConfiguration;
3434
import io.sentry.spring.jakarta.opentelemetry.SentryOpenTelemetryNoAgentConfiguration;
35+
import io.sentry.spring.jakarta.tracing.CombinedTransactionNameProvider;
3536
import io.sentry.spring.jakarta.tracing.SentryAdviceConfiguration;
3637
import io.sentry.spring.jakarta.tracing.SentrySpanPointcutConfiguration;
3738
import io.sentry.spring.jakarta.tracing.SentryTracingFilter;
@@ -42,6 +43,7 @@
4243
import io.sentry.transport.ITransportGate;
4344
import io.sentry.transport.apache.ApacheHttpClientTransportFactory;
4445
import jakarta.servlet.http.HttpServletRequest;
46+
import java.util.Arrays;
4547
import java.util.List;
4648
import java.util.Optional;
4749
import org.aspectj.lang.ProceedingJoinPoint;
@@ -342,7 +344,10 @@ static class SentryMvcModeConfig {
342344
@Bean
343345
@ConditionalOnMissingBean(TransactionNameProvider.class)
344346
public @NotNull TransactionNameProvider transactionNameProvider() {
345-
return new SpringMvcTransactionNameProvider();
347+
return new CombinedTransactionNameProvider(
348+
Arrays.asList(
349+
new SpringMvcTransactionNameProvider(),
350+
new SpringServletTransactionNameProvider()));
346351
}
347352
}
348353

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import io.sentry.spring.exception.SentryExceptionParameterAdviceConfiguration;
3333
import io.sentry.spring.opentelemetry.SentryOpenTelemetryAgentWithoutAutoInitConfiguration;
3434
import io.sentry.spring.opentelemetry.SentryOpenTelemetryNoAgentConfiguration;
35+
import io.sentry.spring.tracing.CombinedTransactionNameProvider;
3536
import io.sentry.spring.tracing.SentryAdviceConfiguration;
3637
import io.sentry.spring.tracing.SentrySpanPointcutConfiguration;
3738
import io.sentry.spring.tracing.SentryTracingFilter;
@@ -41,6 +42,7 @@
4142
import io.sentry.spring.tracing.TransactionNameProvider;
4243
import io.sentry.transport.ITransportGate;
4344
import io.sentry.transport.apache.ApacheHttpClientTransportFactory;
45+
import java.util.Arrays;
4446
import java.util.List;
4547
import java.util.Optional;
4648
import javax.servlet.http.HttpServletRequest;
@@ -327,7 +329,10 @@ static class SentryMvcModeConfig {
327329
@Bean
328330
@ConditionalOnMissingBean(TransactionNameProvider.class)
329331
public @NotNull TransactionNameProvider transactionNameProvider() {
330-
return new SpringMvcTransactionNameProvider();
332+
return new CombinedTransactionNameProvider(
333+
Arrays.asList(
334+
new SpringMvcTransactionNameProvider(),
335+
new SpringServletTransactionNameProvider()));
331336
}
332337
}
333338

sentry-spring-jakarta/api/sentry-spring-jakarta.api

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,13 @@ public class io/sentry/spring/jakarta/opentelemetry/SentryOpenTelemetryNoAgentCo
220220
public fun sentryOpenTelemetryOptionsConfiguration ()Lio/sentry/Sentry$OptionsConfiguration;
221221
}
222222

223+
public final class io/sentry/spring/jakarta/tracing/CombinedTransactionNameProvider : io/sentry/spring/jakarta/tracing/TransactionNameProvider {
224+
public fun <init> (Ljava/util/List;)V
225+
public fun provideTransactionName (Ljakarta/servlet/http/HttpServletRequest;)Ljava/lang/String;
226+
public fun provideTransactionNameAndSource (Ljakarta/servlet/http/HttpServletRequest;)Lio/sentry/spring/jakarta/tracing/TransactionNameWithSource;
227+
public fun provideTransactionSource ()Lio/sentry/protocol/TransactionNameSource;
228+
}
229+
223230
public class io/sentry/spring/jakarta/tracing/SentryAdviceConfiguration {
224231
public fun <init> ()V
225232
public fun sentrySpanAdvice ()Lorg/aopalliance/aop/Advice;
@@ -300,9 +307,16 @@ public final class io/sentry/spring/jakarta/tracing/SpringServletTransactionName
300307

301308
public abstract interface class io/sentry/spring/jakarta/tracing/TransactionNameProvider {
302309
public abstract fun provideTransactionName (Ljakarta/servlet/http/HttpServletRequest;)Ljava/lang/String;
310+
public fun provideTransactionNameAndSource (Ljakarta/servlet/http/HttpServletRequest;)Lio/sentry/spring/jakarta/tracing/TransactionNameWithSource;
303311
public fun provideTransactionSource ()Lio/sentry/protocol/TransactionNameSource;
304312
}
305313

314+
public final class io/sentry/spring/jakarta/tracing/TransactionNameWithSource {
315+
public fun <init> (Ljava/lang/String;Lio/sentry/protocol/TransactionNameSource;)V
316+
public fun getTransactionName ()Ljava/lang/String;
317+
public fun getTransactionNameSource ()Lio/sentry/protocol/TransactionNameSource;
318+
}
319+
306320
public abstract class io/sentry/spring/jakarta/webflux/AbstractSentryWebFilter : org/springframework/web/server/WebFilter {
307321
public static final field SENTRY_HUB_KEY Ljava/lang/String;
308322
public static final field SENTRY_SCOPES_KEY Ljava/lang/String;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package io.sentry.spring.jakarta.tracing;
2+
3+
import io.sentry.protocol.TransactionNameSource;
4+
import jakarta.servlet.http.HttpServletRequest;
5+
import java.util.List;
6+
import org.jetbrains.annotations.ApiStatus;
7+
import org.jetbrains.annotations.NotNull;
8+
import org.jetbrains.annotations.Nullable;
9+
10+
/**
11+
* Resolves transaction name using {@link HttpServletRequest#getMethod()} and templated route that
12+
* handled the request. To return correct transaction name, it must be used after request is
13+
* processed by {@link org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping}
14+
* where {@link org.springframework.web.servlet.HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} is
15+
* set.
16+
*/
17+
@ApiStatus.Internal
18+
public final class CombinedTransactionNameProvider implements TransactionNameProvider {
19+
20+
private final @NotNull List<TransactionNameProvider> providers;
21+
22+
public CombinedTransactionNameProvider(final @NotNull List<TransactionNameProvider> providers) {
23+
this.providers = providers;
24+
}
25+
26+
@Override
27+
public @Nullable String provideTransactionName(@NotNull HttpServletRequest request) {
28+
for (TransactionNameProvider provider : providers) {
29+
String transactionName = provider.provideTransactionName(request);
30+
if (transactionName != null) {
31+
return transactionName;
32+
}
33+
}
34+
35+
return null;
36+
}
37+
38+
@Override
39+
@ApiStatus.Internal
40+
public @NotNull TransactionNameSource provideTransactionSource() {
41+
return TransactionNameSource.CUSTOM;
42+
}
43+
44+
@ApiStatus.Internal
45+
@Override
46+
public @NotNull TransactionNameWithSource provideTransactionNameAndSource(
47+
@NotNull HttpServletRequest request) {
48+
for (TransactionNameProvider provider : providers) {
49+
String transactionName = provider.provideTransactionName(request);
50+
if (transactionName != null) {
51+
final @NotNull TransactionNameSource source = provider.provideTransactionSource();
52+
return new TransactionNameWithSource(transactionName, source);
53+
}
54+
}
55+
56+
return new TransactionNameWithSource(null, TransactionNameSource.CUSTOM);
57+
}
58+
}

sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/tracing/SentryTracingFilter.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,11 @@ private void doFilterWithTransaction(
145145
} finally {
146146
if (shouldFinishTransaction(httpRequest) && transaction != null) {
147147
// after all filters run, templated path pattern is available in request attribute
148-
final String transactionName = transactionNameProvider.provideTransactionName(httpRequest);
149-
final TransactionNameSource transactionNameSource =
150-
transactionNameProvider.provideTransactionSource();
148+
final @NotNull TransactionNameWithSource transactionNameWithSource =
149+
transactionNameProvider.provideTransactionNameAndSource(httpRequest);
150+
final @Nullable String transactionName = transactionNameWithSource.getTransactionName();
151+
final @NotNull TransactionNameSource transactionNameSource =
152+
transactionNameWithSource.getTransactionNameSource();
151153
// if transaction name is not resolved, the request has not been processed by a controller
152154
// and we should not report it to Sentry
153155
if (transactionName != null) {

sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/tracing/TransactionNameProvider.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,12 @@ public interface TransactionNameProvider {
2727
default TransactionNameSource provideTransactionSource() {
2828
return TransactionNameSource.CUSTOM;
2929
}
30+
31+
@NotNull
32+
@ApiStatus.Internal
33+
default TransactionNameWithSource provideTransactionNameAndSource(
34+
final @NotNull HttpServletRequest request) {
35+
return new TransactionNameWithSource(
36+
provideTransactionName(request), provideTransactionSource());
37+
}
3038
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.sentry.spring.jakarta.tracing;
2+
3+
import io.sentry.protocol.TransactionNameSource;
4+
import org.jetbrains.annotations.ApiStatus;
5+
import org.jetbrains.annotations.NotNull;
6+
import org.jetbrains.annotations.Nullable;
7+
8+
@ApiStatus.Internal
9+
public final class TransactionNameWithSource {
10+
private final @Nullable String transactionName;
11+
private final @NotNull TransactionNameSource transactionNameSource;
12+
13+
public TransactionNameWithSource(
14+
final @Nullable String transactionName,
15+
final @NotNull TransactionNameSource transactionNameSource) {
16+
this.transactionName = transactionName;
17+
this.transactionNameSource = transactionNameSource;
18+
}
19+
20+
public @Nullable String getTransactionName() {
21+
return transactionName;
22+
}
23+
24+
public @NotNull TransactionNameSource getTransactionNameSource() {
25+
return transactionNameSource;
26+
}
27+
}

sentry-spring-jakarta/src/test/kotlin/io/sentry/spring/jakarta/tracing/SentryTracingFilterTest.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ class SentryTracingFilterTest {
6565
request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/product/{id}")
6666
whenever(transactionNameProvider.provideTransactionName(request)).thenReturn("POST /product/{id}")
6767
whenever(transactionNameProvider.provideTransactionSource()).thenReturn(TransactionNameSource.CUSTOM)
68+
whenever(transactionNameProvider.provideTransactionNameAndSource(request)).thenReturn(
69+
TransactionNameWithSource(
70+
"POST /product/{id}",
71+
TransactionNameSource.CUSTOM
72+
)
73+
)
6874
if (sentryTraceHeader != null) {
6975
request.addHeader("sentry-trace", sentryTraceHeader)
7076
whenever(scopes.startTransaction(any(), check<TransactionOptions> { it.isBindToScope })).thenAnswer { SentryTracer(it.arguments[0] as TransactionContext, scopes) }

sentry-spring/api/sentry-spring.api

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,13 @@ public class io/sentry/spring/opentelemetry/SentryOpenTelemetryNoAgentConfigurat
212212
public fun sentryOpenTelemetryOptionsConfiguration ()Lio/sentry/Sentry$OptionsConfiguration;
213213
}
214214

215+
public final class io/sentry/spring/tracing/CombinedTransactionNameProvider : io/sentry/spring/tracing/TransactionNameProvider {
216+
public fun <init> (Ljava/util/List;)V
217+
public fun provideTransactionName (Ljavax/servlet/http/HttpServletRequest;)Ljava/lang/String;
218+
public fun provideTransactionNameAndSource (Ljavax/servlet/http/HttpServletRequest;)Lio/sentry/spring/tracing/TransactionNameWithSource;
219+
public fun provideTransactionSource ()Lio/sentry/protocol/TransactionNameSource;
220+
}
221+
215222
public class io/sentry/spring/tracing/SentryAdviceConfiguration {
216223
public fun <init> ()V
217224
public fun sentrySpanAdvice ()Lorg/aopalliance/aop/Advice;
@@ -291,9 +298,16 @@ public final class io/sentry/spring/tracing/SpringServletTransactionNameProvider
291298

292299
public abstract interface class io/sentry/spring/tracing/TransactionNameProvider {
293300
public abstract fun provideTransactionName (Ljavax/servlet/http/HttpServletRequest;)Ljava/lang/String;
301+
public fun provideTransactionNameAndSource (Ljavax/servlet/http/HttpServletRequest;)Lio/sentry/spring/tracing/TransactionNameWithSource;
294302
public fun provideTransactionSource ()Lio/sentry/protocol/TransactionNameSource;
295303
}
296304

305+
public final class io/sentry/spring/tracing/TransactionNameWithSource {
306+
public fun <init> (Ljava/lang/String;Lio/sentry/protocol/TransactionNameSource;)V
307+
public fun getTransactionName ()Ljava/lang/String;
308+
public fun getTransactionNameSource ()Lio/sentry/protocol/TransactionNameSource;
309+
}
310+
297311
public class io/sentry/spring/webflux/SentryRequestResolver {
298312
public fun <init> (Lio/sentry/IScopes;)V
299313
public fun resolveSentryRequest (Lorg/springframework/http/server/reactive/ServerHttpRequest;)Lio/sentry/protocol/Request;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package io.sentry.spring.tracing;
2+
3+
import io.sentry.protocol.TransactionNameSource;
4+
import java.util.List;
5+
import javax.servlet.http.HttpServletRequest;
6+
import org.jetbrains.annotations.ApiStatus;
7+
import org.jetbrains.annotations.NotNull;
8+
import org.jetbrains.annotations.Nullable;
9+
10+
/**
11+
* Resolves transaction name using {@link HttpServletRequest#getMethod()} and templated route that
12+
* handled the request. To return correct transaction name, it must be used after request is
13+
* processed by {@link org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping}
14+
* where {@link org.springframework.web.servlet.HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE} is
15+
* set.
16+
*/
17+
@ApiStatus.Internal
18+
public final class CombinedTransactionNameProvider implements TransactionNameProvider {
19+
20+
private final @NotNull List<TransactionNameProvider> providers;
21+
private @Nullable TransactionNameSource source = null;
22+
23+
public CombinedTransactionNameProvider(final @NotNull List<TransactionNameProvider> providers) {
24+
this.providers = providers;
25+
}
26+
27+
@Override
28+
public @Nullable String provideTransactionName(final @NotNull HttpServletRequest request) {
29+
for (TransactionNameProvider provider : providers) {
30+
String transactionName = provider.provideTransactionName(request);
31+
if (transactionName != null) {
32+
source = provider.provideTransactionSource();
33+
return transactionName;
34+
}
35+
}
36+
37+
return null;
38+
}
39+
40+
@Override
41+
@ApiStatus.Internal
42+
public @NotNull TransactionNameSource provideTransactionSource() {
43+
final @Nullable TransactionNameSource tmpSource = source;
44+
return tmpSource == null ? TransactionNameSource.CUSTOM : tmpSource;
45+
}
46+
47+
@ApiStatus.Internal
48+
@Override
49+
public @NotNull TransactionNameWithSource provideTransactionNameAndSource(
50+
@NotNull HttpServletRequest request) {
51+
for (TransactionNameProvider provider : providers) {
52+
String transactionName = provider.provideTransactionName(request);
53+
if (transactionName != null) {
54+
final @NotNull TransactionNameSource source = provider.provideTransactionSource();
55+
return new TransactionNameWithSource(transactionName, source);
56+
}
57+
}
58+
59+
return new TransactionNameWithSource(null, TransactionNameSource.CUSTOM);
60+
}
61+
}

0 commit comments

Comments
 (0)