Skip to content

mqwerm98/logging-module

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

68 Commits
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Munzi Log - API Server๋ฅผ ์œ„ํ•œ Request, Response, Error Logging ์ฒ˜๋ฆฌ ๋ชจ๋“ˆ

์ ์šฉ ์˜ˆ์‹œ

# Request Log
[INFO ] 2023/09/12 15:19:00.956 [127.0.0.1 772f27b1-d5d9-4453-8bbb-daa8f54df0cd] http-nio-10108-exec-1 [l.m.i.LoggingInterceptor.preHandle:127] REQ > [POST /hello],
headers={"Accept":"*/*", "User-Agent":"PostmanRuntime/7.26.10", "Connection":"keep-alive", "Postman-Token":"88ed20f8-cb8a-4a17-b4b0-6acb813abd39", "Host":"localhost:10009", "Accept-Encoding":"gzip, deflate, br", "Content-Length":"46", "Content-Type":"application/json"}, 
params={}, 
body={"name":"์Šน๋ฆฌ๋ฅผ","name2":"tt"}

# Response Log
[INFO ] 2023/09/12 15:22:06.643 [127.0.0.1 6b7da681-6fee-4de8-9e83-6c42d790ba9a] http-nio-10108-exec-4 [l.m.i.LoggingInterceptor.postHandle:209] RES > 201 [POST /hello] 6ms,
headers={"Accept":"*/*", "User-Agent":"PostmanRuntime/7.26.10", "Connection":"keep-alive", "Postman-Token":"88ed20f8-cb8a-4a17-b4b0-6acb813abd39", "Host":"localhost:10009", "Accept-Encoding":"gzip, deflate, br", "Content-Length":"46", "Content-Type":"application/json"}, 
payload={"name":"์Šน๋ฆฌ๋ฅผ"}

# Checked Exception Error Log
[ERROR] 2023/09/12 15:20:47.440 [127.0.0.1 1f125f13-ba47-42e7-90d3-7cb388a4dfcf] http-nio-10108-exec-3 [l.m.i.ErrorAspect.recordErrorLog:71] ERR > httpStatus=400, errorCode="003", errorType="org.springframework.web.bind.MethodArgumentNotValidException", message="[issuedDate] ๋„์ด์–ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค",
stackTrace="Validation failed for argument [1] in public java.lang.String ..."

# Unchecked Exception Error Log
[ERROR] 2023/09/12 15:29:38.290 [127.0.0.1 faaa0aaa-2914-4202-8ce3-329f3cf7ddae] http-nio-10108-exec-4 [l.m.i.ErrorAspect.recordErrorLog:71] ERR > httpStatus=500, errorCode="", errorType="java.lang.NullPointerException", message="Cannot invoke \"net.test.api.module.dto.request.ReqDto.getNumber()\" because \"reqDto\" is null",
stackTrace="Cannot invoke ..."

๋กœ๊น… ๋ชจ๋“ˆ ์ ์šฉ

0. ์˜์กด์„ฑ ์ถ”๊ฐ€ (build.gradle)

ext {
	version_log4j= '2.17.0' 
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }

    all {
        // log4j2๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด, spring์˜ default์ธ logback์„ ์ œ์™ธ
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
        resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
    }
}

repositories {
	mavenCentral()
}

dependencies {
	implementation group:'log.munzi', name:'munzi-log', version:'0.1.12'

	implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: "${version_log4j}"
	implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: "${version_log4j}"
	implementation group: 'org.apache.logging.log4j', name: 'log4j-jul', version: "${version_log4j}"
	implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: "${version_log4j}"
	implementation group: 'org.apache.logging.log4j', name: 'log4j-web', version: "${version_log4j}"
	implementation group: 'org.springframework.boot', name: 'spring-boot-starter-log4j2'
	implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: "${version_jackson}"
	implementation group: 'org.bgee.log4jdbc-log4j2', name: 'log4jdbc-log4j2-jdbc4.1', version: '1.16'
	implementation group: 'org.json', name: 'json', version: '20230618'
}

1. ApiLogProperties bean ๋“ฑ๋ก

@EnableConfigurationProperties(ApiLogProperties.class) // ์ด๋ถ€๋ถ„ ์ถ”๊ฐ€!
public class ApiApplication {
	public static void main(String[] args) {
			...
	}
}

2. Filter, Interceptor, Error ๊ด€๋ฆฌ, util bean ๋“ฑ๋ก

<LoggingConfig.java>

import com.fasterxml.jackson.databind.ObjectMapper;
import log.munzi.common.util.LoggingUtil;
import log.munzi.config.ApiLogProperties;
import log.munzi.error.ErrorAspect;
import log.munzi.interceptor.GlobalRequestWrappingFilter;
import log.munzi.interceptor.LoggingInterceptor;
import log.munzi.stacktrace.error.StackTraceErrorWriter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@RequiredArgsConstructor
@Slf4j
public class LoggingConfig {

    private final ObjectMapper objectMapper;
    private final ApiLogProperties apiLogProperties;

    @Value("${spring.profiles.active}")
    private String profile;

    @Bean
    public LoggingInterceptor loggingInterceptor() {
        return new LoggingInterceptor(objectMapper, apiLogProperties);
    }

    @Bean
    public StackTraceErrorWriter stackTraceErrorWriter() {
        return new StackTraceErrorWriter();
    }

    @Bean
    public GlobalRequestWrappingFilter globalRequestWrappingFilter() {
        return new GlobalRequestWrappingFilter(apiLogProperties, profile);
    }

    @Bean
    public ErrorAspect errorAspect() {
        return new ErrorAspect(apiLogProperties, stackTraceErrorWriter());
    }

    @Bean
    public LoggingUtil loggingUtil() {
        return new LoggingUtil(loggingInterceptor(), apiLogProperties, profile, stackTraceErrorWriter());
    }

}

3. bean ๋“ฑ๋กํ•œ Filter ์ ์šฉ

GlobalRequestWrappingFilter๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Filter ์šฐ์„ ์ˆœ์œ„ ์ œ์ผ ์•„๋ž˜๋กœ ๋“ฑ๋ก์ด ๋œ๋‹ค. ํ•˜์ง€๋งŒ security ์„ค์ •์ด ๋“ค์–ด๊ฐ€๋ฉด Filter Chain์— ์ œ๋Œ€๋กœ ๋“ค์–ด๊ฐ€์ง€ ์•Š๋Š” ์˜ค๋ฅ˜(?)๊ฐ€ ์žˆ์–ด์„œ SecurityConfig ์„ค์ •์„ ํ•ด์ค„ ๋•Œ, addFilter๋ฅผ ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

<SecurityConfig.java (Security Configuration Class)>

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	    ...
	
	    http.addFilterBefore(munziLoginFilter(), UsernamePasswordAuthenticationFilter.class);
	    http.addFilterBefore(globalRequestWrappingFilter, UsernamePasswordAuthenticationFilter.class);
	
	    return http.build();
	}
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด addFilter๋ฅผ ํ•ด์ค€๋‹ค. ๊ผญ UserNamePasswordAuthenticationFiler ํ•˜์œ„์— ํ•ด์ค„ ํ•„์š”๋Š” ์—†๋‹ค. SpringSecurityFilter๋“ค๋ณด๋‹ค๋งŒ ํ›„์ˆœ์œ„๋กœ ๋“ค์–ด๊ฐ€๊ฒŒ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

4. bean ๋“ฑ๋กํ•œ Interceptor ์ ์šฉ

<WebMvcConfig.java>

import log.munzi.interceptor.LoggingInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {

    private final LoggingInterceptor loggingInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loggingInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/vendor/**", "/css/*", "/img/*");

    }
}

5. globalRequestWrappingFilter ์ „์— ๋‹ค๋ฅธ filter ๋“ฑ์— ๊ฑธ๋ ค์„œ Log๊ฐ€ ์•ˆ์ฐํ˜€์„œ ์ง์ ‘ ์ฐ์–ด์ค˜์•ผ ํ•  ๋•Œ

ex) Spring security filter์—์„œ ์—๋Ÿฌ๊ฐ€ ๋‚˜์„œ globalRequestWrappingFilter์™€ interceptor๋ฅผ ๊ฑฐ์น˜์ง€ ๋ชปํ•ด request, error ๋กœ๊ทธ๋ฅผ ์ฐ์ง€ ๋ชปํ•˜๋Š” ์ƒํ™ฉ.

AuthenticationFailureHandler์˜ onAuthenticationFailure ์—์„œ request ๊ฐ’์œผ๋กœ loggingUtil.recordRequestLog ๋ฅผ ์‚ฌ์šฉํ•ด request log๋ฅผ ์ฐ๊ณ  exception(AuthenticationException)๊ณผ return ๊ฐ’(ProblemDetail)์œผ๋กœ loggingUtil.recordErrorLog ๋ฅผ ์‚ฌ์šฉํ•ด error log๋ฅผ ์ฐ๋Š”๋‹ค.

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import log.munzi.common.util.LoggingUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONException;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ProblemDetail;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.UnknownHostException;

/**
 * ์ธ์ฆ ์‹คํŒจ handler
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class AuthenticationFailureCustomHandler implements AuthenticationFailureHandler {

    private final ObjectMapper objectMapper;
    private final LoggingUtil loggingUtil;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {
        String requestId = null;
        try {
            requestId = loggingUtil.recordRequestLog(request, true);
        } catch (Exception e) {
            log.error("recordRequestLog error", e);
        }

        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        response.setStatus(HttpStatus.UNAUTHORIZED.value()); 

	ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.UNAUTHORIZED, exception.getMessage());
	response.getWriter()
                .write(objectMapper.writeValueAsString(problemDetail));
        try {
            loggingUtil.recordErrorLog(exception, problemDetail, requestId);
        } catch (UnknownHostException | JSONException e) {
            log.error("recordErrorLog error", e);
        }
    }
}

์„ค์ •ํŒŒ์ผ


<application.yml>

spring:
  output:
    ansi:
      enabled: ALWAYS # ๋กœ๊ทธ ์•Œ๋ก๋‹ฌ๋ก ์˜ˆ์˜๊ฒŒ ๋‚˜์˜ค๊ฒŒ ์„ค์ •
  datasource: # log4jdbc-log4j2 ์‚ฌ์šฉ์‹œ ํ•„์š”ํ•œ ์„ค์ •
    driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy # ๊ณ ์ •
    url: jdbc:log4jdbc:mariadb~~~ # ๊ธฐ์กด jdbc:mariadb~~ ์ด๋Ÿฐ์‹์œผ๋กœ ์ผ๋˜ ๋ถ€๋ถ„ ์‚ฌ์ด์— log4jdbc ์ถ”๊ฐ€

logging:
  config: file:/apps/dkargo/munzi-log/config/log4j2-local.yml #log4j2.yml ํŒŒ์ผ์˜ ๊ฒฝ๋กœ
  # config: classpath:log4j2-local.yml # resources ํ•˜์œ„์˜ ๊ฒฝ์šฐ

api-log:
  server-name: munzi-nene-project
  request-id-header-key: X-Request-ID # requestId๋ฅผ ์›ํ•˜๋Š” ๊ฐ’์œผ๋กœ ์ฐ๊ณ  ์‹ถ์„ ๊ฒฝ์šฐ, header์— ๋‹ด์•„์„œ ์ฐ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ ๊ทธ ๋•Œ header์—์„œ ์‚ฌ์šฉํ•  key
  stack-trace-print-yn: true # default = false, true์ผ ๊ฒฝ์šฐ 500๋ฒˆ๋Œ€ ์—๋Ÿฌ๊ฐ€ ๋‚ฌ์„ ๋•Œ StackTrace๋„ ๊ฐ™์ด ์ฐ์Œ
  ignore-security-log: true # default = false, true์ผ ๊ฒฝ์šฐ์—๋งŒ security์—ฌ๋„ ๋กœ๊ทธ ์ฐ์Œ
  use: true # request, response ๋กœ๊ทธ๋ฅผ ์ฐ๋Š”์ง€ ์—ฌ๋ถ€
  json-pretty: false # request, response ๋กœ๊ทธ ๋‚ด json ๋ฐ์ดํ„ฐ๋ฅผ ์ •๋ ฌํ•ด์„œ ๋ณด์—ฌ์ค„์ง€ ์—ฌ๋ถ€
  debug-api: GET /api/debug/*
  request:
    max-body-size: 1 MB # request body max size
    secret-api: POST /api/sjsj # ํ•ด๋‹น api์˜ ๊ฒฝ์šฐ, body ์ „์ฒด๋ฅผ ๋กœ๊ทธ์— ์•ˆ์ฐ์Œ
    inactive-api: GET /api/webjars/*, GET /api/, GET /api/swagger*, GET /api/code/*, OPTIONS /api/code/*
  response:
    max-body-size: 10 KB # response body max size
    secret-api:
    inactive-api: GET /api/webjars/*, GET /api/, GET /api/swagger*, GET /api/code/*, OPTIONS /api/code/*

๐Ÿ’ก ๊ธฐ์กด logging ์„ค์ •์€ ๋ชจ๋‘ ์ฃผ์„์ฒ˜๋ฆฌ ํ•˜๊ฑฐ๋‚˜ ์ง€์›Œ์ฃผ์„ธ์š” log๊ด€๋ จ ์„ค์ •์€ log4j2.ymlํŒŒ์ผ์— ๋ชฐ์•„ ๋„ฃ์„๊ฒ๋‹ˆ๋‹ค

<log4j2.yml>

Configuration:
  name: log4j2 local
  status: INFO
  monitorInterval: 5 # 1

  Properties: # 2
    Property:
      - name: package-name
        value: "xxx.xxx.xxx"
      - name: log-path
        value: "/apps/logs/munzi-log"
      - name: log-filename
        value: "munzi-log.log"
      - name: req-res-log-filename
        value: "munzi-log-req-res.log"
      - name: err-stack-trace-log-filename
        value: "munzi-log-err-stack-trace.log"
      - name: event-log-filename
        value: "munzi-log-event.log"
      - name: scheduler-log-filename
        value: "munzi-log-sch.log"
      - name: log-db-filename
        value: "munzi-db-log.log"
      - name: log-pattern
        value: "%highlight{[%-5p]}{FATAL=bg_red, ERROR=red, INFO=green, DEBUG=blue} %style{%d{yyyy/MM/dd HH:mm:ss.SSS}}{cyan} %style{[%X{applicationName} %X{requestId}]}{magenta} %style{%t}{yellow} %style{[%C{1.}.%M:%L]}{blue} %m%n"
      - name: log-pattern-no-color
        value: "[%-5p] %d{yyyy/MM/dd HH:mm:ss.SSS} [%X{applicationName} %X{requestId}] %t [%C{1.}.%M:%L] %m%n"
  Appenders: # 3
    Console:
      name: Console_Appender
      target: SYSTEM_OUT
      PatternLayout:
        pattern: ${log-pattern}
    RollingFile:
     - name: RollingFile_Appender
        fileName: ${log-path}/${log-filename}
        filePattern: ${log-path}/archive/${log-filename}.%d{yyyy-MM-dd-hh-mm}.gz
        PatternLayout:
          pattern: ${log-pattern-no-color}
        Policies:
          SizeBasedTriggeringPolicy:
            size: 500 MB
        DefaultRollOverStrategy:
          max: 30
          Delete:
            basePath: ${log-path}/archive
            maxDepth: 1
            IfAccumulatedFileCount:
              exceeds: 31
      - name: Debug_RollingFile_Appender
        fileName: ${log-path}/${debug-log-filename}
        filePattern: ${log-path}/archive/${debug-log-filename}.%d{yyyy-MM-dd-hh-mm}.gz
        PatternLayout:
          pattern: ${log-pattern-no-color}
        LevelRangeFilter:
          minLevel: FATAL
          maxLevel: DEBUG
          onMatch: ACCEPT
          onMismatch: DENY
        Policies:
          SizeBasedTriggeringPolicy:
            size: 500 MB
        DefaultRollOverStrategy:
          max: 30
          Delete:
            basePath: ${log-path}/archive
            maxDepth: 1
            IfAccumulatedFileCount:
              exceeds: 31
      - name: Info_RollingFile_Appender
        fileName: ${log-path}/${log-filename}
        filePattern: ${log-path}/archive/${log-filename}.%d{yyyy-MM-dd-hh-mm}.gz
        PatternLayout:
          pattern: ${log-pattern-no-color}
        LevelRangeFilter:
          minLevel: FATAL
          maxLevel: INFO
          onMatch: ACCEPT
          onMismatch: DENY
        Policies:
          SizeBasedTriggeringPolicy:
            size: 500 MB
        DefaultRollOverStrategy:
          max: 30
          Delete:
            basePath: ${log-path}/archive
            maxDepth: 1
            IfAccumulatedFileCount:
              exceeds: 31
      - name: RollingFile_Appender_Color
        fileName: ${log-path}/${log-filename}
        filePattern: ${log-path}/archive/${log-filename}.%d{yyyy-MM-dd-hh-mm}.gz
        PatternLayout:
          pattern: ${log-pattern}
        Policies:
          SizeBasedTriggeringPolicy:
            size: 500 MB
        DefaultRollOverStrategy:
          max: 30
          Delete:
            basePath: ${log-path}/archive
            maxDepth: 1
            IfAccumulatedFileCount:
              exceeds: 31
      - name: RollingDBFile_Appender
        fileName: ${log-path}/${log-db-filename}
        filePattern: ${log-path}/archive/${log-db-filename}.%d{yyyy-MM-dd-hh-mm}.gz
        PatternLayout:
          pattern: ${log-pattern}
        Policies:
          SizeBasedTriggeringPolicy:
            size: 500 MB
        DefaultRollOverStrategy:
          max: 30
          Delete:
            basePath: ${log-path}/archive
            maxDepth: 1
            IfAccumulatedFileCount:
              exceeds: 31
      - name: Info_Req_Res_RollingFile_Appender
        fileName: ${log-path}/${req-res-log-filename}
        filePattern: ${log-path}/archive/${req-res-log-filename}.%d{yyyy-MM-dd-hh-mm}.gz
        PatternLayout:
          pattern: ${log-pattern-no-color}
        LevelRangeFilter:
          minLevel: FATAL
          maxLevel: INFO
          onMatch: ACCEPT
          onMismatch: DENY
        Policies:
          SizeBasedTriggeringPolicy:
            size: 500 MB
        DefaultRollOverStrategy:
          max: 30
          Delete:
            basePath: ${log-path}/archive
            maxDepth: 1
            IfAccumulatedFileCount:
              exceeds: 31
      - name: Err_StackTrace_RollingFile_Appender
        fileName: ${log-path}/${err-stack-trace-log-filename}
        filePattern: ${log-path}/archive/${err-stack-trace-log-filename}.%d{yyyy-MM-dd-hh-mm}.gz
        PatternLayout:
          pattern: ${log-pattern-no-color}
        LevelRangeFilter:
          minLevel: FATAL
          maxLevel: ERROR
          onMatch: ACCEPT
          onMismatch: DENY
        Policies:
          SizeBasedTriggeringPolicy:
            size: 500 MB
        DefaultRollOverStrategy:
          max: 30
          Delete:
            basePath: ${log-path}/archive
            maxDepth: 1
            IfAccumulatedFileCount:
              exceeds: 31
      - name: Info_Event_RollingFile_Appender
        fileName: ${log-path}/${event-log-filename}
        filePattern: ${log-path}/archive/${event-log-filename}.%d{yyyy-MM-dd-hh-mm}.gz
        PatternLayout:
          pattern: ${log-pattern-no-color}
        LevelRangeFilter:
          minLevel: FATAL
          maxLevel: INFO
          onMatch: ACCEPT
          onMismatch: DENY
        Policies:
          SizeBasedTriggeringPolicy:
            size: 500 MB
        DefaultRollOverStrategy:
          max: 30
          Delete:
            basePath: ${log-path}/archive
            maxDepth: 1
            IfAccumulatedFileCount:
              exceeds: 31
      - name: Info_Scheduler_RollingFile_Appender
        fileName: ${log-path}/${scheduler-log-filename}
        filePattern: ${log-path}/archive/${scheduler-log-filename}.%d{yyyy-MM-dd-hh-mm}.gz
        PatternLayout:
          pattern: ${log-pattern-no-color}
        LevelRangeFilter:
          minLevel: FATAL
          maxLevel: INFO
          onMatch: ACCEPT
          onMismatch: DENY
        Policies:
          SizeBasedTriggeringPolicy:
            size: 500 MB
        DefaultRollOverStrategy:
          max: 30
          Delete:
            basePath: ${log-path}/archive
            maxDepth: 1
            IfAccumulatedFileCount:
              exceeds: 31

  Loggers: # 4
    Root: # 5
      includeLocation: TRUE
      level: INFO
      AppenderRef:
        - ref: Console_Appender
    AsyncLogger: # 6
      # package
      - name: ${package-name}
        includeLocation: TRUE
        additivity: FALSE
        level: DEBUG
        AppenderRef:
          - ref: Console_Appender
          - ref: RollingFile_Appender

      - name: org.springframework.web
        includeLocation: TRUE
        additivity: FALSE
        level: ERROR
        AppenderRef:
          - ref: Console_Appender
          - ref: RollingFile_Appender

      - name: org.hibernate
        includeLocation: TRUE
        additivity: FALSE
        level: ERROR
        AppenderRef:
          - ref: RollingDBFile_Appender

      - name: log4jdbc.log4j2 # 7
        includeLocation: TRUE
        additivity: FALSE
        level: DEBUG
        AppenderRef:
          - ref: Console_Appender
          - ref: RollingFile_Appender
          - ref: RollingDBFile_Appender
        MarkerFilter:
#          - marker: LOG4JDBC_JDBC # jdbc
#            onMatch: DENY
#            onMismatch: NEUTRAL
#          - marker: LOG4JDBC_CONNECTION # jdbc.connection
#            onMatch: DENY
#            onMismatch: DENY
#          - marker: LOG4JDBC_NON_STATEMENT # jdbc.sqltiming
#            onMatch: ACCEPT
#            onMismatch: DENY
#          - marker: LOG4JDBC_SQL
#            onMatch: DENY
#            onMismatch: DENY
#          - marker: LOG4JDBC_AUDIT # jdbc.audit
#            onMatch: DENY
#            onMismatch: DENY
#          - marker: LOG4JDBC_RESULTSET # jdbc.resultset
#            onMatch: DENY
#            onMismatch: DENY
          - marker: LOG4JDBC_RESULTSETTABLE # jdbc.resultsettable
            onMatch: DENY
            onMismatch: DENY

# 88888888
      - name: log.munzi.interceptor
        includeLocation: TRUE
        additivity: FALSE
        level: INFO
        AppenderRef:
          - ref: Console_Appender
          - ref: Info_Req_Res_RollingFile_Appender
          - ref: Debug_RollingFile_Appender

      - name: log.munzi.error
        includeLocation: TRUE
        additivity: FALSE
        level: ERROR
        AppenderRef:
          - ref: Console_Appender
          - ref: Info_Req_Res_RollingFile_Appender

      - name: log.munzi.stacktrace.error
        includeLocation: TRUE
        additivity: FALSE
        level: ERROR
        AppenderRef:
          - ref: Console_Appender
          - ref: Err_StackTrace_RollingFile_Appender

      - name: xxx.xxx.xxx.event.component
        includeLocation: TRUE
        additivity: FALSE
        level: INFO
        AppenderRef:
          - ref: Console_Appender
          - ref: Info_Event_RollingFile_Appender

      - name: xxx.xxx.xxx.scheduler
        includeLocation: TRUE
        additivity: FALSE
        level: INFO
        AppenderRef:
          - ref: Console_Appender
          - ref: Info_Scheduler_RollingFile_Appender
๐Ÿ’ก profile ์„ค์ •์„ ์œ„ํ•ด log4j2-local.yml ๋“ฑ์œผ๋กœ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  1. monitorInterval : ์„œ๋ฒ„๋ฅผ ์žฌ์‹œ์ž‘ ํ•˜์ง€ ์•Š์•„๋„, ์ ์šฉ๋œ ์‹œ๊ฐ„ ๋‹จ์œ„๋กœ(์ดˆ ๋‹จ์œ„) ํ•ด๋‹น ํŒŒ์ผ์˜ ์ˆ˜์ • ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•ด ์ฃผ๋Š” ์„ค์ •

  2. ํŒŒ์ผ ๋‚ด์—์„œ ์‚ฌ์šฉํ•  ๋ณ€์ˆ˜ ์ง€์ •

  3. Appender ์„ค์ • : ๋กœ๊ทธ๋ฅผ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ์ฐ์„ ๊ฒƒ์ธ์ง€ ์„ค์ •

    ConsoleAppender, FileAppender, RollingFileAppender ๋“ฑ ์กด์žฌ

    Console : console์— System.out์œผ๋กœ ์ฐ์Œ

    File : ํŒŒ์ผ์— ์ฐ์Œ

    RollingFile : ํŒŒ์ผ์— ์ฐ๊ณ , ํŠน์ • ๊ธฐ์ค€์— ๋”ฐ๋ผ ์••์ถ•

    ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์•„๋ž˜ ๋งํฌ ์ฐธ๊ณ ! Log4j 2 ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ธฐ - ๊ฐœ๋…

  4. Logger : ์–ด๋””์—์„œ ์ฐ์„์ง€ ์„ค์ •ํ•  ๋ถ€๋ถ„

  5. Root : ๋ชจ๋“  ๋กœ๊ทธ

    โ†’ INFO ๋ ˆ๋ฒจ ์ด์ƒ์˜ ๋ชจ๋“  ๋กœ๊ทธ๋ฅผ Console_Appender๋ฅผ ์ด์šฉํ•ด ์ฐ๊ฒ ๋‹ค๊ณ  ์„ค์ •ํ•œ ๋ถ€๋ถ„

  6. ํŒจํ‚ค์ง€ ๋‹จ์œ„ ์„ค์ •

    ๋™๊ธฐ ๋ฐฉ์‹์˜ Logger๊ฐ€ ์žˆ๊ณ , ๋น„๋™๊ธฐ ๋ฐฉ์‹์˜ AsyncLogger๊ฐ€ ์žˆ๋Š”๋ฐ

    ๋น„๋™๊ธฐ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ, includeLocation: true๋ฅผ ์„ค์ •ํ•ด ์ค˜์•ผ ํ˜ธ์ถœํ•œ ๊ฒฝ๋กœ๋ฅผ ์ฐพ์•„์˜ฌ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ถ™์—ฌ์ฃผ์ž.

    name : package ๊ฒฝ๋กœ

    additivity : ์ค‘๋ณต ์ œ๊ฑฐ ์„ค์ •

  7. log4jdbc-log4j2๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, log4jdbc.log4j2์—์„œ ๋ชจ๋“  ๋กœ๊ทธ๋ฅผ ์ฐ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—

    ๊ธฐ์กด์— application.yml์—์„œ logging.jdbc.connection: ERROR ์‹์œผ๋กœ ์ผ๋˜ ๋ถ€๋ถ„์„ ์ƒ์„ธํ•˜๊ฒŒ ์„ค์ •ํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์—” MarkerFilter๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์„ค์ •ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

    ์œ„ ์†Œ์Šค๋Š” jdbc.resultsettable์ด๋ฉด ์ฐ๊ณ , ๊ทธ ์™ธ์—๋Š” ๋ชจ๋‘ ์ฐ์ง€ ์•Š๊ฒ ๋‹ค๊ณ  ์„ค์ •ํ•ด ๋†“์€ ๊ฒƒ์ด๋‹ค.

  8. req, res, err ๋กœ๊ทธ๋ฅผ log.munzi.interceptor์—์„œ ์ฐ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.


< DB๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ! >

<build.gradle ํŒŒ์ผ>

configurations {
...
    all {
        ...
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
        exclude group: 'org.bgee.log4jdbc-log4j2', module: 'log4jdbc-log4j2-jdbc4.1'
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-data-jpa'
        resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
    }
}