loki4j와 logback

rejs·2025년 12월 25일

loki

loki를 사용하는 이유는 다음과 같다

  1. grafana tempo와의 연동 : traceId를 가지는 로그에서 trace로, 반대로 trace에서 로그로 이동가능
  2. elk는 너무 무겁다.

loki4j와 logback을 사용해서 log를 남기도록 하겠다.

// grafana-datasources.yml 
- name: Loki
    type: loki
    access: proxy
    orgId: 1
    url: http://loki:3100
    basicAuth: false
    isDefault: true
    version: 1
    editable: false
    jsonData:
      # 로그에서 TraceID 발견하면 Tempo로 연결해주는 설정
      derivedFields:
        - datasourceUid: tempo_uid_registration
          matcherRegex: "traceId=(\\w+)" # 로그에서 traceId=... 패턴을 찾음 (또는 JSON 필드 매칭)
          name: TraceID
          url: "$${__value.raw}"         # 찾은 ID로 URL 생성

derivedFields를 사용하면 로그에서 trace로 이동할 수 있다.
프로메테우스도 비슷한 설정으로 매트릭스에서 trace로 이동할 수 있다.

logback

loki4j appender

logback의 appender는 여러가지가 있지만, 이번에는 loki에다가 비동기로 송신하는 loki4j appender를 사용하도록 하겠다.

	implementation 'com.github.loki4j:loki-logback-appender:2.0.1'

logback-spring

logback.xml대신 logback-spring.xml을 사용한다.

왜냐하면 logback.xml은 spring 실행하기 이전에 로드되어 실행되기 때문이다.

logback-spring을 사용하면 spring의 설정값 등을 사용할 수 있다.
대표적으로는 springProfile이나 springProperty가 있다.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
    <springProperty scope="context" name="LOKI_ENDPOINT" source="loki.endpoint"/>

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd} %d{HH:mm:ss.SSS} traceId=%X{traceId:-} spanId=%X{spanId:-} flags=0 %level [%thread] --- %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender">
        <http>
            <url>${LOKI_ENDPOINT}</url>
        </http>

        <labels>
            compose_service=app-${APP_NAME}
            app=${APP_NAME}
            host=${HOSTNAME}
            level=%level
        </labels>

        <structuredMetadata>
            * = %%mdc
        </structuredMetadata>

        <message>
            <pattern>%d{yyyy-MM-dd} %d{HH:mm:ss.SSS} traceId=%X{traceId:-} spanId=%X{spanId:-} flags=0 %level [%thread] --- %msg%n</pattern>
        </message>
    </appender>

    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="LOKI" />
    </root>

</configuration>

앞에서 regex로 traceId에 대한 link를 찾기로 하였기 때문에 traceId= 형태로 남겨주어야한다

derivedFields 기능이 잘 작동하면 이렇게 같은 traceId를 공유하는 Tempo로 링크를 찾아갈 수 있다.

https://grafana.com/grafana/dashboards/17175-spring-boot-observability/
패턴은 사용하는 대시보드에 맞게 작성되었다

0개의 댓글