Java์ ์ฌ๋ฌ๊ฐ์ง Logger๋ค
Java ์ง์์๋ ์ฌ๋ฌ๊ฐ์ง ๋ก๊น ๊ด๋ จ ํ๋ ์์ํฌ๊ฐ ์์ต๋๋ค. ํํ ์ ํ๊ธฐ ์ด๋ ค์ด commons logging๊ณผ JUL(Java Uitl Logging)๋ ์๊ณ ์. ์ด๋ฒ์ ๋น๊ตํ ๋์์ธ log4j, logback ๊ทธ๋ฆฌ๊ณ log4j2๊ฐ ์์ต๋๋ค.
๊ฐ๋จํ๊ฒ ์๊ฐ ์์๋๋ก ๋น๊ตํ๋ฉด log4j, logback, log4j2 ์์๋ก ๋ฑ์ฅํ์ต๋๋ค.
๊ทธ๋ฌ๋๊น log4j2๊ฐ ์๋์ ์ผ๋ก ์ต๊ทผ์ ๋ฑ์ฅํ ๋ก๊น
ํ๋ ์์ํฌ์ง์. logback๊ณผ log4j2๋ log4j๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๊ณ ์์ด์
์ค์ ํ๋ ๋ฐฉ๋ฒ์ด๋ ์ฌ์ฉ ๋ฐฉ๋ฒ์ด ์ ์ฌํฉ๋๋ค.
๋น์ทํ๊ธด ํ์ง๋ง ๋ค๋ฅธ ๋ก๊น
ํ๋ ์์ํฌ๋ก ์ ํํ ๋๋ฅผ ์๊ฐํ๋ค๋ฉด slf4j ๋ผ๋ ๋
์์ ๋์์ด ํ์ํฉ๋๋ค.
slf4j๋ Java ์ง์์ ๋ก๊น
ํ๋ ์์ํฌ๋ค์ ์ถ์์ฒด(facade) ์ญํ ์ ํ๋๋ฐ์.
์๋ฐ๋ก ๋ฐ์ง๋ฉด ์ธํฐํ์ด์ค์ ๋น์ทํ ์ญํ ์ ํ๋ฉฐ ์ฌ์ฉ์ค์ธ ๋ก๊น
ํ๋ ์์ํฌ๊ฐ ๋ณ๊ฒฝ๋๋๋ผ๋
์์ค ์ฝ๋ ์์ฒด์ ๋ณ๊ฒฝ์ ๋ง์ ์ ์์ต๋๋ค.
Logger ์ถ์์ฒด slf4j
slf4j๋ ๋ง๊ทธ๋๋ก ๋ก๊น ์ ๋ํ ์ถ์์ฒด๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด๋ฉฐ ๊ทธ ์์ฒด๋ฅผ ์ฌ์ฉํ๋ ํธ์ ์ ์ต๋๋ค. ๊ฐ๋จํ๊ฒ ์์ ๋ฅผ ์ดํด๋ณด๋ฉด ์๋์ ๊ฐ์ต๋๋ค. ๋จผ์ ์๋์ ๊ฐ์ด dependency๋ฅผ ์ถ๊ฐํด์ผ ๊ฒ ์ง์?
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
์คํ์ ์ํ ์๋ฐ ์ฝ๋๋ ์์ฑํ๊ณ ์.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Kimtaeng
* Created on 2018. 9. 21.
*/
public class LoggingSample {
Logger logger = LoggerFactory.getLogger(LoggingSample.class);
public void someMethod() {
logger.info("Hello slf4j Logger!");
}
public static void main(String[] args) {
new LoggingSample().someMethod();
}
}
์คํํ๋ฉด ์๋์ ๊ฐ์ ์ค๋ฅ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
SLF4J: Defaulting to no-operation (NOP) logger implementation...์๋ต
๊ตฌํ์ฒด๊ฐ ์๋ค๋ ๋ป์ด์ง์. ์์ ์ธ๊ธํ์ง๋ง slf4j ์์ฒด๋ฅผ ๋ก๊ฑฐ๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ฅผ ๋ณธ ์ ์ด ๊ฑฐ์ ์๋ ๊ฒ ๊ฐ์ต๋๋ค๋ง
๊ทธ๋๋ ๊ถ๊ธํจ์ ํด๊ฒฐํด๋ณด๊ณ ์โฆ slf4j-simple ์ด๋ผ๋ dependency๋ฅผ ์ถ๊ฐํด์ ์ฌ์ฉํด๋ด
์๋ค.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
์์ ๊ฐ์ด ๋ก๊ทธ๊ฐ ์ฐํ๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. ํ์ง๋ง ๊ธฐ๋ฅ์ด ๋๋ฌด ๋จ์ํ์ฌ ์ค์ ๋ก๋ ์ฌ์ฉํ ํ์๊ฐ ์๊ธดํฉ๋๋ค. ๋๋ถ๋ถ logback์ด๋ log4j2์ ๊ฐ์ ํ๋ ์์ํฌ์ ๊ฐ์ด ์ฌ์ฉํ์ง์. slf4j๊ฐ ์ธํฐํ์ด์ค์ ์ญํ ์ ํด์ฃผ๊ธฐ ๋๋ฌธ์ ๋ก๊น ๊ตฌํ์ฒด๊ฐ ๋ฐ๋๋๋ผ๋ ์๊ฐ๋ณด๋ค ์ด๋ ต์ง์๊ฒ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
์ด์ ์๋ log4j
Apache์ log4j๋ ๊ฝค ์ค๋๋ ๋ก๊น ํ๋ ์์ํฌ์ ๋๋ค. 2015๋ ์ ๊ฐ๋ฐํ์ log4j ๊ฐ๋ฐ ์ค๋จ ๋ฐํ๊ฐ ์์๊ณ ์. ์ด์ ๋ ์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ค๋ฉด ๋ค๋ฅธ ๋ก๊น ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
log4j๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์๋์ ๊ฐ์ด dependency ์ถ๊ฐ๊ฐ ํ์ํฉ๋๋ค.
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
์ค์ ์ ํ์ํ log4j.properties ํ์ผ๋ ํ์ํ๊ณ ์.
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] - %m%n
log4j.rootLogger=info, stdout
์๋์ ๊ฐ์ด ์คํํ์ฌ ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ ์๋ฐ ์ฝ๋๋ ์์ฑํด์ค๋๋ค.
import org.apache.log4j.Logger;
/**
* @author Kimtaeng
* Created on 2018. 9. 21.
*/
public class LoggingSample {
Logger logger = Logger.getLogger(LoggingSample.class);
public void someMethod() {
logger.info("Hello log4j Logger!");
}
public static void main(String[] args) {
new LoggingSample().someMethod();
}
}
์ฌ์ฉ์ ๊ฐ๋จํ์ง์? ์ฝ์๋ก ์ถ๋ ฅํ๋ stdout ์ธ์๋ ํ์ผ ์ถ๋ ฅ๋ ์ ๊ณตํฉ๋๋ค. ํ์ง๋ง ์ญ์๋ 2015๋ ์ ๊ฐ๋ฐ์ด ์ค๋จ๋์๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด ์์คํ ์ด ์๋๋ผ๋ฉด ์ฌ์ฉํ ์ด์ ๊ฐ ์์ต๋๋ค. ์ฌ์ค ์ค๋ซ๋์ ๊ฐ๋ฐ๋์ด์จ ์์คํ ์ด์ด๋ ๋ฐ๊ฟ ์ ์๋ ๊ธฐํ๊ฐ ์๋ค๋ฉด ๋ฐ๊พธ๋ ๊ฒ์ด ์ข๊ฒ ์ง์.
log4j๋ฅผ ์๋๋ค. logback
log4j๋ฅผ ๊ตฌํํ ๊ฐ๋ฐ์๊ฐ logback์ ๊ฐ๋ฐํ์ต๋๋ค. log4j์ ์ ์ฌํ๋ฉด์๋ ํฅ์๋ ์ฑ๋ฅ๊ณผ ํํฐ๋ง ์ต์ ์ ์ ๊ณตํ๋ฉฐ slf4j๋ ์ง์ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฐธ ํธ๋ฆฌํ ์๋ ๋ฆฌ๋ก๋๋ ๊ฐ๋ฅํฉ๋๋ค.
Maven์ผ๋ก ๊ด๋ฆฌํ๋ ํ๋ก์ ํธ์์ logback ๊ด๋ จ dependency๋ฅผ ์ถ๊ฐํ๋ ค๊ณ ํ๋ฉด logback-core์
logback-classic์ ํ์ธํ ์ ์๋๋ฐ์. core์ ๊ฒฝ์ฐ ๋ก๊น
ํ๋ ์์ํฌ๋ก์์ ํต์ฌ ๊ธฐ๋ฅ์ด ํฌํจ๋์ด ์์ต๋๋ค.
classic์ ๊ฒฝ์ฐ๋ ํต์ฌ ๊ธฐ๋ฅ์ slf4j์ ๋ํ ์ง์๊ณผ ๊ฐ์ ์ถ๊ฐ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์ฌ์ฉํ๋ ค๋ฉด ์๋์ ๊ฐ์ด dependency ์ถ๊ฐํ๋ฉด ๋ฉ๋๋ค.
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
์ค์ ์ xml๋ก ์งํํด๋ด ์๋ค. logback.xml์ ์์ฑํ๊ณ ์๋์ ๊ฐ์ด ๊ฐ๋จํ๊ฒ ์์ฑํฉ๋๋ค.
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
๊ทธ๋ฆฌ๊ณ ์คํํ ์๋ฐ ์ฝ๋๋ ์์ฑํฉ๋๋ค.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Kimtaeng
* Created on 2018. 9. 21.
*/
public class LoggingSample {
Logger logger = LoggerFactory.getLogger(LoggingSample.class);
public void someMethod() {
logger.info("Hello logback Logger!");
}
public static void main(String[] args) {
new LoggingSample().someMethod();
}
}
์ถ๋ ฅํ ๋ก๊ทธ ํฌ๋งท์ด๋ ํน์ ํจํค์ง์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ ๋ฑ ์ฐพ์๋ณด๋ฉด ๋ค์ํ logback ์ค์ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
๊ฐ์ฅ ์ต์ ์ด๋ค. log4j2
log4j2๋ ์์ ์ดํด๋ณธ log4j์ logback๊ณผ ๋น๊ตํ์ ๋ ๊ฐ์ฅ ์ต๊ทผ์ ๋ฑ์ฅํ์ต๋๋ค. logback๊ณผ ๋์ผํ๊ฒ ์๋ ๋ฆฌ๋ก๋ ๊ธฐ๋ฅ๊ณผ ํํฐ๋ง ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์ค์ ์ ์๋์ ๊ฐ์ด ์งํํ๋ฉด ๋ฉ๋๋ค. ๋จผ์ dependency๋ฅผ ์ ์ธํด์ผ ํ๊ณ ์.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.9.0</version>
</dependency>
log4j2์ ๋ํ ์ค์ ์ ๋ค์๊ณผ ๊ฐ์ด ์งํํ๋ฉด ๋ฉ๋๋ค. log4j2.xml์ ์์ฑํ๊ณ ์๋์ ๊ฐ์ด ์์ฑํฉ๋๋ค.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" >
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
์๋ฐ ์ฝ๋๋ ์๋์ ๊ฐ์ต๋๋ค. ๋ณ๊ฒฝ์ ๊ตฌ๋ถํ๊ธฐ ์ํด์ ๋ก๊ทธ๋ก ์ถ๋ ฅ๋ ๋ฉ์์ง๋ง ๋ฐ๊ฟจ์๋ฟ Logger์ ๋ํ ์ค์ ์ logback์์์ ์ค์ ๊ณผ ๋ณ๊ฒฝ๋ ๊ฒ์ด ์์ต๋๋ค. ํจํค์ง import๋ ๋์ผํ๊ณ ์.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Kimtaeng
* Created on 2018. 9. 21.
*/
public class LoggingSample {
Logger logger = LoggerFactory.getLogger(LoggingSample.class);
public void someMethod() {
logger.info("Hello log4j2 Logger!");
}
public static void main(String[] args) {
new LoggingSample().someMethod();
}
}
์์ ์ธ๊ธํ ๊ฒ์ฒ๋ผ slf4j๊ฐ ์๊ธฐ๋๋ฌธ์ logback๊ณผ log4j2๋ฅผ ๋น๊ต์ ๊ฐ๋จํ๊ฒ ์ ํํ ์ ์์ต๋๋ค. dependency ์ ์ธ๋ง ๋ณ๊ฒฝํ์๋ฟ ์ค์ ์ดํ๋ฆฌ์ผ์ด์ ์ฝ๋๋ฅผ ์์ ํ ๋ถ๋ถ์ ์์ต๋๋ค.
๊ทธ๋ผ ๋ญ๊ฐ ์ข์๊น?
log4j๋ ๊ฐ๋ฐ์ด ์ค๋จ๋์์ผ๋ฏ๋ก ๋น๊ต ๋์์์ ์ ์ธํ๋ค๋ฉด logback๊ณผ log4j2๊ฐ ๋จ์๋๋ฐ์. ๊ณผ์ฐ ์ด๋ ๋ก๊น ํ๋ ์์ํฌ๊ฐ ๋ ์ข์๊น? ๋ผ๋ ์ง๋ฌธ์ ๊ธ์ ๋ง์ด ๋ณธ ๊ฒ ๊ฐ์ต๋๋ค.
๋จ์ํ๊ฒ ๋น๊ต๋ง ํด๋ณธ๋ค๋ฉด ๊ฐ์ฅ ์ต์ (์ต์ ์ด๋ผ๊ณ ํญ์ ์ข์ ๊ฒ์ ์๋์ง๋ง)์ด์ ๋น ๋ฅด๋ฉฐ logback์ ์ํคํ ์ฒ์์ ๋ฐ์ํ๋ ๋ฌธ์ ์ ์ ์์ ํ ์ด๋ผ๊ณ Apache๊ฐ ์๊ฐํ๋ log4j2๋ฅผ ๊ถ์ฅํ ๊ฒ ๊ฐ์ต๋๋ค.
Apache์ ๋ฐ๋ฅด๋ฉด ๋ฉํฐ ์ค๋ ๋ ํ๊ฒฝ์์์ ๋น๋๊ธฐ ๋ก๊ฑฐ(Async Logger)์ ๊ฒฝ์ฐ log4j 1.x ๋ฐ logback๋ณด๋ค ๋ช ๋ฐฐ๋ ๋๋ ์ฒ๋ฆฌ๋์ ๋ณด์ธ๋ค๊ณ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋๋ค ํํ์๊ณผ ์ฌ์ฉ์ ์ ์ ๋ก๊ทธ ๋ ๋ฒจ๋ ์ง์ํ๊ณ ์.
2018๋ 9์์ ๊ธฐ์ค์ผ๋ก log4j2์ ์ต์ ๋ฒ์ ์ 7์์ Release๋ 2.11.1 ์ ๋๋ค.