Skip to content

Commit

Permalink
Merge 8324fd8 into 1707044
Browse files Browse the repository at this point in the history
  • Loading branch information
adinauer committed May 22, 2023
2 parents 1707044 + 8324fd8 commit 1ba2a69
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 292 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,5 @@ public class io/sentry/spring/boot/jakarta/SentryProperties$Reactive {
public class io/sentry/spring/boot/jakarta/SentryWebfluxAutoConfiguration {
public fun <init> ()V
public fun sentryWebExceptionHandler (Lio/sentry/IHub;)Lio/sentry/spring/jakarta/webflux/SentryWebExceptionHandler;
public fun sentryWebTracingFilter ()Lio/sentry/spring/jakarta/webflux/SentryWebTracingFilter;
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@
import io.sentry.spring.jakarta.webflux.SentryWebExceptionHandler;
import io.sentry.spring.jakarta.webflux.SentryWebFilter;
import io.sentry.spring.jakarta.webflux.SentryWebFilterWithThreadLocalAccessor;
import io.sentry.spring.jakarta.webflux.SentryWebTracingFilter;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
Expand Down Expand Up @@ -77,14 +75,6 @@ static class SentryWebfluxFilterConfiguration {
}
}

@Bean
@Order(SENTRY_SPRING_FILTER_PRECEDENCE + 1)
@Conditional(SentryAutoConfiguration.SentryTracingCondition.class)
@ConditionalOnMissingBean(name = "sentryWebTracingFilter")
public @NotNull SentryWebTracingFilter sentryWebTracingFilter() {
return new SentryWebTracingFilter();
}

/** Configures exception handler that handles unhandled exceptions and sends them to Sentry. */
@Bean
public @NotNull SentryWebExceptionHandler sentryWebExceptionHandler(final @NotNull IHub hub) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,5 @@ public class io/sentry/spring/boot/SentryWebfluxAutoConfiguration {
public fun sentryScheduleHookApplicationRunner ()Lorg/springframework/boot/ApplicationRunner;
public fun sentryWebExceptionHandler (Lio/sentry/IHub;)Lio/sentry/spring/webflux/SentryWebExceptionHandler;
public fun sentryWebFilter (Lio/sentry/IHub;)Lio/sentry/spring/webflux/SentryWebFilter;
public fun sentryWebTracingFilter ()Lio/sentry/spring/webflux/SentryWebTracingFilter;
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@
import io.sentry.spring.webflux.SentryScheduleHook;
import io.sentry.spring.webflux.SentryWebExceptionHandler;
import io.sentry.spring.webflux.SentryWebFilter;
import io.sentry.spring.webflux.SentryWebTracingFilter;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
Expand Down Expand Up @@ -45,14 +42,6 @@ public class SentryWebfluxAutoConfiguration {
return new SentryWebFilter(hub);
}

@Bean
@Order(SENTRY_SPRING_FILTER_PRECEDENCE + 1)
@Conditional(SentryAutoConfiguration.SentryTracingCondition.class)
@ConditionalOnMissingBean(name = "sentryWebTracingFilter")
public @NotNull SentryWebTracingFilter sentryWebTracingFilter() {
return new SentryWebTracingFilter();
}

/** Configures exception handler that handles unhandled exceptions and sends them to Sentry. */
@Bean
public @NotNull SentryWebExceptionHandler sentryWebExceptionHandler(final @NotNull IHub hub) {
Expand Down
11 changes: 5 additions & 6 deletions sentry-spring-jakarta/api/sentry-spring-jakarta.api
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,12 @@ public abstract interface class io/sentry/spring/jakarta/tracing/TransactionName
public abstract class io/sentry/spring/jakarta/webflux/AbstractSentryWebFilter : org/springframework/web/server/WebFilter {
public static final field SENTRY_HUB_KEY Ljava/lang/String;
public fun <init> (Lio/sentry/IHub;)V
protected fun doFinally (Lio/sentry/IHub;)V
protected fun doFinally (Lorg/springframework/web/server/ServerWebExchange;Lio/sentry/IHub;Lio/sentry/ITransaction;)V
protected fun doFirst (Lorg/springframework/web/server/ServerWebExchange;Lio/sentry/IHub;)V
protected fun doOnError (Lio/sentry/ITransaction;Ljava/lang/Throwable;)V
protected fun maybeStartTransaction (Lio/sentry/IHub;Lorg/springframework/http/server/reactive/ServerHttpRequest;)Lio/sentry/ITransaction;
protected fun shouldTraceRequest (Lio/sentry/IHub;Lorg/springframework/http/server/reactive/ServerHttpRequest;)Z
protected fun startTransaction (Lio/sentry/IHub;Lorg/springframework/http/server/reactive/ServerHttpRequest;)Lio/sentry/ITransaction;
}

public final class io/sentry/spring/jakarta/webflux/ReactorUtils {
Expand Down Expand Up @@ -215,8 +219,3 @@ public final class io/sentry/spring/jakarta/webflux/SentryWebFilterWithThreadLoc
public fun filter (Lorg/springframework/web/server/ServerWebExchange;Lorg/springframework/web/server/WebFilterChain;)Lreactor/core/publisher/Mono;
}

public class io/sentry/spring/jakarta/webflux/SentryWebTracingFilter : org/springframework/web/server/WebFilter {
public fun <init> ()V
public fun filter (Lorg/springframework/web/server/ServerWebExchange;Lorg/springframework/web/server/WebFilterChain;)Lreactor/core/publisher/Mono;
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,30 @@
import static io.sentry.TypeCheckHint.WEBFLUX_FILTER_REQUEST;
import static io.sentry.TypeCheckHint.WEBFLUX_FILTER_RESPONSE;

import io.sentry.Baggage;
import io.sentry.BaggageHeader;
import io.sentry.Breadcrumb;
import io.sentry.CustomSamplingContext;
import io.sentry.Hint;
import io.sentry.IHub;
import io.sentry.ITransaction;
import io.sentry.NoOpHub;
import io.sentry.Sentry;
import io.sentry.SentryLevel;
import io.sentry.SentryTraceHeader;
import io.sentry.SpanStatus;
import io.sentry.TransactionContext;
import io.sentry.TransactionOptions;
import io.sentry.exception.InvalidSentryTraceHeaderException;
import io.sentry.protocol.TransactionNameSource;
import io.sentry.util.Objects;
import java.util.List;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
Expand All @@ -19,14 +37,33 @@
public abstract class AbstractSentryWebFilter implements WebFilter {
private final @NotNull SentryRequestResolver sentryRequestResolver;
public static final String SENTRY_HUB_KEY = "sentry-hub";
private static final String TRANSACTION_OP = "http.server";

public AbstractSentryWebFilter(final @NotNull IHub hub) {
Objects.requireNonNull(hub, "hub is required");
this.sentryRequestResolver = new SentryRequestResolver(hub);
}

protected void doFinally(final @NotNull IHub requestHub) {
protected @Nullable ITransaction maybeStartTransaction(
final @NotNull IHub requestHub, final @NotNull ServerHttpRequest request) {
if (requestHub.isEnabled()
&& requestHub.getOptions().isTracingEnabled()
&& shouldTraceRequest(requestHub, request)) {
return startTransaction(requestHub, request);
} else {
return null;
}
}

protected void doFinally(
final @NotNull ServerWebExchange serverWebExchange,
final @NotNull IHub requestHub,
final @Nullable ITransaction transaction) {
if (transaction != null) {
finishTransaction(serverWebExchange, transaction);
}
requestHub.popScope();
Sentry.setCurrentHub(NoOpHub.getInstance());
}

protected void doFirst(
Expand All @@ -44,4 +81,75 @@ protected void doFirst(
requestHub.configureScope(
scope -> scope.setRequest(sentryRequestResolver.resolveSentryRequest(request)));
}

protected void doOnError(final @Nullable ITransaction transaction, final @NotNull Throwable e) {
if (transaction != null) {
transaction.setStatus(SpanStatus.INTERNAL_ERROR);
transaction.setThrowable(e);
}
}

protected boolean shouldTraceRequest(
final @NotNull IHub hub, final @NotNull ServerHttpRequest request) {
return hub.getOptions().isTraceOptionsRequests()
|| !HttpMethod.OPTIONS.equals(request.getMethod());
}

private void finishTransaction(ServerWebExchange exchange, ITransaction transaction) {
String transactionName = TransactionNameProvider.provideTransactionName(exchange);
if (transactionName != null) {
transaction.setName(transactionName, TransactionNameSource.ROUTE);
transaction.setOperation(TRANSACTION_OP);
}
if (transaction.getStatus() == null) {
final @Nullable ServerHttpResponse response = exchange.getResponse();
if (response != null) {
final @Nullable HttpStatusCode statusCode = response.getStatusCode();
if (statusCode != null) {
transaction.setStatus(SpanStatus.fromHttpStatusCode(statusCode.value()));
}
}
}
transaction.finish();
}

protected @NotNull ITransaction startTransaction(
final @NotNull IHub hub, final @NotNull ServerHttpRequest request) {
final @NotNull HttpHeaders headers = request.getHeaders();
final @Nullable List<String> sentryTraceHeaders =
headers.get(SentryTraceHeader.SENTRY_TRACE_HEADER);
final @Nullable List<String> baggageHeaders = headers.get(BaggageHeader.BAGGAGE_HEADER);
final @NotNull String name = request.getMethod() + " " + request.getURI().getPath();
final @NotNull CustomSamplingContext customSamplingContext = new CustomSamplingContext();
customSamplingContext.set("request", request);

final TransactionOptions transactionOptions = new TransactionOptions();
transactionOptions.setCustomSamplingContext(customSamplingContext);
transactionOptions.setBindToScope(true);

if (sentryTraceHeaders != null && sentryTraceHeaders.size() > 0) {
final @NotNull Baggage baggage =
Baggage.fromHeader(baggageHeaders, hub.getOptions().getLogger());
try {
final @NotNull TransactionContext contexts =
TransactionContext.fromSentryTrace(
name,
TransactionNameSource.URL,
TRANSACTION_OP,
new SentryTraceHeader(sentryTraceHeaders.get(0)),
baggage,
null);

return hub.startTransaction(contexts, transactionOptions);
} catch (InvalidSentryTraceHeaderException e) {
hub.getOptions()
.getLogger()
.log(SentryLevel.DEBUG, e, "Failed to parse Sentry trace header: %s", e.getMessage());
}
}

return hub.startTransaction(
new TransactionContext(name, TransactionNameSource.URL, TRANSACTION_OP),
transactionOptions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import com.jakewharton.nopen.annotation.Open;
import io.sentry.IHub;
import io.sentry.NoOpHub;
import io.sentry.ITransaction;
import io.sentry.Sentry;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
Expand All @@ -24,13 +26,12 @@ public Mono<Void> filter(
final @NotNull ServerWebExchange serverWebExchange,
final @NotNull WebFilterChain webFilterChain) {
@NotNull IHub requestHub = Sentry.cloneMainHub();
final ServerHttpRequest request = serverWebExchange.getRequest();
final @Nullable ITransaction transaction = maybeStartTransaction(requestHub, request);
return webFilterChain
.filter(serverWebExchange)
.doFinally(
__ -> {
doFinally(requestHub);
Sentry.setCurrentHub(NoOpHub.getInstance());
})
.doFinally(__ -> doFinally(serverWebExchange, requestHub, transaction))
.doOnError(e -> doOnError(transaction, e))
.doFirst(
() -> {
Sentry.setCurrentHub(requestHub);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package io.sentry.spring.jakarta.webflux;

import io.sentry.IHub;
import io.sentry.NoOpHub;
import io.sentry.ITransaction;
import io.sentry.Sentry;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
Expand All @@ -21,17 +22,26 @@ public SentryWebFilterWithThreadLocalAccessor(final @NotNull IHub hub) {
public Mono<Void> filter(
final @NotNull ServerWebExchange serverWebExchange,
final @NotNull WebFilterChain webFilterChain) {
final @NotNull TransactionContainer transactionContainer = new TransactionContainer();
return ReactorUtils.withSentryNewMainHubClone(
webFilterChain
.filter(serverWebExchange)
.doFinally(
__ -> {
doFinally(Sentry.getCurrentHub());
Sentry.setCurrentHub(NoOpHub.getInstance());
})
__ ->
doFinally(
serverWebExchange,
Sentry.getCurrentHub(),
transactionContainer.transaction))
.doOnError(e -> doOnError(transactionContainer.transaction, e))
.doFirst(
() -> {
doFirst(serverWebExchange, Sentry.getCurrentHub());
transactionContainer.transaction =
maybeStartTransaction(Sentry.getCurrentHub(), serverWebExchange.getRequest());
}));
}

private static class TransactionContainer {
private volatile @Nullable ITransaction transaction;
}
}
Loading

0 comments on commit 1ba2a69

Please sign in to comment.