Affects: 6.0.14
Hi,
I'm using spring-boot:3.0.13 spring-framework:6.0.14
And I'm facing an issue with the observation feature. I don't know if it's really a bug or if I'm misusing it.
The problem is that if an application exception is thrown in the controller code I see the proper status and outcome tags in the traces but not the exception itself (exception is always none).
From what I've been gathering it is due to the fact that the SimpleHttpServerObservationFilter
checks for an exception in the request attributes for the key RequestDispatcher.ERROR_EXCEPTION
but the exception is stored in the request attribute DispatcherServlet.EXCEPTION_ATTRIBUTE
:
https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/web/filter/ServerHttpObservationFilter.java#L148
In turn the Observation
is never marked as an error:
https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/web/filter/ServerHttpObservationFilter.java#L120
Or am I just using it wrong and I have to register/configure some other bean?
Thanks in advance,
Daniel
Comment From: bclozel
Can you share a sample application? I cannot reproduce.
@RestController
public class TestController {
@GetMapping("/")
public String test() {
throw new IllegalStateException("custom");
}
}
$ http http://localhost:8080/actuator/metrics/http.server.requests\?tag\=outcome:SERVER_ERROR
HTTP/1.1 200
Connection: keep-alive
Content-Disposition: inline;filename=f.txt
Content-Type: application/vnd.spring-boot.actuator.v3+json
Date: Thu, 08 Feb 2024 08:31:26 GMT
Keep-Alive: timeout=60
Transfer-Encoding: chunked
{
"availableTags": [
{
"tag": "exception",
"values": [
"IllegalStateException"
]
},
{
"tag": "method",
"values": [
"GET"
]
},
{
"tag": "error",
"values": [
"IllegalStateException"
]
},
{
"tag": "uri",
"values": [
"/"
]
},
{
"tag": "status",
"values": [
"500"
]
}
],
"baseUnit": "seconds",
"measurements": [
{
"statistic": "COUNT",
"value": 1.0
},
{
"statistic": "TOTAL_TIME",
"value": 0.028471921
},
{
"statistic": "MAX",
"value": 0.028471921
}
],
"name": "http.server.requests"
}
Comment From: bender316
Yes, I got it working with the code you provided. But as soon as I throw a "custom" exception the whole stuff is behaving differently. DispatcherServlet
is no longer throwing the exception and hence the observation knows nothing about the exception.
See the demo-project I provided: https://github.com/bender316/spring-boot-demo-project
Throw the IllegalStateException and the span is logged to the console (as well as the exception itself). Throw the BadRequestException and the console goes silent.
Comment From: bclozel
Thanks for the sample application, this helps a lot.
This is the expected behavior, as your custom exception is annotated with @ResponseStatus
. This means that this exception is handled by an exception handler. This might be a perfectly "normal" exception to get in an application, for example a ResourceNotFoundException
that should be translated into an HTTP 404. Arguably, this is the regular behavior for the application and should not result in a SERVER_ERROR outcome with the exception tag populated, as those are used to alert when errors happen.
Because you might want to collect metrics for those still, you can do so as explained in the reference documentation. From a Framework perspective, we can't really mark them all in observations as there would be no easy way to opt out - we consider that handling an exception at the MVC level is a signal that we should take into account.
Comment From: bender316
Ok, I misunderstood the passage in the docs in the first place. I now know what to do,
Thanks for your time
Comment From: bclozel
Feel free to suggest here changes to the documentation. Maybe the @ResponseStatus
annotation is not obvious as a way for an error to be handled.