๐ Logging - Log4j, Log4j2, Slf4j, Logback
๋ก๊ทธ(Log) ๋ ๊ธฐ๋ก์ ๋จ๊ธฐ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ๋ก๊ทธ๋ฅผ ํตํด ์ํํธ์จ์ด์ ๊ฐ๋ฐ์ด๋ ์ด์ ์ ๋ฐ์ํ๋ ๋ฌธ์ ์ ์ ํ์ ํ ์ ์์ต๋๋ค.
์ค๋ฅ๊ฐ ๋ฐ์ํ์๋ ๊ฐ์ฅ ๋จผ์ ํ์ธํ๋ ๊ฒ์ด ๋ก๊ทธ๋ฅผ ๋ณด๋ ๊ฒ์ด๋ฏ๋ก, ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๋ ๊ฒ์ ๊ต์ฅํ ์ค์ํ๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ค์ ์ํํธ์จ์ด์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์๋, ์ ์ฌ์ ์์ ๋ก๊ทธ๊ฐ ์ถ๋ ฅ์ด ๋๊ณ ์๋ค๋ฉด ๋ฌธ์ ์ ์์ธ์ ๋ํด ์ ํํ ํ์ ์ด ๊ฐ๋ฅํฉ๋๋ค.
Java์์๋ Log4j, Log4j2, Slf4j, Logback ๋ฑ ๋ค์ํ ๋ก๊น ํ๋ ์์ํฌ๊ฐ ์กด์ฌํ๋๋ฐ์, ์ด์ ๋ํด ๊ฐ๋ตํ ์์๋ณด๊ฒ ์ต๋๋ค.
๐ป Log4j
Apache Log4j ๋ ๋ค๋ฅธ ๋ก๊น ํ๋ ์์ํฌ์ ๋นํด ์ํ์น ์ฌ๋จ์ ๊ฐ์ฅ ์ค๋๋ ํ๋ ์์ํฌ์ ๋๋ค. ์ฝ์ ๋ฐ ํ์ผ ์ถ๋ ฅ์ ํํ๋ก ๋ก๊ทธ๋ฅผ ๋จ๊ธธ ์ ์์ผ๋ฉฐ, xml์ด๋ properties ํ๊ฒฝ์ผ๋ก ๊ตฌ์ฑํ ์ ์์ต๋๋ค. Apache ๊ณต์๋ฌธ์์์๋ 2015๋ 8์์ ๋์ผ๋ก Log4j๋ ๊ฐ๋ฐ์ด ์ค๋จ๋์์ผ๋ฉฐ, Log4j2๋ก ์ ๊ทธ๋ ์ด๋ ํ ๊ฒ์ ๊ถ์ฅํ๋ค๊ณ ํฉ๋๋ค.
Log4j๋ ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์ฑ ๋ฐ ๋ก๊ทธ ๋ ๋ฒจ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
Log4j ๊ตฌ์ฑ
์์ | ์ค๋ช |
Logger | ์ถ๋ ฅํ ๋ฉ์์ง๋ฅผ Appender์๊ฒ ์ ๋ฌ |
Appender | ์ ๋ฌ๋ ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ ๋์์ ์ง์ (File, Console, JDBC ๋ฑ) |
Layout | ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ ํ์์ ์ง์ |
Log4j์ ๋ก๊ทธ ๋ ๋ฒจ
๋ก๊ทธ ๋ ๋ฒจ | ์ค๋ช |
FATAL | ์์ฃผ ์ฌ๊ฐํ ์๋ฌ๊ฐ ๋ฐ์ํ ์ํ. ์ผ๋ฐ์ ์ธ ์ดํ๋ฆฌ์ผ์ด์ ์์๋ ์ฌ์ฉํ ์ผ์ด ์์ |
ERROR | ์์ฒญ์ ์ฒ๋ฆฌํ๋ ์ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ํ |
WARN | ์คํ์๋ ๋ฌธ์ ๊ฐ ์์ผ๋ ํฅํ ์๋ฌ๊ฐ ๋ฐ์ํ ์ ์๋ ๊ฒฝ๊ณ ์ฑ ๋ฉ์์ง |
INFO | ๋ก๊ทธ์ธ, ์ํ๋ณ๊ฒฝ๊ณผ ๊ฐ์ ์ ๋ณด์ฑ ๋ฉ์์ง |
DEBUG | ๋๋ฒ๊ทธ ์ฉ๋๋ก ์ฌ์ฉํ๋ ๋ฉ์์ง |
TRACE | ๋๋ฒ๊ทธ ๋ ๋ฒจ๋ณด๋ค ์์ธํ ์ด๋ฒคํธ๋ฅผ ๋ํ๋ด๋ ๋ฉ์์ง |
๋ก๊ทธ ๋ ๋ฒจ์ FATAL > ERROR > WARN > INFO > DEBUG > TRACE ์์๋ฅผ ๊ฐ์ง๋ฉฐ, DEBUG์ ๋ก๊ทธ ๋ ๋ฒจ๋ก ์ง์ ํ๋ฉด ์์ ๋ ๋ฒจ์ธ FATAL ~ DEBUG๊น์ง ๋ก๊ทธ๊ฐ ์ถ๋ ฅ์ด ๋ฉ๋๋ค. |
Log4j ์์
์์กด์ฑ ์ถ๊ฐ
// gradle
implementation group: 'log4j', name: 'log4j', version: '1.2.17'
// maven
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
resources ๋๋ ํ ๋ฆฌ ํ์์ log4j.xml ํ์ผ ์ถ๊ฐ(Console)
<log4j:configuration debug="false">
<!--Console appender -->
<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %p %m%n"/>
</layout>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="stdout"/>
</root>
</log4j:configuration>
์์ ์ฝ๋
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class Logging {
private static final Logger logger = Logger.getLogger(Logging.class);
public static void main(String[] args) {
logger.setLevel(Level.DEBUG);
logger.fatal("FATAL Logging");
logger.error("ERROR Logging");
logger.warn("WARN Logging");
logger.info("INFO Logging");
logger.debug("DEBUG Logging");
logger.trace("TRACE Logging");
}
}
โป ๋ค์๊ณผ ๊ฐ์ด {}์ ์ธ์๋ฅผ ๋ฃ์ด์ค์ผ๋ก์จ ์ถ๋ ฅ์ ํ ์ ์์ต๋๋ค.
// logger.info("์์ฒญ URL: " + request.getRequestUrl());
logger.info("์์ฒญ URL: {}",request.getRequestUrl());
logger.info("์์ฒญ ์๊ฐ: {}",LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
logger.info("์์ฒญ IP: {}",request.getRemoteAddr());
String์ ๋ํ๊ธฐ ์ฐ์ฐ(+)์ ํตํด ๋ฌธ์์ด์ ์ฐ๊ฒฐํ์ง ์๊ณ ์์ ๊ฐ์ด ์ฌ์ฉํ๋ ๊ฒ์ด ์ฑ๋ฅ์์ผ๋ก ์ด์ ์ ๊ฐ์ ธ๊ฐ๊ฒ ๋๋ค๊ณ ํ๋, ์์ ๊ฐ์ด ์ฌ์ฉํ๋ ๊ฒ์ ์ถ์ฒ๋๋ฆฝ๋๋ค.
๐ป Log4j2
Apache Log4j2 ๋ ์ด์ ๋ฒ์ ์ธ Log4j 1.x์ ๋นํด ์๋นํ ๊ฐ์ ๋ Log4j์ ์ ๊ทธ๋ ์ด๋ ๋ ๋ฒ์ ์ผ๋ก Logback ์ํคํ ์ณ์ ๋ด์ฌ๋ ๋ช ๊ฐ์ง ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ฉด์ Logback์์ ์ฌ์ฉํ ์ ์๋ ๋ก๊น ํ๋ ์์ํฌ์ ๋๋ค.
Logback์ฒ๋ผ ํํฐ๋ง ๊ธฐ๋ฅ๊ณผ ์๋ ๋ฆฌ๋ก๋ฉ์ ์ง์ํ๋ฉฐ, ์ฐจ์ด์ ์ ๋ฉํฐ ์ค๋ ๋ ํ๊ฒฝ์์ ๋น๋๊ธฐ ๋ก๊ฑฐ(Async Logger)๋ ๋ค๋ฅธ ๋ก๊น ํ๋ ์์ํฌ๋ณด๋ค ์ฒ๋ฆฌ๋์ด ํจ์ฌ ๋ง๊ณ , ๋๊ธฐ ์๊ฐ์ด ํจ์ฌ ์งง์ต๋๋ค. ๋ํ Java8์ ๋์ ๋ ๋๋ค์์ ์ง์ํ๊ณ , Lazy Evaluation์ ์ง์ํฉ๋๋ค.
Log4j 1.x ๋ฒ์ ๊ณผ์ ์ฐจ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์ ๋ขฐ์ฑ ํฅ์: Log4j 1.x์ด๋ Logback๊ณผ ๊ฐ์ด ํ๋ ์์ํฌ๋ฅผ ์ฌ๊ตฌ์ฑํ๋ ๋์ ๋ฉ์์ง๊ฐ ์์ค๋์ง ์์ต๋๋ค
- ํ์ฅ์ฑ: Log4j2๋ ์ฌ์ฉ์๊ฐ ์ปค์คํ ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ์ฑํ๊ณ ์ ์ํ ์ ์๋๋ก ํ๋ฌ๊ทธ์ธ ์์คํ ์ ์ง์ํฉ๋๋ค.
- ๊ฐ๋จํ ๊ตฌ์ฑ ๋ฌธ๋ฒ
- xml, json, yaml, properties ์์ฑ ์ง์
- ๊ฐ์ ๋ filters
- ํ๊ฒฝํ์ผ, ์์คํ ์์ฑ, ํ๊ฒฝ ๋ณ์, ThreadContextMap, ์ด๋ฒคํธ์ ์ ์๋ ๊ฐ์ ๋ํ Property ์กฐํ ์ง์
- ๋ค์ค API ์ง์: Log4j2๋ Log4j2, Log4j, Slf4j, Commong Logging ๋ฐ julva.util.logging(JUL) API๋ฅผ ์ฌ์ฉํ๋ ์์ฉ ํ๋ก๊ทธ๋จ๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ์ฌ์ฉ์ ์ปค์คํ ๋ก๊ทธ ๋ ๋ฒจ
- "Lazy Logging"์ ์ํ Java8 ์คํ์ผ์ ๋๋ค ์ง์
- ํฅ์๋ ์๋
์ถ์ฒ: https://en.wikipedia.org/wiki/Log4j
๐ป Slf4j
Slf4j(Simple Logging Facaed for Java) ๋ ์์ฒด์ ์ธ ๋ก๊น ํ๋ ์์ํฌ๊ฐ ์๋ logger์ ์ถ์์ฒด๋ก์ ๋ค๋ฅธ ๋ก๊น ํ๋ ์์ํฌ๊ฐ ์ ๊ทผํ ์ ์๋๋ก ๋์์ฃผ๋ ์ถ์ํ ๊ณ์ธต์ ๋๋ค. ์ฆ, Log4j๋ Logback์ ๊ฐ์ ๋ก๊น ํ๋ ์์ํฌ์ ์ธํฐํ์ด์ค ์ญํ ์ ํฉ๋๋ค.
๋ฐ๋ผ์ Slf4j๋ฅผ ์ด์ฉํ๋ฉด ๋ก๊น ํ๋ ์์ํฌ๊ฐ ๋ค๋ฅธ ๊ตฌํ์ฒด๋ก ๋ณ๊ฒฝ๋๋๋ผ๋ ์ฝ๋๋ฅผ ์ ์ฐํ๊ฒ ์์ ํ ์ ์๋ ์ฅ์ ์ด ์์ต๋๋ค.
โป ์ฐธ๊ณ : ๋์์ธ ํจํด - ํผ์ฌ๋ ํจํด(Facade Pattern)
์ถ์ฒ: http://www.slf4j.org/manual.html
๐ป Logback
Logback ์ Log4j๋ณด๋ค ํฅ์๋ ๋ก๊น ํ๋ ์์ํฌ๋ก ๊ฐ์ฅ ๋๋ฆฌ ์ฌ์ฉ๋๊ณ ์์ต๋๋ค. ์ด์ ์ ์๊ฐ๋๋ฆฐ Slf4j ์ ๊ตฌํ์ฒด๋ก์จ ๋์ํ๋ Logback์ ์ ๊ฐ ์ฃผ๋ก ์ฌ์ฉํ๊ณ ์๋ ์คํ๋ง๋ถํธ์ ๊ฒฝ์ฐ spring-boot-starter-web ์์กด์ฑ ๋ด๋ถ์ logback ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ํฌํจ๋์ด ์๊ธฐ ๋๋ฌธ์ ์ถ๊ฐ์ ์ธ ์ค์ ์์ด ์ฌ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
Logback ์์
์์กด์ฑ ์ถ๊ฐ
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation('org.slf4j:jcl-over-slf4j')
implementation('ch.qos.logback:logback-classic')
resources ๋๋ ํ ๋ฆฌ ํ์์ logback.xml ํ์ผ ์ถ๊ฐ(File)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- ์ฝ์๋ก ๋ก๊ทธ๋ฅผ ๋จ๊น -->
<appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<Pattern>
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n
</Pattern>
</encoder>
</appender>
<!-- ํ์ผ๋ก ๋ก๊ทธ๋ฅผ ๋จ๊น -->
<appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/Users/juhyun/Desktop/study/logback.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n
</Pattern>
</encoder>
<!-- ๋ก๊ทธ ํ์ผ์ด 10KB๊ฐ ๋์ผ๋ฉด ์๋ก์ด ๋ก๊ทธ ํ์ผ๋ก ๋ง๋๋ ์ ์ฑ
-->
<triggeringPolicy
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10KB</MaxFileSize>
</triggeringPolicy>
<!-- ํ์ผ์ ๋ฎ์ด์ฐ๋ ์ ์ฑ
-->
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<FileNamePattern>/Users/juhyun/Desktop/study/logback2.%i.log.zip</FileNamePattern>
<!--
MinIndex, MaxIndex => ๋ก๊ทธ ํ์ผ ์ ์ฑ
logback2.1.log.zip, logback2.2.log.zip, ...
-->
<MinIndex>1</MinIndex>
<MaxIndex>10</MaxIndex>
</rollingPolicy>
</appender>
<!-- com.juhyun ํ์ ํจํค์ง -->
<logger name="com.juhyun" level="info" additivity="false">
<appender-ref ref="fileAppender" />
</logger>
</configuration>
์ ํ์ผ์ ๋ํด ์ฃผ์์ ์ถ๊ฐํ์ง๋ง, ๊ฐ๋ตํ๊ฒ ์ค๋ช ๋๋ฆฌ๊ฒ ์ต๋๋ค.
<appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
- RollingFileAppender ํด๋์ค๋ FileAppender ํด๋์ค๋ฅผ ์์๋ฐ์ผ๋ฉฐ ๋ก๊ทธ ํ์ผ์ ๋กค์ค๋ฒ ํ๋ฅ ๊ธฐ๋ฅ์ ๋๋ค.
์ถ์ฒ: http://logback.qos.ch/manual/appenders.html
%d{HH:mm:ss.SSS}
- ๋ก๊ทธ๊ฐ ์ถ๋ ฅ๋๋ ์๊ฐ์ ๊ธฐ๋กํ๋ ์ค์ ์ ๋๋ค.
[%thread]
- ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ๋ ์ค๋ ๋๋ฅผ ๊ธฐ๋กํฉ๋๋ค.
%-5level
- ๋ก๊ทธ ๋ ๋ฒจ์ ์ถ๋ ฅํฉ๋๋ค.
- -5๋ 5์นธ์ ์ฐจ์งํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
%logger{5}
- ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ java ํ์ผ๋ช ์ ๋ํ๋ด๋ฉฐ, {5}์ ํ์ผ๋ช ์ ํฌ๋งทํ ํ์์ ๋๋ค.
%msg%n
- ๋ฉ์์ง์ ๊ฐํ(์ค๋ฐ๊ฟ)์ ์๋ฏธํฉ๋๋ค.
์์ ์ฝ๋
package com.juhyun;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Logging {
public static void main(String[] args) {
log.debug("Logging - Debug log");
log.info("Logging - Info log");
log.warn("Logging - Warn log");
log.error("Logging - Error log");
}
}
์ ์ฝ๋๋ฅผ ์คํํด๋ณด๋ฉด ์๋์ ๊ฐ์ด xmlํ์ผ์ ์ค์ ํ ๊ฒฝ๋ก์ log ํ์ผ์ด ์์ฑ๋๋๊ฑธ ํ์ธํ ์ ์์ต๋๋ค.
file์ ์ถ๋ ฅํ ๋ก๊ทธ ๋ ๋ฒจ์ info๋ก ์ค์ ํ๊ธฐ ๋๋ฌธ์, ํ์ ๋ ๋ฒจ์ธ Debug๋ ์ถ๋ ฅ์ด ๋์ง ์์ต๋๋ค.
๐ ์ ๋ฆฌ
์ด์์ผ๋ก ๊ฐ๋ตํ๊ฒ ๋ก๊น ์ ๋ํด ์ ๋ฆฌ๋ฅผ ํด๋ณด์์ต๋๋ค.
๋ค์ํ ์ต์ ์ ์ถ๊ฐํ๋ฉด ํด๋์ค๋ณ๋ก ๋ก๊ทธ ํ์ผ์ ๋จ๊ธฐ๊ฑฐ๋, ๋ก๊ทธ ๋ ๋ฒจ์ ์ค์ ํ์ฌ ์ข ๋ ์ ํํ ๋ก๊ทธ๋ฅผ ๋จ๊ธธ ์ ์์ต๋๋ค.
๊ฐ๋ฐ์ ํ๋ฉฐ ์ค๋ฅ๋ฅผ ํด๊ฒฐํ ์ ์๋ ๊ฐ์ฅ ์ค์ํ ๋ฐฉ๋ฒ ์ค ํ๋๊ฐ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ ๋ก๊ทธ๋ ์ต๋ํ ์์ธํ ํด๋น ์ค๋ฅ์ ๋ํด ๋จ๊ฒจ์ฃผ๋๊ฒ ์ข๋ค๊ณ ์๊ฐํฉ๋๋ค.
References
- https://logging.apache.org/log4j/2.x/
- https://minkwon4.tistory.com/161
- https://logging.apache.org/log4j/2.x/performance.html
- https://www.baeldung.com/log4j-no-appenders-found
- http://www.slf4j.org/manual.html
- http://logback.qos.ch/manual/appenders.html
'Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring Boot SQL ์ค์ (hibernate, logging) (4) | 2022.03.12 |
---|---|
Spring AOP - (2) AOP ๊ฐ๋ ๋ฐ ์ค์ต (0) | 2021.09.24 |
Spring Validation - @NotNull, @NotEmpty, @NotBlank (0) | 2021.09.09 |
Spring Boot + MockMvc ํ ์คํธ(feat. Kotlin) (0) | 2021.09.07 |
[Spring] - @JsonProperty, @JsonNaming (2) | 2021.09.02 |
๋๊ธ