Promtail, Loki를 사용한 Logback 모니터링

원태연·2023년 8월 13일
1

모니터링 시스템 구축기(2)

안녕하세요, 셀럽잇의 로이스입니다.

이전 글에 이어서 메트릭 지표 뿐만 아니라 logback으로 남기는 로그 파일을 모니터링 할 수 있도록 구성해보겠습니다.

우선, 저희 셀럽잇에서는 log level에 나누어 다음과 같이 파일을 정리하고 있습니다.

  • INFO -> logs/backend/info
  • WARN -> logs/backend/warn
  • ERROR -> logs/backend/error

레벨에 따라 각각 다른 폴더에 날짜별, 사이즈별로 분리되어 저장되고 있습니다.

# info.log

01:09:19.973 [http-nio-8080-exec-2] INFO  c.c.c.l.r.RequestLogInterceptor - [Web Request START] : [
#  ...

	[Method] = [GET]
	[URL] = [http://localhost:8080/api/celebs]
	[QueryString] = [null]
	[Params] = [

	]
	[Body] = []
	[Controller Method] = [CelebController.findAll()]
]
01:09:19.982 [http-nio-8080-exec-2] INFO  com.celuveat.common.log.Logger                        - [f28a3f61(anonymous)]  |--->CelebController.findAll()                                                  
01:09:19.984 [http-nio-8080-exec-2] INFO  com.celuveat.common.log.Logger                        - [f28a3f61(anonymous)]  |    |--->CelebRepository.findAll()                                             
01:09:20.044 [http-nio-8080-exec-2] INFO  com.celuveat.common.log.Logger                        - [f28a3f61(anonymous)]  |    |<---CelebRepository.findAll()                                                time=74ms  
01:09:20.046 [http-nio-8080-exec-2] INFO  com.celuveat.common.log.Logger                        - [f28a3f61(anonymous)]  |<---CelebController.findAll()                                                     time=76ms  
01:09:20.077 [http-nio-8080-exec-2] INFO  c.c.c.l.r.RequestLogInterceptor                       - [Web Request END] : [
	[ID] = [f28a3f61(anonymous)]
	[Status] = [200]
	[Headers] = [
		[Vary] = [[Origin, Access-Control-Request-Method, Access-Control-Request-Headers]]
	]
	[Body] = [
		[ ]
	]
	[Query Count] = [1]
	[Total Time] = [107ms]
]

Logback을 통해 유용한 정보들을 남기지만, 매번 서버에 직접 들어가서 확인해야 한다는 불편함이 있었습니다.

날짜와 사이즈, 레벨 별로도 분리되어 있고, 개발 및 운영 환경별로도 로그가 분리되어 있어 통합적으로 모니터링하는 것은 상당히 어려웠습니다.

또, 뒤죽박죽으로 섞여 있는 로그들을 쉽게 확인하기 어려웠습니다.

그래서 모니터링을 하기 위해 PromtailLoki를 도입하기로 하였습니다.

Promtail과 Loki

Promatil 공식문서에서는 다음과 같이 설명하고 있습니다.

Promtail is an agent which ships the contents of local logs to a private Grafana Loki instance or Grafana Cloud. It is usually deployed to every machine that has applications needed to be monitored.

It primarily:

  • Discovers targets
  • Attaches labels to log streams
  • Pushes them to the Loki instance.

간단하게 추려보면, Promtail은 모니터링이 필요한 로컬 머신에서 Loki instance에 로컬 로그를 푸시하는 agent라고 합니다.

Loki 공식문서에서는 다음과 같이 설명하네요.

Grafana Loki is a log aggregation tool, and it is the core of a fully-featured logging stack.

로깅에 특화된 집계 도구로 이해하면 좋을 것 같습니다.

(https://grafana.com/docs/loki/latest/fundamentals/overview/)

공식문서에서 제공하는 overview 입니다.
Promtail과 같은 agent가 app에서 발생하는 로그들을 수집하여 HTTP API를 통해 Loki에 전송하는 구조를 띄고 있습니다.

대략적인 구조를 파악했으니, 빠르게 적용해보겠습니다.

적용하기

이번에도 docker-compose-monitoring.yml에 구성하도록 하겠습니다.

# docker-compose-monitoring.yml

version: '3'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    user: "$UID:$GID"
    ports:
      - "3000:3000"
    volumes:
      - ./grafana-data:/var/lib/grafana
    depends_on:
      - prometheus

# 추가됨
  loki:
    image: grafana/loki:latest
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml

  promtail:
    image: grafana/promtail:latest
    volumes:
      - ./logs/backend:/logs
      - ./promtail-config.yml:/etc/promtail/config.yml
    command: -config.file=/etc/promtail/config.yml

우선 Loki에 대해 살펴보겠습니다. Loki 이미지를 다운 받고, 포트를 바인딩 하는건 별로 어색하지 않습니다.

command 옵션은 도커 컨테이너가 실행된 후 실행하는 명령을 정의할 수 있습니다.

-config.file=/etc/loki/local-config.yaml은 Loki 가 실행될 때 사용할 설정 파일을 지정하는 것 인데, 건들일 필요가 없어서 기본값으로 설정해두었습니다.


다음으로 promtail입니다.

우선 접근해야할 log 파일들이 저장되어있는 호스트의 ./logs/backend를 불륨 마운트 시켜줍니다.

이후 promtail이 Log를 수집하는 job을 정의하는 /etc/promtail/config.yml를 직접 정의할 수 있도록 이 역시도 마운트 시켜줍니다.

Loki와 마찬가지로 사용할 설절 파일을 기본값으로 설정하여 실행합니다.

그럼, Log를 수집하는 job을 promtail-config.yml에서 정의해보겠습니다.

positions:
  filename: /tmp/positions.yaml # 동기화 작업을 이루기 위해 promtail이 읽은 마지막 로그 정보를 저장하는 곳

clients:
  - url: http://localhost:3100/loki/api/v1/push # push할 Loki의 주소

scrape_configs:
  - job_name: info
    static_configs:
      - targets:
          - localhost
        labels:
          job: info_logs
          __path__: ./logs/info/*.log # info 폴더 내에 log 파일들 모두 수집
        
  - job_name: warn
    static_configs:
      - targets:
          - localhost
        labels:
          job: warn_logs
          __path__: ./logs/warn/*.log # warn 폴더 내에 log 파일들 모두 수집
          
  - job_name: error
    static_configs:
      - targets:
          - localhost
        labels:
          job: error_logs
          __path__: ./logs/error/*.log # error 폴더 내에 log 파일들 모두 수집

구성이 완료되면, docker을 다시 실행한 뒤 Grafana로 들어갑니다!

Loki Datasource를 추가해보겠습니다.

선택을 한 뒤,

Loki의 주소를 입력하여 추가합니다.

이후 새로운 대시보드를 작성합니다.

원하는 job을 설정하면 해당 job이 수집한 로그들을 볼 수 있습니다.

log는 기본적으로 한 줄 단위로 분리되어 작성되는데요.

저희 celuveat의 로깅 방식에 맞게 multiline 옵션을 추가하여 한 블럭의 단위를 조정해보겠습니다.

pipeline_stages:
- multiline:
    firstline: '^\d{2}:\d{2}:\d{2}\.\d{3} \[.*\] INFO  .* \[Web Request (START|END)\]'
    max_wait_time: 1s
    max_lines: 500

블럭의 단위가 [Web Request START/END]를 기준으로 나눠 볼 수 있게 되었습니다.

또, error 로그의 경우는 다음과 같이 추가하였습니다.

pipeline_stages:
      - multiline:
          firstline: '^\d{2}:\d{2}:\d{2}\.\d{3} \[.*\] ERROR'
          max_wait_time: 1s
          max_lines: 500

최종 형태

# promtail-confing.yml

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://localhost:3100/loki/api/v1/push

scrape_configs:
  - job_name: info
    static_configs:
      - targets:
          - localhost
        labels:
          job: info_logs
          __path__: ./logs/info/*.log
    pipeline_stages:
      - multiline:
          firstline: '^\d{2}:\d{2}:\d{2}\.\d{3} \[.*\] INFO  .* \[Web Request (START|END)\]'
          max_wait_time: 1s
          max_lines: 500

  - job_name: warn
    static_configs:
      - targets:
          - localhost
        labels:
          job: warn_logs
          __path__: ./logs/warn/*.log

  - job_name: error
    static_configs:
      - targets:
          - localhost
        labels:
          job: error_logs
          __path__: ./logs/error/*.log
    pipeline_stages:
      - multiline:
          firstline: '^\d{2}:\d{2}:\d{2}\.\d{3} \[.*\] ERROR'
          max_wait_time: 1s
          max_lines: 500

다음으로

이제 로그백으로 남기는 로그들 까지 모니터링이 가능해졌습니다.

Docker를 사용하여 비교적 간단하게 설치하여 구성할 수 있었습니다.

물론 직접 설치해도 되지만, 현재 인스턴스 상황에 따라 모니터링 서버를 어디에 구축하여야 하는 지 확정이 되지 않아 빠르게 이식할 수 있도록 구성해보게 되었습니다.

또, 다음 포스팅이에서 도커 네트워크를 통해서 비교적 안전하게 내부 네트워크를 통해 meteric정보들을 노출 시키지 않고 모니터링이 가능하도록 구성할 예정입니다.

profile
앞으로 넘어지기

0개의 댓글