Etc

logback 로그 설정 메모 — 시간·용량 기준 분할과 Flume 로그 수집

목차

같은 날 올렸던 logback 관련 메모 두 개를 합쳤다. 한쪽은 애플리케이션 로그를 어떻게 자를지, 다른 쪽은 그 로그를 어떻게 한곳에 모을지다.

시간 + 용량 기준으로 파일 분할

날짜가 바뀌거나 용량이 100메가를 넘어가면 파일이 분리되는 설정이다. 둘 중 하나만 거는 경우가 많은데, 같이 걸 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<appender name="debug" class="ch.qos.logback.core.rolling.RollingFileAppender">   
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>DEBUG</level>
    </filter>
    <prudent>false</prudent>
    <file>/logs/debug.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>/logs/old/debug.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
          <maxFileSize>100mb</maxFileSize>
        </timeBasedFileNamingAndTriggeringPolicy>
        <maxHistory>30</maxHistory> 
    </rollingPolicy>
    <encoder>
        <pattern>[%-5level] %d{HH:mm:ss.SSS} %logger{36} - %msg%n</pattern>
    </encoder>
</appender>
  • <maxFileSize /> 는 분할할 용량이다 (kb, gb 도 된다)
  • <maxHistory /> 는 30일 지난 로그를 오래된 순서대로 지워준다

핵심은 SizeAndTimeBasedFNATP 다. TimeBasedRollingPolicy 안에 이걸 넣어야 날짜와 용량이 같이 걸린다. 파일명 패턴에 %i 가 들어가는 것도 이것 때문이다. 같은 날 안에서 용량으로 몇 번 더 잘릴 수 있으니 인덱스가 필요하다.

<maxHistory /> 를 안 걸면 디스크가 찬다. 서버에서 제일 흔한 사고다.

Flume 의 기본 로그를 log4j 에서 logback 으로

설치

  1. http://logback.qos.ch/download.html 에서 logback 을 받는다 (당시 v1.1.3)
  2. 압축을 풀고 logback-classic-1.1.3.jar, logback-core-1.1.3.jar$FLUME_HOME/lib 에 복사해 넣는다
  3. 기존 log4j 는 ./lib/slf4j-log4j12-1.6.1.jar./lib/slf4j-log4j12-1.6.1.jar.back 으로 이름을 바꾼다. log4j 를 지우는 건 선택사항이다. 놔두면 둘 다 기록한다
  4. logback.xml 을 만들어 $FLUME_HOME/conf/logback.xml 에 넣는다

logback.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

	<!-- Appenders -->
	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">    
      	<encoder>
        	<pattern>[%-5level] %d{HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n</pattern>
       	</encoder>
    </appender>
    <appender name="daily" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <prudent>false</prudent>
        <file>./logs/flume1.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>./logs/old/flume1.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100mb</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>[%-5level] %d{HH:mm:ss.SSS} %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="event" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <prudent>false</prudent>
        <file>./logs/collect.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>./logs/old/collect.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100mb</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>

	<logger name="kimpaper" level="debug">
        <appender-ref ref="event" />
	</logger>

    <!-- 3rdparty Loggers -->
	<logger name="org.apache.flume.lifecycle" level="info">
	</logger>
	<logger name="org.jboss" level="warn">
	</logger>
	<logger name="org.mortbay" level="info">
	</logger>
	<logger name="org.apache.avro.ipc.NettyTransceiver" level="warn">
	</logger>
	
	<logger name="org.apache.hadoop" level="info">
	</logger>
	<logger name="org.apache.hadoop.hive" level="error">
	</logger>
	
	
	<!-- Root Logger -->
	<root level="info">
		<appender-ref ref="console" />
		<appender-ref ref="daily" />
	</root>
	
</configuration>

appender 가 두 개인 게 포인트다. daily 는 Flume 자체 로그, event 는 수집한 이벤트다. kimpaper logger 만 event 로 보내서 수집 데이터와 Flume 동작 로그가 섞이지 않게 했다.

수집 sink 직접 만들기

마스터 서버에서 로그를 모아 저장하는 sink 로 file_roll 을 쓰려고 했는데 단점이 있다.

  • 파일명을 지정 못 한다
  • 로그 파일이 계속 쌓인다

생각보다 큰 단점이어서 간단한 sink 프로젝트를 만들었다. https://github.com/kimpaper/flume-slj4j-sink

설치 방법은 위 저장소를 참고. 적용은 이렇게 한다.

1
2
3
4
5
...
agent1.sinks.k1.type = kimpaper.flume.sink.Slj4jSink
agent1.sinks.k1.logLevel = info
agent1.sinks.k1.channel = c1
...

sink 를 slf4j 로 흘리면 위 logback.xml 의 롤링 정책을 그대로 탄다. 파일명도 정해지고 maxHistory 로 자동 삭제도 된다. 앞의 단점 두 개가 같이 해결된다.

이제 각 서버에서 오는 로그들이 collect.log 에 병합되어 쌓이는걸 확인할 수 있다.

정리

  • 날짜와 용량을 같이 걸려면 TimeBasedRollingPolicy 안에 SizeAndTimeBasedFNATP
  • 파일명 패턴에 %i 필수. 같은 날 여러 번 잘릴 수 있다
  • maxHistory 를 꼭 걸자. 안 걸면 디스크가 찬다
  • Flume 기본 로거를 logback 으로 바꾸면 수집 로그도 같은 롤링 정책을 쓸 수 있다
  • file_roll sink 의 파일명·보관 문제는 slf4j sink 로 흘려서 해결