관리 메뉴

피터의 개발이야기

[Fluentd] multiline parser, 로그병합과 필터링 본문

DevOps

[Fluentd] multiline parser, 로그병합과 필터링

기록하는 백앤드개발자 2025. 9. 6. 11:31
반응형

ㅁ 들어가며

Kibana에서 시스템 로그를 분석하는 과정에서 일부 로그가 누락되는 현상을 발견하였다. Fluentd로그에서 parser 오류를 발견하고 이를 해결하는 과정에서 multiline parser에 대해서 공부한 내용을 정리하였다.

 에러 확인: fluent-plugin-concat을 사용하고 있어, multiline_start_regexp와 multiline_stop_regexp 수정 과정,

 개념정리: Fluentd의 multiline 공식 문서를 통해 개념을 정리하였다.

 

ㅁ Fluentd 에러 확인

2025-09-05 05:30:36 +0000 [warn]: #0 dump an error event: error_class=Fluent::Plugin::Parser::ParserError error="pattern not matched with data

 

ㅁ 에러 원인 분석

    <filter **>
      @type concat
      key log
      separator ""
      multiline_end_regexp /\n$/
      flush_interval 2s
    </filter>

    <filter **>
      @type parser
      key_name log
      reserve_data true
      <parse>
        @type           regexp
        expression      /^(?<logtime>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})/
        time_key        logtime
        time_format     %Y-%m-%d %H:%M:%S.%L
        timezone        +09:00
        keep_time_key   true
        <record>
          time ${Time.parse(record["logtime"]).strftime('%Y-%m-%dT%H:%M:%S.%LZ')}
        </record>
      </parse>
    </filter>

ㅇ fluent.conf의 filter 부분이다.

expression      /^(?<logtime>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})/

ㅇ 현재 파서의 expression은 맨 앞에 시간을 캡처하도록 되어 있다.

\tat com.kaka....(JsWorkerRunner.scala:152)\n

ㅇ 하지만 문제의 라인은 "\tat"로 시작하고, 시간/레벨/로거 같은 헤더가 없었다.

 

ㅁ Fluentd ParserError 해결

[이전]
multiline_end_regexp /\n$/
[수정]
multiline_start_regexp /^(?:\d{4}-\d{2}-\d{2}|\d{8})[ T]\d{2}:\d{2}:\d{2}(?:[.,]\d{3})?\b/

ㅇ 멀티라인 결합을 “끝 패턴”이 아닌 “시작 패턴”**으로 전환해,
    ^\d{4}\d{2}\d{2} ...로 시작하는 줄에서만 새 이벤트를 시작하도록 했다.

ㅇ 이어지는
    \tat ..., Caused by: ...
    같은 줄은 모두 이전 이벤트에 이어붙인다.

ㅇ 이렇게 결합된 하나의 블록만 정규식 파서에 넘기면,
     파서는 첫 줄에서 시간/레벨/로거만 파싱하고 나머지 스택트레이스는 메시지로 포함되어 정상 처리된다.

ㅇ 정리하면
    \tat ... 줄이 잘못된 게 아니라,
    단독으로 한 줄 파서에 들어가 실패했던 것.
   따라서 “시작 패턴 기반 멀티라인으로 묶고 → 파싱” 순서로 바꾸면 해결된다.

 

Fluentd 멀티라인 이란?

멀티라인의 정의 및 특징

ㅇ 여러 줄에 걸쳐 하나의 로그 이벤트가 기록되는 현상으로, 자주 발생하는 예시로는 Java Stack Trace, 서비스 오류 로그 등이 있다.

멀티라인 로그는 시작 줄과 이어지는 줄의 패턴이 있어, 이를 적절히 감지해서 하나의 이벤트로 묶는다.

 

멀티라인으로 처리해야 하는 실무적 이유

ㅇ 각 줄을 개별 이벤트로 인식할 경우 실질적인 오류의 맥락이 분리되어, 원인 분석과 모니터링이 어려워진다.

ㅇ 로그의 일관된 집계, 분석, 저장을 위해 반드시 논리적으로 병합하는 작업이 필요하다.

ㅇ 멀티라인 결합이 누락되면 이벤트 지연, 로그 손실, 정상적인 적재 불가, 성능 저하 등 다양한 문제가 발생할 수 있다.

 

Fluentd에서 멀티라인 설정 및 conf 예시

<source>
  @type multiline
  # ...
  <parse>
    # ...
  </parse>
</source>

ㅇ <source> @type tail <parse> 블록을 두고 @type multiline을 명시한다.

Fluentd 공식 문서 > Config: Parse Section

 

<parse>
  @type multiline
  format_firstline /\d{4}-\d{1,2}-\d{1,2}/
  format1 /^(?<time>\d{4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}) \[(?<thread>.*)\] (?<level>[^\s]+)(?<message>.*)/
</parse>

ㅇ format_firstline, format1 등 정규식 패턴으로 시작 줄 및 이어지는 줄 포맷을 정의하여 이벤트를 분리/결합한다.

ㅇ multiline_flush_interval 등 파라미터로 집계 주기를 세밀하게 제어하여 성능과 데이터 정확성을 최적화한다.

Fluentd 공식문서 > Multiline

 

ㅁ 함께 보면 좋은 사이트

 Fluentd 공식문서 > Multiline

 Fluentd 공식 문서 > Config: Parse Section

Fluentd 로그병합 & 필터링

fluent-plugin-concat

반응형
Comments