1. 개요

Spring Boot 애플리케이션 로그를 JSON으로 출력하고, OpenTelemetry Collector로 수집하도록 붙인 설정을 정리했다. 문자열 로그를 정규식으로 파싱하다 지쳐서 JSON으로 갈아탄 기록이기도 하다.

2. 환경

  • Java: 1.8
  • Spring Boot: 2.5.1
  • OpenTelemetry Collector: contrib 버전

3. 로그 형식을 JSON으로 변경

3-1. 기존 방식의 문제점

기존에는 Logback으로 문자열(String) 로그를 출력했다. 이 방식이 걸렸던 지점은 이랬다.

  • 파싱 정확도: 필드를 나누려면 정규식을 써야 하는데, 로그 포맷이 조금만 바뀌어도 파싱이 깨진다.
  • 리소스 낭비: 복잡한 정규식 패턴 매칭은 CPU·메모리를 제법 잡아먹는다.
  • 유지보수: 포맷이 바뀔 때마다 파싱 규칙도 같이 손봐야 한다.

그래서 로그 형식을 JSON으로 바꾸기로 했다.

3-2. logstash-logback-encoder 의존성 추가

JSON 로그를 뽑으려면 logstash-logback-encoder 라이브러리가 필요하다. 이 라이브러리는 자바 버전, Jackson 버전, logback-classic 버전 호환성을 같이 따져야 한다.

INFO

Spring Boot Starter에 딸려오는 logback-classic과 버전이 충돌할 수 있어 exclude로 걷어내야 하는 경우가 있다.

Java 1.8이라 logstash-logback-encoder는 8.x가 아닌 7.0을 골랐다. (8.x는 Java 11 이상이 필요하다.)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.5.1</version>
    <exclusions>
        <exclusion>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </exclusion>
    </exclusions>
</dependency>
 
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>
<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>7.0</version>
</dependency>

Starter에 포함된 기본 logback-classic을 빼고, 호환되는 버전을 직접 명시해 넣는 방식이다.

3-3. Logback 설정 변경

의존성을 넣었으면 logback-spring.xml에서 JSON 인코더를 쓰도록 바꿔준다.

<appender name="LOGGER" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>

이제 애플리케이션 로그가 JSON으로 나오고, 각 필드를 구조화된 데이터로 그대로 다룰 수 있다.

4. OpenTelemetry Collector 수집 설정

4-1. FileLog Receiver 선택 이유

수집 방식은 여러 가지가 있지만, 제일 단순한 OpenTelemetry Collector Contribfilelogreceiver를 골랐다. 파드 로그가 이미 노드 파일로 떨어지니, 그 파일만 읽으면 됐다.

4-2. FileLog Receiver 설정

receivers:
  filelog/test-app:
    include: 
    - "/var/log/pods/test-app-java-backend-1*/*/*.log"
    - "/var/log/pods/test-app-java-backend-2*/*/*.log"
    include_file_name: false
    include_file_path: true
    start_at: beginning # 또는 end
    operators:
    - type: container
      add_metadata_from_filepath: true
    - type: json_parser
      id: parse_json
      parse_from: body
      parse_to: attributes
    - type: move
      from: attributes.message
      to: body

각 설정 항목의 의미는 다음과 같다.

  • include: 수집할 로그 파일 경로 패턴을 지정한다.
  • include_file_path: 로그 레코드에 파일 경로 정보를 포함할지 여부다.
  • start_at: 컬렉터 시작 시 로그 파일의 어느 지점부터 읽을지 결정한다.
  • operators: 로그 데이터를 처리하는 파이프라인을 정의한다.

IMPORTANT

json_parser 오퍼레이터가 핵심인데, 이것이 JSON 형태의 로그를 파싱해서 구조화된 속성(attributes)으로 변환해준다.

5. 설정 검증 및 확인

파이프라인을 구성한 뒤에는 세 지점을 순서대로 확인했다.

  1. 애플리케이션 로그: JSON 형태로 잘 찍히는지.
  2. 컬렉터 로그: 컬렉터가 대상 파일을 제대로 읽고 있는지.
  3. 파싱 결과: JSON 필드가 attributes로 잘 쪼개졌는지.

전체 OpenTelemetry Collector 설정 예시는 여기에 올려뒀다.

6. 참고