몰입하며 나아가는 개발이란

Framework

Logback 이란?

류하을 2022. 3. 29. 10:00

Logback

Logback이란?

Logback은 Java에서 가장 많이 사용 되었던 로깅 라이브러리인 log4j의 후속버전이며, log4j를 설계한 Ceki Gulgu에 의해 설계되었습니다.

logback은 새롭게 작성된 logger가 아니라, 오랫동안 검증된 "log4j"의 아키텍쳐 기반으로 재작성 되었으며, 또한 "SLF4J"를 지원하기 때문에 마음에 들지 않으면 언제든지 다른 로거로 스위칭이 가능하게 구현되어있습니다.

특징 및 장점(log4j 대비)

-Logback에 SiftingAppender는 Filter의 기능화 유사하면서 다른 기능을 제공합니다. 로그파일을 특정 주제별로 분류 하며, HTTP Session별로 파일을 저장한다거나 사용자별로 별도의 로그파일을 저장 할 수 있게 해줍니다.

-Logback은 Exception 발생시 참조했던 외부 라이브러리 버전까지 출력해줍니다.

-Logback은 별도의 삭제 스케줄러 설정및 개발이 필요없이 maxHistory라는 설정을 통해 주기적으로 Archive 파일을 자동 삭제 하는 기능이있습니다.

-Logback은 어플리케이션을 중지 시켰다가 재가동하더라도 서버 중지 없이, 이전 시점부터 복구를 지원합니다.

-Logback은 로그 레벨 변경시 내부 스캐닝하는 별도의 쓰레드가 있어 서버 재기동을 할 필요가 없습니다.

현재 Java에서 사용되는 Logging 라이브러리 비교

로그라이브러리

현재 java에서 주로 사용되는 Logging 라이브러리는 Log4j, Logback, Log4j2를 주로 사용하며, 개발된 순서또한 Log4j, Logback, Log4j2 와 같다. 현재 Log4j는 2015년 8월 5일 기준으로 프로젝트 진행 종료가 된 상태이며, Log4j2로 업그레이드 하는것을 권고하고있다. 위 사진처럼 멀티쓰레드시 18배 이상의 성능차이가 나게되므로 프로젝트 성격에 따라 맞는 Logging 라이브러리를 선택하면된다. Spring Boot의 경우 Logback 라이브러리가 기본적으로 포함되어있다.

로그 레벨 순서 및 작성 방법

  • 로그 Level

    1. ERROR: 요청을 처리하는 중 오류가 발생한 경우 표시한다.
    2. WARN: 처리 가능한 문제, 향후 시스템 에러의 원인이 될 수 있는 경고성 메세지를 나타낸다.
    3. INFO: 상태변경과 같은 정보성 로그를 표시한다.
    4. DEBUG: 프로그램을 디버깅하기 위한 정보를 표시한다.
    5. TRACE: 추적 레벨은 Debug보다 훨씬 상세한 정보를 나타낸다.

로그에 설정할 수 있는 레벨은 총 5가지이며, ERROR - WARN - INFO - DEBUG - TRACE 순으로 높은 레벨을 나타낸다. 또한 출력레벨의 설정에 따라 설정 레벨 이상의 로그를 출력한다.

ex) 로깅 레벨 설정을 "INFO"로 하였을경우 "TRACE", "DEBUG" 레벨의 로그는 출력되지 않는다.

  • 로그 작성 Pattern

    • %logger{length} : Logger name을 축약 할 수 있다. {length}는 최대 글자 수 ex)logger{35}

    • %-5level : 로그 레벨, -5는 출력의 고정폭 값(5글자)

    • %msg : - 로그 메세지(=%message)

    • ${PID:-} : 프로세스 아이디

    • %d : 로그 기록시간

    • %p : 로깅 레벨

    • %F : 로깅이 발생한 프로그램 파일명

    • %M : 로깅일 발생한 메소드의 명

    • %I : 로깅이 발생한 호출지의 정보

    • %L : 로깅이 발생한 호출지의 라인 수

    • %thread : 현재 Thread 명

    • %t : 로깅이 발생한 Threrad명

    • %c : 로깅이 발생한 카테고리

    • %C : 로깅이 발생한 클래스 명

    • %m : 로그 메세지

    • %n : 줄바꿈

    • %% : %를 출력

    • %r : 애플리케이션 시작 이후 부터 로깅이 발생한 시점 까지의 시간(ms)

Spring Boot 설정방법

src/main/resources/application.properties에 출력레벨 설정

logging.level.root={level}

logging.level.com.gochigo.admin.test={level}
logging.level.com.gochigo.admin.test.controller={level}

logging.level.root=는 전체 level 설정

logging.level.com.gochigo.admin.test.controller=는 특정 패키지 또는 컨트롤러 별 level설정

{level}은 상단에 5가지 레벨을 참고하여 작성하되, 실운영 환경에서는 보통 INFO 레벨로 설정하여 사용하고 필요여부에 따라 실시간으로 DEBUG 레벨로 조정하기도 한다.

src/main/resources/logback-spring.xml 생성 및 설정

스프링 부트의 경우 logback.xml이라는 이름으로 이미 스프링부트가 설정되기 전에 관련 logback 설정을 하기때문에 logback.xml 대신 logback_spring.xml을 사용한다.

logback-spring.xml은 appenderlogger 크게 두개로 구분 된다.

appender는 log의 형태를 설정하고, logger는 설정한 appender를 참조하여 package와 level을 설정한다.

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">

    <!-- 속성 또는 변수 설정 -->
    <property resource="application.properties"/>
    <property name="${name}" value="${value}"/>

    <!-- application.properties 설정값을 가져올때 사용 -->
    <springProperty name="${name}" source="spring.datasource.driverClassName"/>
    <springProperty scope="context" name="${name}" source="logging.level.root"/>

    <!-- 어떤 속성의 appender를 사용할지 클레스 및 이름 설정 -->
    <appender name="${name}" class="${appender class}">
        <!-- 각 append class에 맞는 설정값이 다름.
             ch.qos.logback.core.ConsoleAppender,
            ch.qos.logback.core.FileAppender,
            ch.qos.logback.core.rolling.RollingFileAppender,
            ch.qos.logback.classic.db.DBAppender,
            ch.qos.logback.classic.net.SMTPAppender 등
        -->
    </appender>

    <!-- 전체 로그 출력설정 -->
    <root level="${proerty}">
        <appender-ref ref="${appender}"/>
        <appender-ref ref="${appender}"/>
        <appender-ref ref="${appender}"/>
    </root>

    <!-- 패키지 별 로그 출력설정 -->
    <logger name="org.hibernate" level="debug">
        <appender-ref ref="${appender}"/>
        <appender-ref ref="${appender}"/>
    </logger>
    <!-- 해당 패키지 하위 로그를 출력하고 싶지 않을때 additivity="false" -->
    <logger name="org.springframework" level="debug" additivity="false">
        <appender-ref ref="${appender}"/>
        <appender-ref ref="${appender}"/>
    </logger>

</configuration>

위와 같이 logback-spring.xml을 작성해야한다.

appender class종류 및 설정방법

https://logback.qos.ch/manual/appenders.html 를 참고하여 원하는 퍼포먼스에 맞춰 logback-spring.xml을 작성하는것이 좋다. 아래는 appender 종류별 간단한 작성방법만 소개한다.

  • ch.qos.logback.core.ConsoleAppender : 콘솔에 로그를 출력한다. 로그를 OutputStream에 작성하여 콘솔에 출력되도록 한다.

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%level] [%logger] : %msg%n</pattern>
        </encoder>
    </appender>
  • ch.qos.logback.core.FileAppender : 파일에 로그를 저장한다. 최대 보관 일 수 등를 지정할 수 있다.

    <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
    
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>log-${bySecond}.txt</file>
        <append>true</append>
        <!-- set immediateFlush to false for much higher logging throughput -->
        <immediateFlush>true</immediateFlush>
        <!-- encoders are assigned the type
             ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
        </encoder>
    </appender>
  • ch.qos.logback.core.rolling.RollingFileAppender : 여러개의 파일을 롤링, 순회하면서 로그를 찍는다.(FileAppender를 상속 받는다. 지정 용량이 넘어간 Log File을 넘버링 하여 나누어 저장할 수 있다.)

    RollingFileAppender 는 작성해야할 설정이 많기 때문에 해당 링크를 참고 하여 작성하는것이 좋다. https://logback.qos.ch/manual/appenders.html

  • ch.qos.logback.classic.net.SMTPAppender : 로그를 메일로 보낸다.

    <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
        <smtpHost>ADDRESS-OF-YOUR-SMTP-HOST</smtpHost>
        <to>EMAIL-DESTINATION</to>
        <to>ANOTHER_EMAIL_DESTINATION</to> <!-- additional destinations are possible -->
        <from>SENDER-EMAIL</from>
        <subject>TESTING: %logger{20} - %m</subject>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%date %-5level %logger{35} - %message%n</pattern>
        </layout>       
    </appender>
  • ch.qos.logback.classic.db.DBAppender : DB(데이터베이스)에 로그를 쌓는다.

    <property resource="application.properties" />
    <springProperty name="spring.datasource.driverClassName" source="spring.datasource.driverClassName"/>
    <springProperty name="spring.datasource.url" source="spring.datasource.url"/>
    <springProperty name="spring.datasource.username" source="spring.datasource.username"/>
    <springProperty name="spring.datasource.password" source="spring.datasource.password"/>
    
    <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
        <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
            <driverClass>${spring.datasource.driverClassName}</driverClass>
            <url>${spring.datasource.url}</url>
            <user>${spring.datasource.username}</user>
            <password>${spring.datasource.password}</password>
        </connectionSource>
    </appender>

DBAppender 사용시 DB 필요한 Table

Logback에서 DBAppender는 독립적인 형식으로 logging_event, logging_event_property, logging_event_exception 세 개의 데이터 베이스 테이블을 insert 하므로 DBAppender를 사용하기 전에 먼저 테이블을 생성해야합니다.

DROP TABLE IF EXISTS logging_event_property;
DROP TABLE IF EXISTS logging_event_exception;
DROP TABLE IF EXISTS logging_event;

CREATE TABLE logging_event
(
    timestmp         BIGINT NOT NULL,
    formatted_message  TEXT NOT NULL,
    logger_name       VARCHAR(254) NOT NULL,
    level_string      VARCHAR(254) NOT NULL,
    thread_name       VARCHAR(254),
    reference_flag    SMALLINT,
    arg0              VARCHAR(254),
    arg1              VARCHAR(254),
    arg2              VARCHAR(254),
    arg3              VARCHAR(254),
    caller_filename   VARCHAR(254) NOT NULL,
    caller_class      VARCHAR(254) NOT NULL,
    caller_method     VARCHAR(254) NOT NULL,
    caller_line       CHAR(4) NOT NULL,
    event_id          BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
);

CREATE TABLE logging_event_property
(
    event_id          BIGINT NOT NULL,
    mapped_key        VARCHAR(254) NOT NULL,
    mapped_value      TEXT,
    PRIMARY KEY(event_id, mapped_key),
    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
);

CREATE TABLE logging_event_exception
(
    event_id         BIGINT NOT NULL,
    i                SMALLINT NOT NULL,
    trace_line       VARCHAR(254) NOT NULL,
    PRIMARY KEY(event_id, i),
    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
);

DBAppender와 테이블을 생성했다면 해당테이블에 로그가 자동으로 insert 됩니다.

'Framework' 카테고리의 다른 글

Spring Security  (0) 2022.04.04
JNA(Java Native Access)란?  (0) 2022.03.31
Javadoc 작성방법  (0) 2022.03.30
Javadoc이란? Javadoc 사용방법  (0) 2022.03.28