Spring bootでTomcatのリクエスト情報をログへ出力する

# 背景

Spring bootで開発したAPIに対して脆弱性テストを実施した際に、tomcatのエラーページが表示されるケースがあった。
調べた限りでは、Controllerまで到達せずにtomcatのエラーページがHTMLでレスポンスされるようになっており、設定による変更が不可能。エラーページを出力する処理をオーバライドしてカスタマイズすることで回避する方法が提案されていた。
[参考のGithub issue](https://github.com/spring-projects/spring-boot/issues/21257)

#### エラーページが表示される例
- URIに使用できない文字が含まれている
``http://localhost:8080/api/get/%aaa``
- ヘッダに使用できない文字が含まれている
``(request): test``

# 実施したいこと

エラーページのカスタマイズは本投稿下部の参考情報をもとに実現できたが、このようなリクエストがあっても必ずしも例外が発生するわけではないようで、エラー時の情報が取得できない。
- リクエストヘッダに異常がある場合はIllegalArgumentExceptionが発生する。
- URIの異常は例外が発生せず、ログに何も出力せずにHTMLをレスポンスしてしまう。

リクエストの情報をログへ出力する方法を調べたところ、オーバライドするErrorReportValve.report()の引数のRequestクラスに含まれる情報が使用できることがわかった。

[Requestクラス](https://tomcat.apache.org/tomcat-8.5-doc/api/org/apache/catalina/connector/Request.html)
[MimeHeadersクラス](https://tomcat.apache.org/tomcat-8.5-doc/api/org/apache/tomcat/util/http/MimeHeaders.html)

## リクエストヘッダ
```java
@Override
protected void report(final Request request, final Response response, final Throwable throwable){
  :
  MimeHeaders headers = request.getCoyoteRequest().getMimeHeaders();
    for(int i = 0; i < headers.size(); i++){
      LOGGER.error(String.format("Request header  %s : %s", headers.getName(i), headers.getValue(i)));
    }
```

ただしエラーとなったヘッダについては含まれておらず、受け取ることができたもののみが設定されていると思われる。
例外のトレースにはヘッダ情報が含まれているので、別途出力すれば情報は残すことができる。
```java
  if(throwable != null){
    LOGGER.error("Request exception", throwable);
  }
```


## リクエストURIとクエリストリング

```java
  LOGGER.error(String.format("Request URI    : %s", request.getCoyoteRequest().requestURI()));
  LOGGER.error(String.format("Request querys : %s", request.getCoyoteRequest().queryString()));
```

## 出力

```bash:リクエスト
[22:11:28 ec2-user ~] curl -H '(request): test'  'http://localhost:8080/api/get/aaaa?a=111&b
=abc' -v
> GET /api/get/aaaa?a=111&b=abc HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
> (request): test
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 
< Content-Type: text/html;charset=utf-8
< Content-Length: 85
< Date: Sun, 08 Jan 2023 13:11:39 GMT
< Connection: close
< 
* Closing connection 0
<!doctype html><html lang="ja"><body>Error</body></html>
```

```text:Spring bootログ
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve           : Request exception
java.lang.IllegalArgumentException: The HTTP header line [(request): test] does not conform to RFC 7230 and has been ignored.
        at org.apache.coyote.http11.Http11InputBuffer.skipLine(Http11InputBuffer.java:1093) ~[tomcat-embed-core-10.1.4.jar:10.1.4]
 :
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve           : Request header : host : localhost:8080
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve           : Request header : user-agent : curl/7.79.1
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve           : Request header : accept : */*
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve           : Request URI    : /api/get/aaaa
2023-01-08T22:11:39.710+09:00 ERROR 10950 --- [nio-8080-exec-3] c.e.c.c.CustomErrorReportValve           : Request querys : a=111&b=abc

```

### 参考にした情報

エラーページのカスタマイズ方法
`https://yukihane.github.io/blog/202105/21/spring-boot-avoid-tomcat-error-page/`