Tomcat 中的 HTTP 状态代码 500 访问 ClientAbortException/Broken Pipe 日志

HTTP Statuscode 500 in Tomcat AccesLog on ClientAbortException / BrokenPipe

我们使用 Kibana 设置了一些仪表板和可视化,以监控 tomcat 为我们的 spring 启动 Web 应用程序生成的访问日志。

我们特别关注状态码为 5xx 的请求。

事实证明,如果客户端请求资源,并且在请求正在进行时取消请求(出现 ClientAbortException/BrokenPipe 错误),则 ResponseCode 设置为 500,并且应用程序中不会记录任何错误日志(还可以)。

我们现在想将 ResponseCode 更改为不同于 500 的值,以便更好地区分 "real" 内部服务器错误和 "expected connection aborts, initiated by the client"。

因此我实现了一个 ExceptionHandler 如下:

@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);
  }
}

但事实证明,statusCode 500 是由 tomcat/catalina/coyote 内部设置的,不能从外部更改(因为响应设置为已提交)。

是否有可能以某种方式区分 "real" 内部服务器错误和 "just" 连接中止?

原来这个好像是不久前介绍的,Tomcat

8.5.12 onwards
8.0.42 onwards
7.0.76 onwards

并且计划将其还原为记录应用程序设置的状态码,而不是 500:see discussion here

另一种解决方法可能是将 %{javax.servlet.error.exception}r 添加到访问日志模式 server.tomcat.accesslog.pattern= 中,这将注销类似...

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

并通过 ELK 过滤掉那些条目。