Skip to content

Fix traceId discrepancy in case error in servlet web #17134

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 1 commit into
base: 6.4.x
Choose a base branch
from

Conversation

nkonev
Copy link
Contributor

@nkonev nkonev commented May 18, 2025

Fixes #12610


As I see from my research, the bug happens only in the real servlet environment, supposedly because of HttpServletResponse.sendError(), I didn't manage to reproduce it via mockMvc.
Tomcat creates a new HttpServletRequest in case error, which is related to "/error" path, which will be served by ErrorController.
Fortunately, request attributes are copied from the original request to the "/error"-related one, so we can put the ObservationView into the original request in order to extract this ObservationView from "/error"-related request and create a new parent observation with a given parent ObservationView. The last ObservationView propagates TraceContext to the new Observation so we have the same traceId.


Reproducer is here https://github.com/nkonev/trace-discrepancy-reproducer

curl -i 'http://localhost:8060/internal/profile/auth' -X GET -H 'Accept: text/plain, */*'

To check that the bug is fixed, you can run publishMavenJavaPublicationToMavenLocal in spring-security:web

./gradlew :spring-security-web:publishMavenJavaPublicationToMavenLocal --offline

or via IDE
image

then switch to the SNAPSHOT dependency nkonev/trace-discrepancy-reproducer@131a271

Before:
Screenshot From 2025-05-21 17-45-08
Screenshot From 2025-05-21 17-45-31

After:
Screenshot From 2025-05-21 17-54-26
Screenshot From 2025-05-21 17-54-45


UPD:
I also checked this PR with jetty and undertow, it works fine.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 18, 2025
@nkonev nkonev force-pushed the gh-12610 branch 2 times, most recently from cc7ac16 to f526143 Compare May 18, 2025 13:24
@nkonev
Copy link
Contributor Author

nkonev commented May 18, 2025

PTAL @jzheaux

nkonev added a commit to nkonev/videochat that referenced this pull request May 20, 2025
Signed-off-by: Nikita Konev <nikit.cpp@yandex.ru>
@nkonev
Copy link
Contributor Author

nkonev commented May 26, 2025

@jzheaux
When you have a chance, I’d appreciate your review or thoughts.

@nkonev
Copy link
Contributor Author

nkonev commented Jun 3, 2025

@marcusdacoregio @jzheaux
please take a look when you have a time

@jzheaux jzheaux self-assigned this Jun 17, 2025
@jzheaux jzheaux added in: web An issue in web modules (web, webmvc) and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 17, 2025
Copy link
Contributor

@jzheaux jzheaux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR and the sample application, @nkonev. I've left some feedback inline.

Also, I think we should try adding a test for it. That may mean dispatching to ERROR manually in the test.

@@ -250,9 +258,30 @@ private void wrapFilter(ServletRequest request, ServletResponse response, Filter
private AroundFilterObservation parent(HttpServletRequest request) {
FilterChainObservationContext beforeContext = FilterChainObservationContext.before();
FilterChainObservationContext afterContext = FilterChainObservationContext.after();

Object maybeBeforeObservationView = request.getAttribute(ATTRIBUTE_BEFORE_OBSERVATION_VIEW);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the parent observations are available through the AroundFilterObservation instance, it seems like the ATTRIBUTE attribute should be sufficient.

For example, instead of two other attributes, would this give you what you need:

AroundFilterObservation parent = (AroundFilterObservation) request.getAttribute(ATTRIBUTE);
if (parent != null) {
    beforeContext.setParentObservation(parent.before().getContext().getParentObservation());
    afterContext.setParentObservation(parent.after().getContext().getParentObservation());
}

Note that I tried this modification locally and the traceId is preserved in your project.

@jzheaux jzheaux added status: waiting-for-feedback We need additional information before we can continue type: bug A general bug labels Jun 20, 2025
@jzheaux jzheaux added this to the 6.4.8 milestone Jun 20, 2025
@nkonev
Copy link
Contributor Author

nkonev commented Jun 20, 2025

Thank you for review @jzheaux !

That may mean dispatching to ERROR manually in the test.

Can you please explain it a bit more ? I still don't understand for what I need to write an assertion ?

May be somewhere there is a similar test which I can copy and modify for this particular issue ?

Did you mean to use MockMvc ?


In the time when I wrote this PR I considered to make the following test:
Create request 1
then somehow fail it
then manually copy attributes to the request 2 (/error-related) -- to simulate servlet container
then assert the tracing contexts has the similar traceId

I decided it is too artificial in that time.

Do you mean to something like this ?

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jun 20, 2025
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
in: web An issue in web modules (web, webmvc) status: feedback-provided Feedback has been provided type: bug A general bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants