SpringBoot에서 Logger마다 각기 다른 파일에 분리하는 방법에 대해 정리합니다.
1. 요구사항과 예제
- 에러 로그는 logs/error/error.log 에 기록되어야 한다
- sql 실행 시간을 기록한 로그는 logs/sql/sql_execute_time.log 에 기록되어야 한다
- warn 로그는 logs/warn/warn.log에 기록되어야 한다.
요구사항과 예제를 간단하게 구현한 클래스입니다.
public class LoggerTest { private ErrorLogger errorLogger = new ErrorLogger(); private WarnLogger warnLogger = new WarnLogger(); private SqlLogger sqlLogger = new SqlLogger(); public void call(String message) { errorLogger.errorLog(message); warnLogger.warnLog(message); sqlLogger.sqlLog(); } public static class ErrorLogger { // 1. private static final Logger errorLogger = LoggerFactory.getLogger("errorLogger"); public void errorLog(String message) { errorLogger.error(message); } } // 2. @Slf4j(topic = "warnLogger") public static class WarnLogger { public void warnLog(String message) { log.warn(message); } } public static class SqlLogger { // 3. private static final Logger sqlLogger = LoggerFactory.getLogger("sqlLogger"); public void sqlLog() { sqlLogger.debug("execute time 0.01s"); } } public static void main(String[] args) { LoggerTest loggerTest = new LoggerTest(); loggerTest.call("로그 테스트"); // 4 } }
한 파일에 넣어 간단히 정리한 클래스 입니다.
각기 다른 로거를 사용하며, call() 메소드로 한번에 다 출력하도록 했습니다.
- error 레벨을 기록할 로거(Logger) 입니다. error 로거의 이름을 errorLogger 라고 명명
- warn 레벨을 기록할 로거(Logger) 입니다. warn 로거의 이름을 warnLogger라고 명명 하였습니다.
- @Slf4j의 topic값을 지정하면 (위에서는 warnLogger) 해당 로거의 이름이 명명됩니다.
- https://projectlombok.org/api/lombok/extern/slf4j/Slf4j
- https://projectlombok.org/features/log
- sql을 기록할 로거입니다. sql 로거의 이름을 sqlLogger 명명
결과
> cat ./error/error.log 2023-05-25 03:08:06,911 GMT [ERROR] [main] [errorLogger.errorLog(36)] 로그 테스트 > cat ./warn/warn.log 2023-05-25 03:08:06,912 GMT [WARN ] [main] [warnLogger.warnLog(52)] 로그 테스트 2023-05-25 03:08:06,912 GMT [WARN ] [main] [warnLogger.aopWarnLog(44)] 로그 테스트 > cat ./sql/sql_execute_time.log 2023-05-25 03:08:06,912 GMT [DEBUG] [main] [sqlLogger.sqlLog(60)] execute time 0.01s
Loggger의 name 지정과 동일 로거
LoggerFactory.getLogger(name); // or @Slf4j(topic = name)
라고 같은 name을 지정하게 되면, 동일한 Logger를 사용하게 됩니다.
public static class AopLogger { private static final Logger logger = LoggerFactory.getLogger("warnLogger"); public void aopWarnLog(String message) { logger.warn(message + "className {}, object : {} hashCode : {}", logger.getName(), logger, logger.hashCode() ); } } @Slf4j(topic = "warnLogger") public static class WarnLogger { public void warnLog(String message) { log.warn(message + "className {}, object : {} hashCode : {}", log.getName(), log, log.hashCode() ); } }
결과
2023-05-25 03:04:49,523 GMT [WARN ] [main] [warnLogger.warnLog(55)] 로그 테스트 className warnLogger, object : Logger[warnLogger] hashCode : 1800031768 2023-05-25 03:04:49,524 GMT [WARN ] [main] [warnLogger.aopWarnLog(44)] 로그 테스트 className warnLogger, object : Logger[warnLogger] hashCode : 1800031768
@Slf4j 어노테이션 ?
lombok의 @Slf4j 어노테이션을 사용하면 편하게 사용할 수 있습니다.
@Slf4j어노테이션 사용시 변환되는 코드는 아래와 같습니다.
@Slf4j public class LoggerClass { }
위처럼 선언시 아래처럼 작동합니다.
// generate public class LoggerClass { private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggerClass.class); }
만약 @Slf4j의 Topic값을 지정하면, 로거의 이름이 됩니다.
Slf4j 이외에도 다음 Logger를 제공합니다.
어노테이션 | Logger 클래스 |
---|---|
@CommonsLog |
org.apache.commons.logging.Log |
@Log |
org.apache.commons.logging.Log |
@Log4j |
org.apache.log4j.Logger |
@Log4j2 |
org.apache.logging.log4j.Logger |
@Slf4j |
org.slf4j.Logger |
@XSlf4j |
org.slf4j.ext.XLogger |
2. 로그백 (logback.xml) 설정
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="consoleLogback" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <!--<pattern>[%date GMT][%-5level][%logger{36}.%M\(%line\)] %msg %n</pattern>--> <pattern>%cyan(%date GMT) [%highlight(%-5level)] [%magenta(%thread)] [%boldBlue(%logger{36}.%M\(%line\))] %msg %n</pattern> </encoder> </appender> <!-- profile이 local인 경우--> <springProfile name="local"> <property name="PATH" value="./logs/local.log"/> </springProfile> <!-- warn 패턴 --> <property name="WARN_LOG_PATTERN" value="%cyan(%date GMT) [%highlight(%-5level)] [%magenta(%thread)] [%blue(%logger{36}.%M\(%line\))] %msg %n"/> <!-- 1. error Level Logger 지정 --> <appender name="errorLogger" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/error/error.log</file> <append>true</append> <encoder> <pattern>%cyan(%date GMT) [%highlight(%-5level)] [%magenta(%thread)] [%red(%logger{36}.%M\(%line\))] %msg %n</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>logs/error/error.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxFileSize>30MB</maxFileSize> <maxHistory>15</maxHistory> <!--전체 용량 제어(maxHistory와 함께 사용 필수)--> <totalSizeCap>1GB</totalSizeCap> </rollingPolicy> </appender> <!-- 2. warn Level Logger 지정 --> <appender name="warnLogger" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/warn/warn.log</file> <append>true</append> <encoder> <pattern>${WARN_LOG_PATTERN}</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>logs/warn/warn.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxFileSize>30MB</maxFileSize> <maxHistory>15</maxHistory> <!--전체 용량 제어(maxHistory와 함께 사용 필수)--> <totalSizeCap>1GB</totalSizeCap> </rollingPolicy> </appender> <!-- 3. sql Logger 지정 --> <appender name="sqlLogger" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/sql/sql_execute_time.log</file> <append>true</append> <encoder> <pattern>%cyan(%date GMT) [%highlight(%-5level)] [%magenta(%thread)] [%blue(%logger{36}.%M\(%line\))] %msg %n</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>logs/sql/sql_execute_time.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxFileSize>30MB</maxFileSize> <maxHistory>15</maxHistory> <!--전체 용량 제어(maxHistory와 함께 사용 필수)--> <totalSizeCap>1GB</totalSizeCap> </rollingPolicy> </appender> <!-- 4. sqlLogger 지정 --> <logger name="sqlLogger" level="debug" additivity="false"> <appender-ref ref="sqlLogger" /> <appender-ref ref="consoleLogback"/> </logger> <logger name="warnLogger" level="warn" additivity="false"> <appender-ref ref="warnLogger" /> <appender-ref ref="consoleLogback"/> </logger> <logger name="errorLogger" level="error" additivity="false"> <appender-ref ref="errorLogger" /> <appender-ref ref="consoleLogback"/> </logger> <root> <level value="debug"/> <appender-ref ref="consoleLogback"/> </root> </configuration>
구성 방법은 간단합니다
- 지정한 Logger의 이름으로 appender를 생성합니다.
- sqlLogger, errorLogger, warnLogger
- RollingFileAppender를 선택했습니다. maxFileSize로 사이즈를 지정했으며 이 크기를 초과하면 새로운 파일이 생성됩니다,
- maxHistory로 삭제 주기를 지정했습니다.
- 각각의 Appender는 다음과 같은 일을 합니다.
- error Level Logger - logs/error/ 아래 위치에 error.log라는 파일로 지정한 패턴대로 로그를 기록
- warn Level Logger - logs/warn/ 아래 위치에 warn.log라는 파일로,
<property>
로 지정한 패턴대로 로그를 기록 - sql Logger - logs/sql/ 아래 위치에 sql_execute_time.log라는 파일로 지정한 패턴대로 기록
- rollingPolicy를 따라 기록하게 됩니다.
<logger name = >
으로 logger의 이름과 appender를 지정했습니다. 지정한 appender를 사용하게 됩니다.
'Spring > log' 카테고리의 다른 글
Logback + MDC를 이용한 request 로깅 (0) | 2023.06.21 |
---|---|
Logback.xml include 태그 사용하여 깔끔하게 분리하기 (0) | 2023.05.26 |
Logback 을 이용하여 AWS Cloud Watch에 로그 전송 (0) | 2023.05.26 |
Logback 사용 정리 (0) | 2023.05.25 |
Java 로깅 logger, log4j, logback, slf4j 비교 (0) | 2023.05.25 |