[6주차] 로그 시스템 고도화 (feat. 비동기 Logstash 파이프라인)
5주차에는 프론트엔드 작업하느라 글을 쓸 만한 주제도 없었고, 시간도 없었다.
그래도 이번 주 수요일까지는 프론트를 마무리하고 로그 쪽 고도화할 시간이 있었고, 오랜만에 행복 개발 했다.
기술 블로그 글을 어떤 형식으로 작성해야 할지 아직도 고민이다.
- 많은 독자를 상정하고
입니다체
를 사용하며 내용을 추상화하여 작성할지 - 지금처럼 회고성으로
이다체
를 사용하며 어느 정도 구체적으로 작성할지
최근에 후자로 작성한 기술 블로그 글을 보는데 깊이도 있고 사고 과정이 잘 느껴져서 좋았던 것 같다.
그래서 이번 글은 후자로 작성해보려고 한다.
아무튼 잡설은 여기까지 하고, 6주차에 로깅 시스템 고도화한 내용을 기록/공유하려 한다.
(그마저도 절반은 프론트엔드에 시간을 갈아 넣긴 하였다.)
📌 사전 참고 글
이 글을 읽기 전에 아래 글을 읽지 않았다면 읽는 것을 추천한다.
아래 글의 후속 내용을 다룬 것이 이 글이다.
👉 [3주차] MongoDB를 활용한 로깅 시스템 구축 (시스템/데이터 로그 저장)
👉 https://ti2soon.tistory.com
🧠 의사결정
SODA에서는 두 가지 종류의 로그를 저장 중이다.
-
시스템 로그: 콘솔에 찍히는
LEVEL(INFO, ERROR 등)
로그 - 데이터 로그: 데이터의 생성/변경/삭제 사항을 JSON 형태로 기록한 로그
각 로그의 특성
- 데이터 로그: 수가 많지 않음 (CRUD 발생 시에만 로깅됨)
- 시스템 로그: 수가 많음 (컨트롤러/서비스 전반, 프레임워크 레벨 로그 포함)
기존 문제점
기존에는 동기식으로 MongoDB에 로깅했기 때문에
시스템 로그처럼 양이 많을 경우 I/O로 인한 지연이 발생 → 서비스 응답 시간에 영향
개선 목표
- 파일로 먼저 저장
- Logstash 등 수집기를 통해 비동기적으로 MongoDB 저장
- Spring은 파일만 던지고 로깅에 대해 책임 없음
- 로깅이 WAS 성능에 영향 X
⚙️ 최종 구조
- 비동기 로그 수집기로
Logstash
사용 - 처음에는
Filebeat
사용하려다 실패 (MongoDB output 미지원)
Exiting: error initializing publisher: output type mongodb undefined
결국 Logstash를 Spring 서버 안에 설치
원칙적으로는 별도 서버로 분리하는 게 맞음 그러나 마감 임박 + 서버 비용 문제로 동일 서버에 설치
🛠️ 구현
- logback-spring.xml 설정 ```java
2. logstash.conf 작성
```lombok.config
input {
file {
path => "/usr/share/logstash/logs/*.json"
start_position => "beginning"
sincedb_path => "/usr/share/logstash/data/.sincedb"
codec => "json"
}
}
filter {
mutate {
remove_field => ["@version", "path", "host", "thread"]
}
date {
match => ["time", "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ"]
target => "@timestamp"
}
mutate {
rename => { "time" => "created_time" }
rename => { "@timestamp" => "logging_time" }
}
}
output {
if [level] == "ERROR" {
mongodb {
uri => "${MONGODB_URI}"
database => "log"
collection => "error_log"
isodate => true
}
} else {
mongodb {
uri => "${MONGODB_URI}"
database => "log"
collection => "system_log"
isodate => true
}
}
}
- Dockerfile
FROM docker.elastic.co/logstash/logstash:7.17.16 RUN bin/logstash-plugin install logstash-output-mongodb COPY logstash.conf /usr/share/logstash/pipeline/logstash.conf
- Jenkins Shell Script
```bash
docker run -d
–env-file .env
-p 8085:8080
–name soda
–network ${DOCKER_NETWORK}
-v “/home/ubuntu/logs:/logs”
do2soon/soda:latest
docker pull do2soon/logstash:latest
if [ “$(docker ps -a -q –filter name=logstash)” ]; then docker rm -f logstash fi
docker run -d
–name logstash
–network soda-network
-m 1g –memory-swap=1g
-v “/home/ubuntu/logs:/usr/share/logstash/logs”
-v “/home/ubuntu/sincedb:/usr/share/logstash/data”
–env-file .env
-e LS_JAVA_OPTS=”-Xms512m -Xmx512m”
do2soon/logstash:latest
```
- 로그 TTL 설정
- logback-spring.xml에서
30 로 파일 로그 관리 - MongoDB에서는 TTL 인덱스로 로그 수명 관리
- logback-spring.xml에서
🧯 트러블슈팅
1. Logstash RAM 과점유
t2.micro에 Logstash → RAM/CPU 전부 점유, SSH도 불가
t2.small로 교체 + -m 1g –memory-swap=1g 옵션으로 해결
2. 로그 시간 문자열 저장
로그의 시간 필드가 문자열로 저장되어 TTL/인덱싱 불가
해결:
-
logback에서 ISO 포맷 저장
-
logstash에서 date 필터로 변환
3. 중복 로깅
로그가 초당 50개씩 증가하는 기이한 현상
sincedb_path + 외부 마운트로 중복 로깅 방지
✅ 정상 작동 확인
로그가 파일 → Logstash → MongoDB로 비동기 전달
오류 로그와 일반 로그를 다른 컬렉션으로 구분 저장
TTL 및 로그 순환 정책도 정상 작동