'logback'에 해당하는 글 4건

Logback 구성 파일을 사용하면 코드를 다시 컴파일 할 필요없이 logging 동작을 재정의 할 수도 있다.

구성 파일에 로그를 어떤 형태로 어디에 남길 것인지에 대한 계획도 명시할 수 있으며, 프로그래밍 방식이나 XML, Groovy 형식으로도 작성할 수 있다.

Logback 웹사이트에서 기존 log4j 사용자를 위한 PropertiesTranslator 도 제공한다. (log4j.properties -> logback.xml)



Logback 의 구성 파일 검색 순서


  1. classpath 에서 logback-test.xml 파일 검색.
  2. 없으면 logback.groovy 파일 검색.
  3. 없으면 logback.xml 파일 검색.
  4. 없으면 BasicConfigurator 를 사용하여 logback 을 가장 기본적으로 구성하고, console 로 logging 출력.


src/main/resources 디렉토리에 logback.xml, src/test/resources 디렉토리에 logback-test.xml 파일을 두어 운영/개발에 대한 구성을 분리하여 사용할 수 있다.

구성 파일이 없어서 BasicConfigurator 를 사용하게 되면, root logger 는 DEBUG 레벨이 할당되고 아래의 형식을 가진다.


%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n


// console :

16:06:09.031 [main] INFO  chapters.configuration.MyApp1 - Entering application.

16:06:09.046 [main] DEBUG chapters.configuration.Foo - Did it again!

16:06:09.046 [main] INFO  chapters.configuration.MyApp1 - Exiting application.



logback.xml 구성


아래 코드는 BasicConfigurator 로 기본 설정된 것을 logback-test.xml 이나 logback.xml 파일로 자체 구성한 것이다.


<configuration>
 
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
        <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>
cs


이것이 구성 파일을 찾지 못했을 때 적용되는 기본 구성이다.

위 기본 파일 처럼, 구성 파일의 기본적인 구조는 <configuration> 안에 <appender>, <logger>, <root> 순으로 나열하는 것이다.


<appender> 는 name, class 속성을 필수로 지정해야 하며, 선택적으로 하나 이상의 <layout>, <encoder>, <filter> 를 포함할 수 있다.

logback 0.9.19 부터 FileAppender와 하위 클래스는 <encoder> 를 필요로 하고 더 이상 <layout> 을 사용하지 않는다.

<encoder> 는 class 속성을 지정하지 않으면 PatternLayoutEncoder 클래스가 적용된다.

<logger> 는 root 로거와 레벨이나 appender 가 다를 경우 패키지명과 함께 설정한다.

<root> 는 appender 를 참조하여 root 로거에 첨부한다.


아래는 로그를 console 과 file 로 전달하는, 보편적(?)인 logback.xml 스트립트이다.


<?xml version="1.0" encoding="UTF-8"?>
 
<!-- 구성 파일을 수정하였을 때, logback-classic 이 변경 사항을 자동으로 반영하게 한다. -->
<!-- scanPeriod 값의 단위는 milliseconds (default), seconds, minutes, hours 단위로 입력할 수 있다. -->
<!-- StatusPrinter 클래스의 print() 메소드를 호출한 것과 동일하게 logback 의 내부 상태 출력 -->
<configuration scan="true" scanPeriod="30 seconds" debug="true">
 
    <!-- property 요소로 변수를 사용할 수 있다. (아래의 logDir 이나 HOSTNAME 등) -->
    <property resource="resource.properties"/>
 
    <!-- ConsoleAppender 는 거의 이 형식을 벗어나지 않는다. pattern 만 적절히 수정한다. -->
    <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>
 
    <!-- RollingFileAppender 는 FileAppender 를 확장한 것으로 파일을 특정 조건에 맞게 로테이션 시키는데 유용하다. -->
    <!-- 아래의 로테이션 정책은 30일이 넘거나 총 파일 크기가 3GB 를 넘기면 오래된 순으로 삭제된다. -->
    <appender name="FILEOUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${logDir}/logFile.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
 
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
        </encoder>
    </appender>
 
    <!-- 아래 logger 들로 특정 라이브러리들에 대한 logger 레벨과 appender 를 지정할 수 있다. -->
    <!-- 여기 지정된 logger 레벨은 root 레벨보다 우선한다. -->
 
    <!-- Hibernate Loggers -->
    <logger name="org.hibernate" level="ERROR">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILEOUT"/>
    </logger>
 
    <!-- springframework -->
    <logger name="org.springframework" level="ERROR">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILEOUT"/>
    </logger>
 
    <!-- ibatis and mybatis spring -->
    <logger name="org.apache.ibatis" level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILEOUT"/>
    </logger>
    <logger name="org.mybatis.spring" level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILEOUT"/>
    </logger>
 
    <!-- if, then, else 구문을 사용하여 서버 환경에 따른 스크립트를 하나의 파일에 동시에 설정할 수 있다. -->
    <!-- 아래는 root 레벨만 조정하였지만, appender-ref 를 변경할 수도 있다. -->
    <if condition='property("HOSTNAME").contains("prod")'>
        <then>
            <root level="info">
                <appender-ref ref="STDOUT"/>
                <appender-ref ref="FILEOUT"/>
            </root>
        </then>
        <else>
            <root level="debug">
                <appender-ref ref="STDOUT"/>
                <appender-ref ref="FILEOUT"/>
            </root>
        </else>
    </if>
</configuration>
cs


구성 파일을 구문 분석하는 동안 경고 또는 오류가 발생하면 Logback 은 내부 상태 데이터를 자동으로 콘솔에 출력한다.

구성 파일의 configuration 요소에 debug="true" 를 설정하면, 오류가 없는 경우에도 구성 파일에 상태 데이터를 출력할 수 있다.

이것은 코드에 StatusPrinter.print() 메소드를 사용한 것과 같은 결과로 나타난다.

또한 설정 파일의 statusListener 요소에 OnConsoleStatusListener 클래스를 설정하는 것과도 같다.





WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

트랙백  0 , 댓글  0개가 달렸습니다.
secret

Logback 은 Logger, Appender, Layout 의 세 가지 기본 클래스를 기반으로 한다.

이를 사용하여 개발자는 메시지 유형 및 수준에 따라 메시지를 기록하고 런타임에 이러한 메시지의 형식과 보고 위치를 설정할 수 있다.

Logger 클래스는 logback-classic 모듈에 속하고, Appender 및 Layout 인터페이스는 logback-core 에 속하기 때문에, logback-core 에는 logger 의 개념이 없다.



Logger Class


Logger 의 레벨인 TRACE, DEBUG, INFO, WARN, ERROR 는 ch.qos.logback.classic.Level 클래스에 정의된다.

Logger 레벨을 지정하지 않으면 상위 클래스에서 상속받게 되고, default 레벨은 DEBUG 이다.

레벨은 아래와 같으며, 지정된 레벨 이하의 메소드 호출은 기록되지 않는다.


TRACE < DEBUG < INFO < WARN < ERROR



Appenders Class


Appender 는 로그 출력 대상(목적지) 을 설정할 수 있다.

현재 Appender 대상은 console, files, Syslog, TCP Sockets, JMS, DB, JMS 및 원격 UNIX Syslog 데몬이 될 수 있다.



Layouts Class


Appender 와 관련하여 출력 형식을 사용자 정의 하는 것이 Layout 이다.

PatternLayout 을 사용하면 C 언어 printf 함수와 비슷한 변환 패턴에 따라 출력 형식을 지정할 수 있다.

예를 들어 "%-4relative [%thread] %-5level %logger{32} - %msg%n" 같은 패턴을 가진 PatternLayout 의 결과는 다음과 같다.


176  [main] DEBUG manual.architecture.HelloWorld2 - Hello world.
cs



Logging 파라미터


logger.debug("The new entry is "+entry+".");
logger.debug("The new entry is {}.", entry);
cs


위 debug 메소드의 결과는 같지만, 두 번째 debug 메소드가 첫 번째 debug 메소드 형식보다 성능면에서 30배 이상 좋다. 

파라미터 수 만큼 해당 자리에 {} 를 나열하고 이어서 콤마로 구분하여 파라미터를 나열하면 된다.


logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);
cs


배열도 사용 가능하다.


Object[] paramArray = {newVal, below, above};
logger.debug("Value {} was inserted between {} and {}.", paramArray);
cs



내부 동작


사용자가 info() 메소드를 호출할 때 Logback 처리 과정은 다음과 같다.


  1. 필터 체인
    로깅 요청시 TurboFilter 가 존재할 경우 호출되어, 특정 이벤트를 필터링 하여 다음의 응답과 함께 단계 이동한다.
    FilterReply.DENY 이면 Logging 요청 삭제, NEUTRAL 인 경우 2 단계 진행, ACCEPT 인 경우 3 단계 진행.

  2. 기본 선택 규칙 적용
    요청 레벨과 logger 레벨을 비교하여, 사용할 수 없으면 요청을 삭제하고 그렇지 않으면 다음 단계로 진행.

  3. LoggingEvent 객체 생성
    logger, level, message 같은 요청의 모든 파라미터를 포함하는 ch.qos.logback.classic.LoggingEvent 객체를 생성.

  4. Appenders 호출
    LoggingEvent 객체를 만든 후 AppenderBase 의 doAppend() 메소드를 호출하여, 사용자 정의 필터가 있는 경우 해당 필터를 호출.

  5. 출력 형식화 (Layout)
    appender 를 통해, LoggingEvent 인스턴스를 형식화하고 결과를 문자열로 반환.

  6. LoggingEvent 목적지로 보내기
    로깅 이벤트가 완전히 형식화된 후, 각 appender 에 의해 목적지로 전송.




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

트랙백  0 , 댓글  0개가 달렸습니다.
secret

log4j 를 만든 Ceki Gülcü 는 log4j 를 포함한 다른 logging 시스템들 보다 더 가볍고 빠르게 동작하는 Logback 을 개발하였다.

log4j 와 logback 은 개념적으로 매우 유사하고, log4j 를 사용했던 사용자라면 logback 역시 쉽게 다가갈 수 있다.

System.out.println 와 비교하자면 빠르고, 레벨, 환경 등에 따라 출력 여부를 표시할 수 있다는 점?



Logback 모듈


Logback 은 logback-core, logback-classic, logback-access 세 가지 모듈로 나뉜다.


  • logback-classic 은 log4j 의 향상된 버전에 해당하며, SLF4J API를 기본적으로 구현하여 log4j 이나 JUL 과 같은 다른 로깅 시스템과 쉽게 전환이 가능하다.
  • logback-access 는 Servlet 컨테이너와 통합되어 HTTP 액세스 로그 기능을 제공한다.
  • logback-core 은 위 두 모듈의 기반이 되며, logback 은 이 모듈의 일부인 Joran 이라는 구성 라이브러리에 의존한다. 



Logback 특징


  • logback-classic 모듈의 Logger 클래스가 SLF4J API 를 기본적으로 구현하므로 SLF4J 로거를 호출 할 때 오버 헤드가 발생하지 않는다. 
  • logback-classic 은 설정 파일이 수정되면 자동으로 reload 할 수 있다. 
  • FileAppender 를 비롯한 하위 클래스는 I/O 오류를 정상적으로 복구할 수 있다.
  • 아카이브 된 로그 파일을 자동으로 비동기 압축하며, maxHistory 프로퍼티를 설정하여 오래된 아카이브 로그 파일을 자동으로 삭제할 수 있다.
  • Prudent 모드로 여러 FileAppender 인스턴스로부터 동일한 로그 파일에 안전하게 기록할 수 있다.
  • development, testing, production 같은 다른 환경에 대하여 구성 파일을 중복 구성할 필요없이, 단일 구성 파일에서 조건부 처리를 사용할 수 있다.
    (조건부 처리시 Janino 라이브러리 필요)
  • MDCFilter 를 사용하여 특정 사용자에 대한 Logging Level 지정이 가능하다.
  • SiftingAppender 는 사용자 세션에 따라 로그 파일을 분리할 수 있다.
  • logback 이 exception 을 출력할 때, stack trace 에서 exception 에 개입하는 클래스, 패키지, 패키지 버전을 알 수 있다.
  • logback-Access 모듈은 Jetty, Tomcat 같은 Servlet 컨테이너와 통합되어 풍부하고 강력한 HTTP 액세스 로그 기능을 제공한다.



Logback 요구사항


logback-classic 모듈을 사용하려면, classpath 에 logback-classic.jar 외에도 slf4j-api.jar 와 logback-core.jar 파일이 있어야 한다.

maven 이나 gradle 같은 빌드 툴을 사용할 때는, logback-classic 모듈만 가져오면 slf4j-api.jar, logback-core.jar 파일도 딸려온다.


gradle 예)


dependencies {
    // logback-classic (slf4j-api, logback-core 포함)
    compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
}
cs



Logback 구현


package chapters.introduction;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class HelloWorld1 {
 
    public static void main(String[] args) {
 
        Logger logger = LoggerFactory.getLogger("chapters.introduction.HelloWorld1");
        logger.debug("Hello world.");  // 20:49:07.962 [main] DEBUG chapters.introduction.HelloWorld1 - Hello world.
 
    }
}
cs


"Hello world." 라는 debug 레벨의 로그를 출력하는 예제이다.

SLF4J API 에 정의된 Logger 와 LoggerFactory 를 import 하고, Logger 인스턴스를 생성해서 사용했다.

이 예제처럼, Logging 이 필요한 대부분의 경우 logback 클래스를 참조하지 않고 SLF4J API 만으로 구현해야 한다.


만약 logback 수명주기 동안의 로그가 필요하다면 StatusManager 라는 컴포넌트를 이용할 수 있으며, Logback 관련 문제 진단에 매우 유용할 수 있다.

StatusPrinter 클래스의 print() 메소드를 호출하여 logback 의 내부 상태를 출력할 수 있다.


import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.util.StatusPrinter;
 
...
 
// print internal state
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
StatusPrinter.print(lc);
 
/*
12:49:22.203 [main] DEBUG chapters.introduction.HelloWorld2 - Hello world.
12:49:22,076 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
12:49:22,078 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
12:49:22,093 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.xml]
12:49:22,093 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Setting up default configuration.
*/
cs


위 로그에서 logback 이 구성 파일을 찾지 못하여 기본 정책(ConsoleAppender) 으로 구성되었음을 알 수 있다.

Appender 는 로그를 남길 목적지로, console, files, Syslog, TCP Sockets, JMS 등 다양하게 설정할 수 있다.

에러가 발생하면 logback은 자동으로 내부 상태를 콘솔에 출력한다.



Logback 사용 정리


  1. logback.xml 이나 logback.groovy 같은 구성 설정.
  2. Logging 이 필요한 모든 클래스에 org.slf4j.Logger 인스턴스 생성.
  3. debug(), info(), warn() 및 error() 등 적절한 출력 메소드 호출로 구성된 appender 에 Logging.




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

트랙백  0 , 댓글  0개가 달렸습니다.
secret

개발자들은 어플리케이션의 중심부에 통합 로깅을 구성하여, 개발시 문제점 추적이나 필요한 부분을 모니터링 하려고 할 것이다.

System.out.println() 을 열심히 붙여 넣으면 로깅이 가능하다.

조금더 진보적인 방법으로는 Logging Framework 를 사용하는 방법이 있다.


Logging Framework 의 종류는 매우 많겠지만, 대부분 사용하는 것은 정해져 있는 듯 하다.

JUL, Log4j, Logback 정도...


Spring Framework 은 기본적으로 spring-core 모듈이 JCL(Jakarta Commons Logging) API 에 의존성을 가지고 있다.

commons-logging 의 역할은 지정된 클래스패스에서 다른 Logging Framework 를 찾아 동일한 API 로 로깅을 구현할 수 있게 한다.

예를 들면 Log4j 같은 Logging Framework 와 연동시켜 logging 을 가능하게 한다.

사용 가능한 Logging Framework 가 없다면 JDK 의 JUL(java.util.logging) 을 기본으로 사용한다.


문제는 commons-logging 이 slf4j 에 비해 비효율적이라는데 있다.

slf4j 는 commons-logging 처럼 다른 Logging Framework 를 찾는 작업을 런타임시 하지 않고, 컴파일 시점에 바인딩하기 때문에 더 효율적이다.

이러한 효율성이 얼마나 체감 가능한지는 모르겠지만 아무튼 그러한 이유로 slf4j 를 많이 사용한다고 한다.

Log4j 도 런타임 오버헤드와 코드 사이즈가 증가하는 단점으로 인해, slf4j API 를 구현하는 Logback 을 주로 사용한다.

JUL, JCL, Log4j 등을 호출하는 외부 라이브러리 이용시에는 slf4j 의 extend 라이브러리(jcl-over-slf4j 등) 를 사용하면 slf4j 로 통합된다.


정리하자면, commons-logging 이나 slf4j 같은 Logging API 를 사용하는 이유는,

JUL 이든 Log4j 든 Logback 이든 개발 도중 Logging Framework 가 바껴도 Logging 에 관련된 코드를 수정할 필요가 없도록 하기 위해서이다.

slf4j + logback 인 logging 을 위해 dependancy 에 추가할 것은 세가지 정도가 되겠다.


  1. slf4j Logging API
  2. logback Logging Framework
  3. Binding to slf4j : jul-over-slf4j / jcl-over-slf4j / log4j-over-slf4j / ... 


Gradle 을 예로 들면, 다음과 같은 형태가 되겠다.


dependencies {
    // logback-classic (slf4j-api, logback-core 포함)
    compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'
    compile group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.25'
    compile group: 'org.slf4j', name: 'log4j-over-slf4j', version: '1.7.25'
}
cs


마지막으로 resources 디렉토리에 적당한 logback.xml 나 logback.groovy 파일을 생성/설정한다. ^^




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

트랙백  0 , 댓글  0개가 달렸습니다.
secret