gateway의 역할 중에 하나는 서비스의 단일 진입점이다.
서비스의 모든 요청이 들어오는 곳이니, accessLog를 남겨 호출이력을 관리할 수 있게 된다.
Spring Cloud Gateway Reactive Server의 경우 netty를 HttpServer로 활용하니
NettyWebServer에 accessLog 사용 방법을 알아보고, accessLog를 Customize 할 수 있는 방법을 알아보자.
기본적으로 Spring Cloud Gateway 가이드에 기본적인 설명이 나와있다.
Add java property
-Dreactor.netty.http.server.accessLogEnabled=true
Add logback configuration
<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
<file>access_log.log</file>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="accessLog" />
</appender>
<logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
<appender-ref ref="async"/>
</logger>
기본 설정으로는 아래와 같은 로그 형태가 남는다.
0:0:0:0:0:0:0:1 - - [2024-12-26T10:28:30.104994+09:00[Asia/Seoul]] "POST /actuator/gateway/refresh HTTP/1.1" 200 0 3278 - PostmanRuntime/7.43.0
0:0:0:0:0:0:0:1 - - [2024-12-26T10:28:42.162045+09:00[Asia/Seoul]] "POST /actuator/refresh HTTP/1.1" 400 0 41 - PostmanRuntime/7.43.0
Customize
netty의 accessLog customize를 찾다 보면 github repository의 관련 이슈를 찾을 수 있다.
https://github.com/reactor/reactor-netty/issues/436
이슈의 연관 PR을 따라가 보면 어떤 식으로 기본 accessLog 형태를 취하고 있는지 확인이 가능하다.
- reactor-netty-http/src/main/java/reactor/netty/http/server/logging/BaseAccessLogHandler.java
- 해당 handler에서 default_log_format을 정의하고 사용하고 있다.
- 생성자를 보면 accessLog Fuction을 넘겨받는다
- accessLog Fuction은 HttpServer에서 설정한 값을 넘겨받는다
spring boot에서는 NettyWebServerFactoryCustomizer를 제공하고 있어
손쉽게 serverCustomizer를 설정할 수 있다.
@Configuration
public class NettyWebServerConfig {
private static final String LOG_FORMAT =
"123{} - {} [{}] \"{} {} {}\" {} {} {} {} {}";
private static final String USER_AGENT = "User-Agent";
private static final String REFERER = "Referer";
private static final String MISSING = "-";
@Bean
public NettyWebServerFactoryCustomizer nettyServerCustomizer(Environment environment, ServerProperties serverProperties) {
return new NettyWebServerFactoryCustomizer(environment, serverProperties) {
public void customize(NettyReactiveWebServerFactory factory) {
AccessLogFactory accessLogFactory = arg -> AccessLog.create(LOG_FORMAT,
((InetSocketAddress) arg.connectionInformation().connectionRemoteAddress()).getHostString(),
arg.user(),
arg.accessDateTime(),
arg.method(),
arg.uri(),
arg.protocol(),
arg.status(),
arg.contentLength() > -1 ? arg.contentLength() : MISSING,
arg.duration(),
arg.requestHeader(REFERER) != null ? arg.requestHeader(REFERER) : MISSING,
arg.requestHeader(USER_AGENT) != null ? arg.requestHeader(USER_AGENT) : MISSING);
factory.addServerCustomizers(httpServer -> httpServer.accessLog(true, accessLogFactory));
}
};
}
}