logback + webfilter 로 로그설정

1. logback-spring.xml (/resources 내부 포함)

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <property name="logPath"		value="/root/logs" />
    <property name="fileName"		value="application" />
    <property name="maxHistory"		value="30" />
    <property name="maxFileSize"	value="10MB" />
    <property name="totalSizeCap"	value="1GB" />
    <property name="consolePattern"	value="[%level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"/>
    <property name="filePattern"    value="[%level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"/>
    <property name="slackPattern"   value="%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n"/>
    <property name="slackHookUri"	value="%%%%%%%%%YOUR SLACK WEBHOOK URI%%%%%%%%%"/>

    <!-- Log Appender Module -->
    <springProfile name="console-logging">
        <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${consolePattern}</pattern>
            </encoder>
        </appender>
        <root level="INFO">
            <appender-ref ref="console"/>
        </root>
    </springProfile>

    <!-- file Appender Module -->
    <springProfile name="file-logging">
        <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${logPath}//${fileName}.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                <fileNamePattern>${logPath}//archive/%d{yyyy-MM-dd}_${fileName}_%i.log</fileNamePattern>
                <maxHistory>${maxHistory}</maxHistory>
                <maxFileSize>${maxFileSize}</maxFileSize>
                <totalSizeCap>${totalSizeCap}</totalSizeCap>
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>${filePattern}</pattern>
            </encoder>
        </appender>
        <root level="INFO">
            <appender-ref ref="file"/>
        </root>
    </springProfile>

    <!-- Message Appender Module -->
    <springProfile name="message-logging">
        <appender name="slack" class="com.github.maricn.logback.SlackAppender">
            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>${slackPattern}</pattern>
            </layout>
            <webhookUri>${slackHookUri}</webhookUri>
            <username>username</username>
            <iconEmoji>:stuck_out_tongue_winking_eye:</iconEmoji>
            <colorCoding>true</colorCoding>
        </appender>
    </springProfile>

    <!-- Log Level Module -->
<!--    <springProfile name="high-level-logging">-->
<!--        <logger name="root" level="error" />-->
<!--        <logger name="org.springframework" level="error" />-->
<!--        <logger name="com.blog.tistory" level="warn" />-->
<!--    </springProfile>-->

<!--    <springProfile name="low-level-logging">-->
<!--        <logger name="root" level="info" />-->
<!--        <logger name="org.springframework" level="info" />-->
<!--        <logger name="com.blog.tistory" level="debug" />-->
<!--    </springProfile>-->

</configuration>

2. application.yml

# common setting
spring:
  profiles:
    group:
      local:
        - console-logging
      dev:
        - file-logging
      prod:
        - file-logging

---
# local

spring:
  config:
    activate:
      on-profile: local
  datasource:
    ...
---
# dev
spring:
  config:
    activate:
      on-profile: dev
  datasource:
    ...

---
# prod
spring:
  config:
    activate:
      on-profile: prod
  datasource:
    ...

3. GlobalLoggingFilter.java

package com.testapp.filter;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import java.io.IOException;
import java.util.Collections;

@Slf4j
@WebFilter(filterName = "loggingFilter", urlPatterns = { "/*" })
public class GlobalLoggingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //request&response caching
        ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
        ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);

        //main logic
        chain.doFilter(httpServletRequest, httpServletResponse);

        String url = httpServletRequest.getRequestURI();
        String reqContent = new String(httpServletRequest.getContentAsByteArray());

        log.info("\n\n");
        log.info(" ========== TEST-APP REQUEST ========== ");
        log.info("url : {}", url);
        Collections.list(httpServletRequest.getHeaderNames()).forEach(headerName -> {
            log.info("headerName {} : {}", headerName, httpServletRequest.getHeader(headerName));
        });
        log.info("requestBody : {}", reqContent);

        int httpStatusCode = httpServletResponse.getStatus();
        String resContent = new String(httpServletResponse.getContentAsByteArray());
        httpServletResponse.copyBodyToResponse();       //이 매서드를 호출해줘야 한번 읽은 response 가 클라이언트에게도 복사되어 응답될 수 있다.

        log.info("\n\n");
        log.info(" ========== TEST-APP RESPONSE ========== ");
        log.info("httpStatusCode : {}", httpStatusCode);
        httpServletResponse.getHeaderNames().forEach(headerName -> {
            log.info("headerName {} : {}", headerName, httpServletResponse.getHeader(headerName));
        });
        log.info("responseBody : {}", resContent);
        log.info("\n\n");
    }
}

4. MainApplication

@SpringBootApplication
@ServletComponentScan
public class TestAppApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestAppApplication.class, args);
    }

}

Last updated