Link
Today
Total
05-02 03:06
Archives
관리 메뉴

초보개발자 긍.응.성

Logback - 3. Logback의 설정 (2). configuration 파일 구성 본문

Spring/Logback

Logback - 3. Logback의 설정 (2). configuration 파일 구성

긍.응.성 2020. 10. 1. 18:52
반응형
logback

logback 홈페이지의 매뉴얼을 읽으며 내용들을 정리한 글입니다.

Configuration 파일 문법

Logback은 코드를 재 컴파일하지 않고도 logging에 대하여 재 구성할 수 있습니다. Logback의 configuration 파일은 매우 유연한 문법을 갖고 있습니다.

logback.xml file syntax diagram

기본적인 구조는 위의 사진과 같습니다. configuration 태그는 내부에 최대 1개의 root 태그를 갖고, 0개 이상의 appender와 logger 태그를 가질 수 있습니다. 태그 명명 규칙은 조금 복잡하지만 일반적으로 대소문자를 구분하며 camelCase를 따르도록 합니다.

Logger와 같이 keyword로 지정된 태그 이름은 대소문자를 구분하지 않고 선언할 수 있습니다 (logger = Logger = LOGGER). 하지만, 여는 태그와 닫는 태그에서 대소문자는 기존 xml 규칙을 따릅니다(<xyz>는 </xYz>로 닫을 수 없습니다).
- 문서에서는 CamelCase를 따라서 태그의 이름을 짓는것을 권장합니다.

<logger>, 로거 구성

Logger는 <logger> 태그를 통하여 구성됩니다. <logger>는 필수 name속성, 선택적으로 level 속성과 additivity 속성을 가집니다. level 속성은 대소문자를 구분하지 않으면 TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF 중 하나의 값으로 지정할 수 있습니다. 특별한 level 값으로는 INHERITED 또는 NULL (같다)이 존재하는데, 이는 자신이 상속하는 상위 로거의 level을 그대로 따릅니다. additivity 속성은 true와 false의 값을 가질 수 있습니다. 이는 appender의 cumulative 속성에 대하여 설정합니다.

<logger> 태그는 0개 이상의 <appender-ref> 태그를 포함할 수 있습니다. 각 <appender-ref> 태그로 포함된 appender는 명명된 로거에 추가됩니다.

<root>, 루트 로거 구성

루트 로거는 <root> 태그를 통하여 구성됩니다. 루트 로거의 속성으로는 오직 단 하나의 level 속성만 허용 됩니다. 루트 로거의 이름은 이미 "ROOT"로 정해져 있기에 name 속성도 포함하지 않습니다. level 속성으로는 기존 logger와 동일하게 level 값들을 가질 수 있습니다. 하지만, 가장 최상단의 로거이기 때문에 INHERITED 혹은 NULL 값은 level 값으로 가질 수 없습니다.

<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>

  <logger name="chapters.configuration" level="INFO" />
  <logger name="chapters.configuration.Foo" level="DEBUG" />
  
  <!-- turn OFF all logging (children can override) -->
  <root level="OFF">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

위와 같은 logback.xml 파일을 살펴봅시다. 루트 로거는 OFF 레벨로 지정되어 아무런 로그를 출력하지 않도록 지정했습니다. 하지만 하위 로거인 "chapters.configuration" 로거에서 level을 오버라이드 하여 INFO 레벨로 지정하였습니다. 그렇기 때문에 "chapters.configuration" 로거의 하위 로거들의 level은 모두 INFO 레벨로 지정되게 됩니다. "chapters.configuration.Foo" 로거는 "chapters.configuration" 로거의 하위 로거로 level을 다시 오버라이드 하고 있습니다. 그렇기에 "chapters.configuration.Foo" 로거의 하위 로거들은 무도 DEBUG 레벨을 갖게 됩니다.

Logger Name Assigned Level Effective Level
root OFF OFF
chapters.configuration INFO INFO
chapters.configuration.ExampleApp null INFO
chapters.configuration.Foo DEBUG DEBUG
chapters.configuration.Foo.Bar null DEBUG

Appender 구성

Appender는 <appender> 태그를 통하여 구성되며 name와 class 속성을 필수적으로 가져야만 합니다. name 속성은 appender의 이름을 명시하며, class 속성은 인스턴스화 시킬 appender 클래스를 명시하여야 합니다. <appender> 태그는 0개 또는 1개의 <layout> 태그와 0개 이상의 <encoder>, <filter> 태그를 가질 수 있습니다. 또한, <appender> 태그는 JavaBean으로 등록된 appender 클래스를 다수 포함할 수 있습니다. 

logback.xml appender diagram

<layout> 태그는 class 속성으로 인스턴스화 시킬 layout 클래스를 명시하여야 합니다. 마찬가지로, <encoder> 태그도 class 속성으로 인스턴스화 시킬 encoder 클래스를 명시하여야 합니다. 일반적인 경우에는 PatternLayout과 PatternLayoutEncoder 클래스가 연결되며 이러한 클래스 속성은 JoranConfigurator의 default class mapping 규칙을 따릅니다.

Parent class property name default nested class
ch.qos.logback.core.AppenderBase encoder ch.qos.logback.classic.encoder.PatternLayoutEncoder
ch.qos.logback.core.UnsynchronizedAppenderBase encoder ch.qos.logback.classic.encoder.PatternLayoutEncoder
ch.qos.logback.core.AppenderBase layout ch.qos.logback.classic.PatternLayout
ch.qos.logback.core.UnsynchronizedAppenderBase layout ch.qos.logback.classic.PatternLayout
ch.qos.logback.core.filter.EvaluatorFilter evaluator ch.qos.logback.classic.boolex.JaninoEventEvaluator
<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>myApp.log</file>

    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

위의 코드에는 FILE과 STDOUT이라는 appender를 확인할 수 있습니다. FILE appender는 myApp.log라는 파일에 로그를 출력하고 encoder로 PatternLayoutEncoder를 사용합니다. STDOUT appender는 콘솔에 로그를 출력합니다. 두 개의 appender는 <appender-ref>를 통해 로트 로거에 등록됩니다.

Appenders accumlate

기본적으로 appender는 누적되는 성질을 갖고 있습니다. logger는 자신에게 부착된 appender 이외에 자신의 상위 logger의 appender에게 로그를 전달합니다. 그렇기에 같은 appender를 다른 logger에 등록한다면 로그의 중복 출력에 주의하여야 합니다.

<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>

  <logger name="chapters.configuration">
    <appender-ref ref="STDOUT" />
  </logger>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
14:25:36.343 [main] INFO  chapters.configuration.MyApp3 - Entering application.
14:25:36.343 [main] INFO  chapters.configuration.MyApp3 - Entering application.
14:25:36.359 [main] DEBUG chapters.configuration.Foo - Did it again!
14:25:36.359 [main] DEBUG chapters.configuration.Foo - Did it again!
14:25:36.359 [main] INFO  chapters.configuration.MyApp3 - Exiting application.
14:25:36.359 [main] INFO  chapters.configuration.MyApp3 - Exiting application.

앞서 logger에는 additivity 속성이 존재한다고 말씀드렸습니다. 이 속성은 appender accumlate를 컨트롤하기 위한 속성입니다. "additivity=false"로 설정된 경우 로깅이 발생할 때 상위 로거의 appender로 전달되지 않습니다. 아래와 같은 경우는 "chapters.configuration.Foo" 로거에서 발생한 로그는 루트 로거로 전달되지 않기에 오직 foo.log 파일에만 출력됩니다.

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>foo.log</file>
    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file : %line] %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration.Foo" additivity="false"> <!-- 상위 로거로 전달 방지 -->
    <appender-ref ref="FILE" />
  </logger>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

Context Name 설정

모든 로거는 LoggerContext에 부착됩니다. 그리고 이 LoggerContext 기본 이름은 "default"입니다. 만약 LoggetContext의 이름을 다르게 지정하고 싶다면 <contextName> 태그를 이용하여 지정해줄 수 있습니다. LoggerContext의 이름은 하나의 target에 대하여 다수의 Application 로그를 수집할 때 Application 구분을 위해 사용될 수 있습니다. 그렇기에 이름을 수정한다면 간단하고 명확한 이름으로 명명하는 것을 권장드립니다.

<configuration>
  <contextName>myAppName</contextName>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d %contextName [%t] %level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

 LoggerContext 이름을 출력하기 위해 %contextName을 사용합니다.

변수 선언 및 치환 (Variable substitution)

configuration 파일에 변수를 선언하고 이를 태그 구성에 사용할 수 있습니다. 사용할 수 있는 정의된 변수들이 많이 존재하지만, 일반적인 변수를 선언하고 이를 설정에 치환하는 방법만 정리하도록 하겠습니다. 추가적인 변수 사용 방법은 Logback manual: Variable substitution를 참고하시길 바랍니다.

변수는 <property> 태그를 이용하여 선언 가능합니다. logback 1.0.7 이후로는 <property> 대신 <variable>이라는 이름으로 키워드가 대체되었지만 현재 둘 다 태그명으로 사용 가능합니다.

선언한 변수 ${variable_name}으로 사용할 수 있습니다. ${ 과 } 사이에 선언한 문자열은 같은 이름의 변수 값으로 치환됩니다.

<configuration>

  <property name="USER_HOME" value="/home/changwoo" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${USER_HOME}/myApp.log</file>
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
  </root>
</configuration>

위의 코드를 봅시다. <property> 태그를 이용하여 "USER_HOME"이라는 변수에 "/home/changwoo"값을 넣어주었습니다. FILE appender에서 <file> 태그에 ${USER_HOME}/myApp.log의 값을 전달하였습니다. 이때 ${ 과 } 사이 선언된 문자열 USER_HOME이 같은 이름의 변수의 값으로 치환되어 "/home/changwoo/myApp.log" 파일에 로그가 쌓이게 됩니다.

변수는 <property> 태그 대신 시스템 변수로써 전달하여도 위의 configuration과 동일하게 설정할 수 있습니다.

java -DUSER_HOME="/home/changwoo" MyApp
반응형
Comments