Re-enable async dispatches in Observation Filter

Prior to this commit, the fix for gh-32730 disabled the involvment of
the osbervation filter for async dispatches. Instead of relying on ASYNC
dispatches to close the observation for async requests, this is now
using an async listener instead: async dispatches are not guaranteed to
happen once the async request is handled.

This change caused another side-effect: because async dispatches are not
considered anymore by this filter, the observation scope is not
reinstated for async dispatches. For example, `ResponseBodyAdvice`
implementations do not have the observation scope opened during their
execution.

This commit re-enables async dispatches for this filter, but ensures
that observations are not closed during such dispatches as this will be
done by the async listener.

Fixes gh-33091
This commit is contained in:
Brian Clozel
2024-06-26 11:45:25 +02:00
parent 61adf2dd25
commit ab236c7741
2 changed files with 74 additions and 10 deletions

View File

@@ -23,6 +23,7 @@ import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
import jakarta.servlet.AsyncEvent;
import jakarta.servlet.AsyncListener;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.FilterChain;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
@@ -97,6 +98,11 @@ public class ServerHttpObservationFilter extends OncePerRequestFilter {
return Optional.ofNullable((ServerRequestObservationContext) request.getAttribute(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE));
}
@Override
protected boolean shouldNotFilterAsyncDispatch() {
return false;
}
@Override
@SuppressWarnings("try")
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
@@ -116,8 +122,9 @@ public class ServerHttpObservationFilter extends OncePerRequestFilter {
if (request.isAsyncStarted()) {
request.getAsyncContext().addListener(new ObservationAsyncListener(observation));
}
// Stop Observation right now if async processing has not been started.
else {
// scope is opened for ASYNC dispatches, but the observation will be closed
// by the async listener.
else if (request.getDispatcherType() != DispatcherType.ASYNC){
Throwable error = fetchException(request);
if (error != null) {
observation.error(error);
@@ -176,7 +183,6 @@ public class ServerHttpObservationFilter extends OncePerRequestFilter {
@Override
public void onError(AsyncEvent event) {
this.currentObservation.error(unwrapServletException(event.getThrowable()));
this.currentObservation.stop();
}
}