새소식

반응형
Spring/SpringCloudGateway

[SpringCloudGateway] Netty AccessLog - Customize

  • -
반응형

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));
            }
        };
    }
}
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.