HTTP Statuscode 500 in Tomcat AccesLog on ClientAb

2019-06-08 10:55发布

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?

1条回答
乱世女痞
2楼-- · 2019-06-08 11:31

As it turns out this seems to have been introduced not long ago, with Tomcat

8.5.12 onwards
8.0.42 onwards
7.0.76 onwards

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 pattern server.tomcat.accesslog.pattern= which would log out something like..

... org.apache.catalina.connector.ClientAbortException: java.io.IOException: Eine bestehende Verbindung wurde ...

and filter out those entries through ELK.

查看更多
登录 后发表回答