# 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์ด ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•  ๋•Œ, ํด๋ž˜์ŠคํŒŒ์ผ์„ ์ฐพ๋Š” ๋ฐ ๊ธฐ์ค€์ด ๋˜๋Š” ํŒŒ์ผ ๊ฒฝ๋กœ

# ์„ค์ •ํŒŒ์ผ์˜ ํ•ญ๋ชฉ

  1. Level : ์•„๋ž˜์™€ ๊ฐ™์€ ์ˆœ์„œ๋Œ€๋กœ ๋†’์€ ๋ ˆ๋ฒจ์ด๋ฉฐ, ์ถœ๋ ฅ ๋ ˆ๋ฒจ์˜ ์„ค์ •์— ๋”ฐ๋ผ ์„ค์ • ๋ ˆ๋ฒจ ์ด์ƒ์˜ ๋กœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

    • ERROR
    • WARN
    • INFO
    • DEBUG
    • TRACE

    ex) ์ถœ๋ ฅ๋ ˆ๋ฒจ์„ INFO๋กœ ์„ค์ •ํ•˜๋ฉด, DEBUG, TRACE ๋ ˆ๋ฒจ์˜ ๋กœ๊ทธ๋Š” ์ถœ๋ ฅ๋˜์ง€ ์•Š๋Š”๋‹ค.

  2. 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) ๋“ฑ

  3. 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/
Last Updated: 6/18/2023, 2:13:15 PM