We set up some dashboards and visualisations with Kibana to monitor our accessLogs generated by tomcat for our spring boot web application.
We specifically are paying attention to Requests that have been answered with Statuscode 5xx.
As it turns out, if a Client requests a Resource and while the request is ongoing cancels the request (with an ClientAbortException/BrokenPipe
Error), the ResponseCode is set to 500 and no error is logged in the application logs (which is kind of okay).
We now wanted to change the ResponseCode to something different than 500, to better distinguish between "real" internal server errors, and "expected connection aborts, initiated by the client".
Therefor I implemented an ExceptionHandler as follows:
@RestControllerAdvice
public class HttpRequestExceptionHandler {
private final static Logger LOGGER = LoggerFactory.getLogger(HttpRequestExceptionHandler.class);
@ExceptionHandler(value = { ClientAbortException.class })
@ResponseBody
public ResponseEntity<String> exceptionHandler(Exception e, HttpServletResponse res) {
res.setStatus(299);
//res.sendError(299);
LOGGER.error(""+res.getStatus());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
}
As it turns out though, the statusCode 500 is set by tomcat/catalina/coyote internals and can not be changed from outside (as the response is set to commited).
Is it possible to somehow distinguish between "real" internal server errors and "just" connection aborts?
As it turns out this seems to have been introduced not long ago, with Tomcat
and the plan is to revert it back to logging the statuscode that was set by the application, instead of 500: see discussion here.
Another workaround might be to add
%{javax.servlet.error.exception}r
to the accesslog patternserver.tomcat.accesslog.pattern=
which would log out something like..and filter out those entries through ELK.