@@ -310,6 +310,61 @@ public void doFilterWhenMatchesThenObservationRegistryObserves() throws Exceptio
310310 assertFilterChainObservation (contexts .next (), "after" , 1 );
311311 }
312312
313+ // gh-12610
314+ @ Test
315+ void parentObservationIsTakenIntoAccountDuringDispatchError () throws Exception {
316+ ObservationHandler <Observation .Context > handler = mock (ObservationHandler .class );
317+ given (handler .supportsContext (any ())).willReturn (true );
318+ ObservationRegistry registry = ObservationRegistry .create ();
319+ registry .observationConfig ().observationHandler (handler );
320+
321+ given (this .matcher .matches (any ())).willReturn (true );
322+ SecurityFilterChain sec = new DefaultSecurityFilterChain (this .matcher , Arrays .asList (this .filter ));
323+ FilterChainProxy fcp = new FilterChainProxy (sec );
324+ fcp .setFilterChainDecorator (new ObservationFilterChainDecorator (registry ));
325+ Filter initialFilter = ObservationFilterChainDecorator .FilterObservation
326+ .create (Observation .createNotStarted ("wrap" , registry ))
327+ .wrap (fcp );
328+
329+ ServletRequest initialRequest = new MockHttpServletRequest ("GET" , "/" );
330+ initialFilter .doFilter (initialRequest , new MockHttpServletResponse (), this .chain );
331+
332+ // simulate request attribute copying in case dispatching to ERROR
333+ ObservationFilterChainDecorator .AroundFilterObservation parentObservation = (ObservationFilterChainDecorator .AroundFilterObservation ) initialRequest .getAttribute (ObservationFilterChainDecorator .ATTRIBUTE );
334+ assertThat (parentObservation ).isNotNull ();
335+
336+ // simulate dispatching error-related request
337+ Filter errorRelatedFilter = ObservationFilterChainDecorator .FilterObservation
338+ .create (Observation .createNotStarted ("wrap" , registry ))
339+ .wrap (fcp );
340+ ServletRequest errorRelatedRequest = new MockHttpServletRequest ("GET" , "/error" );
341+ errorRelatedRequest .setAttribute (ObservationFilterChainDecorator .ATTRIBUTE , parentObservation );
342+ errorRelatedFilter .doFilter (errorRelatedRequest , new MockHttpServletResponse (), this .chain );
343+
344+ ArgumentCaptor <Observation .Context > captor = ArgumentCaptor .forClass (Observation .Context .class );
345+ verify (handler , times (8 )).onStart (captor .capture ());
346+ verify (handler , times (8 )).onStop (any ());
347+ List <Observation .Context > contexts = captor .getAllValues ();
348+
349+ Observation .Context initialRequestObservationContextBefore = contexts .get (1 );
350+ Observation .Context initialRequestObservationContextAfter = contexts .get (3 );
351+ assertFilterChainObservation (initialRequestObservationContextBefore , "before" , 1 );
352+ assertFilterChainObservation (initialRequestObservationContextAfter , "after" , 1 );
353+
354+ assertThat (initialRequestObservationContextBefore .getParentObservation ()).isNotNull ();
355+ assertThat (initialRequestObservationContextBefore .getParentObservation ()).isSameAs (initialRequestObservationContextAfter .getParentObservation ());
356+
357+ Observation .Context errorRelatedRequestObservationContextBefore = contexts .get (5 );
358+ Observation .Context errorRelatedRequestObservationContextAfter = contexts .get (7 );
359+ assertFilterChainObservation (errorRelatedRequestObservationContextBefore , "before" , 1 );
360+ assertFilterChainObservation (errorRelatedRequestObservationContextAfter , "after" , 1 );
361+
362+ assertThat (errorRelatedRequestObservationContextBefore .getParentObservation ()).isNotNull ();
363+ assertThat (errorRelatedRequestObservationContextBefore .getParentObservation ()).isSameAs (initialRequestObservationContextBefore .getParentObservation ());
364+ assertThat (errorRelatedRequestObservationContextAfter .getParentObservation ()).isNotNull ();
365+ assertThat (errorRelatedRequestObservationContextAfter .getParentObservation ()).isSameAs (initialRequestObservationContextBefore .getParentObservation ());
366+ }
367+
313368 @ Test
314369 public void doFilterWhenMultipleFiltersThenObservationRegistryObserves () throws Exception {
315370 ObservationHandler <Observation .Context > handler = mock (ObservationHandler .class );
0 commit comments