# Logback์ด๋
Logback์ ์ฌ์ฉํ๊ธฐ์ ์์์, SLF4J๋ฅผ ์์์ผ ํ๋ค.
Simple Logging Facade for Java์ ์ฝ์๋ก Log4J์ ๊ฐ๋ฐ์๊ฐ Logback๊ณผ ํจ๊ป ๊ฐ๋ฐํ ๋ก๊น ์ ๋ํ ์ธํฐํ์ด์ค ๋ชจ์์ด๋ค. ๋ก๊น ์ ๋ํ ์ถ์ ๋ ์ด์ด๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด๊ณ ์ธํผํ ์ด์ค ๋ฉ์ด๋ฆฌ๋ผ๊ณ ๋ณด๋ฉด ๋๋ค. ์ด๋ฌํ ์ด์ ๋ก ์ธํด์ artifact ์ด๋ฆ๋ api๊ฐ ๋ถ๋๋ค.
ํ์ง๋ง ์ด๋ฌํ Slf4J๋ฅผ ๋จ๋ ์ผ๋ก ์ฌ์ฉํ๋ค๋ฉด ๊ตฌํ์ฒด๊ฐ ์๋ค๋ ์๋ฌ๊ฐ ๋์จ๋ค. ๊ฐ๋จํ๊ฒ slf4j-simple์ ์ถ๊ฐ ํ ์๋ ์์ง๋ง, ๊ธฐ๋ฅ์ด ๋๋ฌด ๋จ์ํ๊ธฐ ๋๋ฌธ์ slf4j native ๊ตฌํ์ฒด์ธ logback์ ์ฌ์ฉํ๋ค.
๋ฐ๋ผ์ ๋ค์๊ณผ ๊ฐ์ด ์ค์ต์ ํด๋ณด๊ฒ ๋ค.
# 1.pom.xml ์์กด์ฑ ์ถ๊ฐ
<!-- ์์กด์ฑ ์ถ๊ฐ -->
<dependencies>
<!-- logback-core.jar ์ถ๊ฐ -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<!-- logback-classic.jar ์ถ๊ฐ -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- slf4j-api.jar ์ถ๊ฐ-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.28</version>
</dependency>
</dependencies>
# 2.๊ธฐ๋ณธ ์ฌ์ฉ ์์
/** ์๋ฐ ์์ **/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
// LoggerFactory ํด๋์ค์ getLogger๋ก Logger ๊ฐ์ฒด ์์ฑ
private static Logger logger = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
logger.trace("trace");
logger.debug("debug");
logger.info("info");
logger.warn("warn");
logger.error("error");
}
}
๋ก๊ทธ ๊ฒฐ๊ณผ ์ถ๋ ฅ ํจํด์ ์ค์ ํ์ผ์ ์ธํ ํ์ง ์๊ณ default๋ก ์ฐํ ๊ฒฝ์ฐ, '์๊ฐ / ํธ์ถ ๋ฉ์๋ / ๋ก๊ทธ ๋ ๋ฒจ / ํด๋์ค๋ช / ๋ก๊ทธ ๋ด์ฉ' ์์ผ๋ก ํจํด์ด ์ถ๋ ฅ๋๋ค. ๊ธฐ๋ณธ ์ค์ ์ ๋ก๊ทธ ์ถ๋ ฅ ๋ ๋ฒจ์ด debug์ด๊ธฐ ๋๋ฌธ์ trace ๋ ๋ฒจ์ ๋ก๊ทธ๋ ์ถ๋ ฅ์ด ๋์ง ์๋๋ค.
# 3.์ค์ ํ์ผ
# ์ค์ ํ์ผ ์์น
Classpath์ ์์น์์ผ์ผ ํ๋ค. Classpath๋ฅผ lib/๊ณผ ๊ฐ์ด ์ค์ ํ์๋ค๋ฉด lib/logback.xml๊ณผ ๊ฐ์ด ์์น์ํค๋ฉด ๋๋ค. ์๋ฅผ ๋ค์ด lib/a/ ๊ณผ ๊ฐ์ ์์น์ ๋๋ฉด ์ค์ ์ ์ ์ฉ๋์ง ์๋๋ค. ์ ์ฉํ ์ ์๋ ์ค์ ํ์ผ์ ๋ค์๊ณผ ๊ฐ๋ค.
- logback.groovy
- logback-test.xml
- logback.xml
์ 3๊ฐ์ ํ์ผ์ ์์๋๋ก ๋์ ์ฐ์ ์์๋ฅผ ๊ฐ์ง๋ค. ์ฆ, logback์ Classpath์์ ์์ ์ค์ ํ์ผ์ ์์๋๋ก ๊ฒ์ํ์ฌ ์ ์ฉํ๋ฉฐ, ์ฐ์ ์์๊ฐ ๋์ ์ค์ ํ์ผ์ ์ฐพ์ผ๋ฉด ํ์ ์ค์ ํ์ผ์ ๊ฒ์ํ์ง ์๋๋ค.
classpath๋?
JVM์ด ํ๋ก๊ทธ๋จ์ ์คํํ ๋, ํด๋์คํ์ผ์ ์ฐพ๋ ๋ฐ ๊ธฐ์ค์ด ๋๋ ํ์ผ ๊ฒฝ๋ก
# ์ค์ ํ์ผ์ ํญ๋ชฉ
Level : ์๋์ ๊ฐ์ ์์๋๋ก ๋์ ๋ ๋ฒจ์ด๋ฉฐ, ์ถ๋ ฅ ๋ ๋ฒจ์ ์ค์ ์ ๋ฐ๋ผ ์ค์ ๋ ๋ฒจ ์ด์์ ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ๋ค.
- ERROR
- WARN
- INFO
- DEBUG
- TRACE
ex) ์ถ๋ ฅ๋ ๋ฒจ์ INFO๋ก ์ค์ ํ๋ฉด, DEBUG, TRACE ๋ ๋ฒจ์ ๋ก๊ทธ๋ ์ถ๋ ฅ๋์ง ์๋๋ค.
Appender : ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ ์์น, ์ถ๋ ฅ ํ์ ๋ฑ์ ์ค์ ํ๋ค. Logback-core ๋ชจ๋์ ํตํด ์ฌ์ฉํ ์ ์๋ Appender๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด 3๊ฐ์ง๊ฐ ์๋ค.
- ConsoleAppender : ๋ก๊ทธ๋ฅผ OutputStream์ writeํ์ฌ, ์ต์ข ์ ์ผ๋ก ์ฝ์์ ์ถ๋ ฅ๋๋๋ก ํ๋ค.
- FileAppender : ๋ก๊ทธ์ ๋ด์ฉ์ ์ง์ ๋ File์ ๊ธฐ๋กํ๋ค.
- RollingFileAppender
- FileAppender๋ก๋ถํฐ ์์๋ฐ์ Appender๋ก์, ๋ ์ง, ์ต๋ ์ฉ๋ ๋ฑ์ ์ค์ ํ์ฌ ์ง์ ํ ํ์ผ๋ช ํจํด์ ๋ฐ๋ผ ๋ก๊ทธ๊ฐ ๋ค๋ฅธ ํ์ผ์ ๊ธฐ๋ก๋๋๋ก ํ๋ค. => ๋๋์ ๋ก๊ทธ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ธฐ๋ก ๊ฐ๋ฅ
- Logback-Core์ ๊ธฐ๋ณธ Appender ์ธ์๋ Logback-Classic ๋ชจ๋์ ๋ค์ํ Appender (SSLSocketAppender, SMTPAppender, DBAppender ๋ฑ)์ ์ฌ์ฉํ์ฌ ๋ก๊ทธ๋ฅผ ์๊ฒฉ์์น์ ๊ธฐ๋กํ ์๋ ์๋ค.
- Appender๋ค์ ํ์ ํญ๋ชฉ์ผ๋ก ์ถ๋ ฅ ํ์(Layout Pattern)์ ์ง์ ํ์ฌ ๊ฐ Appender๋ง๋ค ์ํ๋ ๋ด์ฉ์ ์ถ๋ ฅ์ํฌ ์ ์๋ค.
ex) %logger(Logger ์ด๋ฆ), %thread(ํ์ฌ ์ค๋ ๋๋ช ), %level(๋ก๊ทธ ๋ ๋ฒจ), %msg(๋ก๊ทธ๋ฉ์์ง), %n(new line) ๋ฑ
Logger
- ์ค์ ๋ก๊ทธ ๊ธฐ๋ฅ์ ์ํํ๋ ๊ฐ์ฒด๋ก ๊ฐ Logger๋ง๋ค ์ด๋ฆ์ ๋ถ์ฌํ์ฌ ์ฌ์ฉํ๋ค.
- ๊ฐ logger๋ง๋ค ์ํ๋ ์ถ๋ ฅ ๋ ๋ฒจ๊ฐ์ ์ค์ ํ ์ ์์ผ๋ฉฐ, 0๊ฐ ์ด์์ Appender๋ฅผ ์ง์ ํ ์ ์๋ค. ๊ฐ ์์ค๋ก๋ถํฐ ์ ๋ ฅ๋ฐ์ ๋ก๊น ๋ฉ์์ง๋ ๋ก๊ทธ ๋ ๋ฒจ์ ๋ฐ๋ผ Appender๋ก ์ ๋ฌ๋๋ค.
- ๊ธฐ๋ณธ์ ์ผ๋ก ์ต์์ ๋ก๊ฑฐ์ธ Root Logger๋ฅผ ์ค์ ํด ์ฃผ์ด์ผํ๋ฉฐ, ์ถ๊ฐ๋ก ํ์ํ ๋ก๊ฑฐ์ ๋ํด String ๋๋ ํด๋์ค๋ช ํ์์๋ก Logger name์ ์ถ๊ฐํ์ฌ ์ฌ์ฉํ ์ ์๋ค. ๋ํ Logger์ Name์ .๋ฌธ์๋ฅผ ๊ตฌ๋ถ์๋ก ์ฌ์ฉํ์ฌ ๊ณ์ธต์ ์ผ๋ก ํ์ฉํ ์ ์๋ค.
# 4. ์ค์ ํ์ผ ์์
# ์ค์ ํ์ผ ๊ธฐ๋ณธ ๊ตฌ์กฐ
<!-- ๊ธฐ๋ณธ ๊ตฌ์กฐ -->
<configuration>
<appender> <!--Appender ์ค์ --> </appender>
<logger> <!--Logger ์ค์ --> </logger>
</configuration>
# ์์
<!-- ์์ -->
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<property name="LOGS_ABSOLUTE_PATH" value="./logs" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%d{yyyy-MM-dd HH:mm:ss}][%-5level][%logger{36}] - %msg%n</pattern>
</encoder>
</appender>
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOGS_ABSOLUTE_PATH}/logback.log</file>
<encoder>
<pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOGS_ABSOLUTE_PATH}/logback.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- or whenever the file size reaches 100MB -->
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<logger name="src.Main" level="debug" additivity="false">
<appender-ref ref="ROLLING" />
</logger>
<logger name="src.Main.Child" additivity="true" />
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>
์ ์์์์๋ 2๊ฐ์ง์ Appender(Console, Rollingfile), **3๊ฐ์ง์ Logger(Root, src.Main, src.Main.Child)**๋ฅผ ์ฌ์ฉํ์๋ค.
RollingFileAppender์ ๊ฒฝ์ฐ ๋จผ์ ๊ธฐ๋ณธ ํ์ผ๋ช ์ ๊ฒฝ๋ก์ ํจ๊ป ์ง์ ํ๊ณ , ๋ก๊ทธ ํจํด๊ณผ Rolling ํ์ผ๋ช ํจํด์ ์ง์ ํด ์ฃผ๋ฉด ๋๋ค.
์์์์๋ ๋จผ์ **๋ ์ง(yyyy-mm-dd)**๋ฅผ ๊ธฐ์ค์ผ๋ก ํ์ผ๋ช ์ Rollingํ๊ณ , timeBasedFileNamingAndTriggeringPolicy ํญ๋ชฉ์ ํตํด 100MB์ ์ฉ๋ ์ ํ์ ์ค์ ํ์ฌ Rolling ํ๋๋ก ํ์๋ค.
์ฌ๊ธฐ์ ์ฉ๋์ ํ์ ์ค์ ํ ๊ฒฝ์ฐ ํ์ผ๋ช ํจํด์ %i ์ ๊ฐ์ด ํ์ผ๋ช ์ ๋ณํ๋ฅผ ์ค ์์๋ ์ธ์๋ฅผ ์ถ๊ฐํด ์ฃผ์ด์ผ ํ๋ค.
configuration์ ํ์ ํญ๋ชฉ์ผ๋ก scan๊ณผ scanPeriod ํญ๋ชฉ์ ์ถ๊ฐํ์ฌ Auto-Reloading ๊ธฐ๋ฅ์ ํ์ฑํ ์ํฌ ์๋ ์๋ค.
# Reference
- https://hochoon-dev.tistory.com/entry/JAVA-Logback-%EC%82%AC%EC%9A%A9%EB%B2%95
- https://thinkwarelab.wordpress.com/2016/11/18/java์์-logback์-์ด์ฉํ-๋ก๊น logging-์ฌ์ฉ๋ฒ/
- https://sonegy.wordpress.com/2014/05/23/how-to-slf4j/