최근에 서버 로그 환경을 손보면서, PM2 + winston logger + Docker 조합을 쓰다 보니 예상 못한 부분에서 꽤 헤맸다.
처음에는 “그냥 로그 찍으면 되지”였는데, 막상 운영 환경에 들어가니까 로그 색상, 포맷, pm2-runtime 옵션, 그리고 Docker 로그 수집 방식까지 다 얽히면서 재미있는(?) 상황이 벌어졌다.
1. PM2와 logger의 첫 만남
원래 Node.js에서 console.log()로 로그를 찍고 있었다.
근데 운영 환경에서는 이게 너무 단순하다 보니, 로그 파일 분리나 회전(rotation)도 없고, JSON 포맷도 아니어서 검색이나 필터링이 힘들었다.
그래서 winston + winston-daily-rotate-file 조합으로 logger를 도입했다.
const logger = winston.createLogger({
level: logLevel,
format: winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new DailyRotateFile({
filename: 'app-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxSize: '20m',
maxFiles: '14d'
})
]
});
이렇게 하면 파일이 날짜별로 잘 잘리고, JSON으로 남아서 나중에 Loki나 Elasticsearch 같은 로그 시스템에도 잘 들어간다.
2. 색깔 출력이 사라진 이유
문제는 여기서부터였다.
개발 환경에서는 예쁘게 색깔 들어간 로그가 잘 보였는데, Docker + PM2로 돌리니까 색깔이 다 빠지고 흑백만 나왔다.
이유는 간단하다.
- winston에서 색상 포맷을 따로 넣지 않았고
- PM2가 stdout을 잡아서 Docker 로그로 넘기는 과정에서 ANSI 색상 코드가 빠지는 경우가 있었다.
해결 방법은 winston 포맷에 colorize()를 추가하는 거다.
근데 여기서도 한 가지 고려할 점이 있다.
Promtail, Loki 같은 로그 수집기가 색상 코드를 싫어한다.
색상 ANSI 코드가 들어가면 JSON 파싱이 깨질 수도 있고, 검색이 꼬일 수 있다.
그래서 운영 환경에서는 색상 없이 JSON 로그, 로컬 개발 환경에서는 색상 있는 콘솔 로그로 분리하는 게 깔끔하다.
3. pm2-runtime과 --raw 옵션
다음 문제는 PM2 runtime이었다.
Dockerfile에서 기존에는 이렇게 쓰고 있었다.
이걸 pm2-runtime으로 바꾸면,
Docker에서 종료 시그널 처리나 재시작 관리가 더 안전해진다.
근데 여기서 --raw 옵션을 붙이면
4. Docker 로그와 out_file, merge_logs
또 하나 헷갈렸던 건 pm2 설정의 이 부분이었다.
이걸 넣으면 PM2가 찍는 로그가 전부 Docker의 stdout/stderr로 바로 전달된다.
덕분에 docker logs로 다 볼 수 있다.
안 그러면 PM2 내부 로그 파일로만 쌓이고 Docker 쪽에서는 안 보이는 경우가 생긴다.
5. 결론 – 환경별 로그 전략
내가 겪어본 바로는 이렇게 정리된다.
- 개발 환경
- colorize된 콘솔 로그
- pm2 --raw 옵션 ON
- 파일 로그는 최소화
- 운영 환경
- JSON 포맷 (color X)
- pm2-runtime + prefix 유지
- stdout/stderr로 로그 출력 → Loki/Promtail 수집
- winston-daily-rotate-file로 백업 로그도 남김
6. 덤 – 색상 로깅과 Loki
색상 코드를 넣으면 사람 눈에는 좋지만, Loki에서는 이렇게 나온다.
그래서 운영 Loki에 색상 코드가 들어가면 필터링할 때 좀 빡세진다.
차라리 색상은 개발자 로컬에서만 즐기는 걸로 하고, 운영은 깔끔한 JSON이 낫다.
이렇게 정리하고 나니까, 처음에 왜 색상이 안 나오고 로그가 두 배로 찍히고 그랬는지 이해가 됐다.
PM2, logger, Docker 로그 수집기는 각각 “자기 방식”이 있다 보니, 셋을 잘 맞춰주는 게 포인트다.
'TIL' 카테고리의 다른 글
| Socket Admin UI 페이지 보는법 (0) | 2025.09.11 |
|---|---|
| Socket.IO에서 JWT 만료 시 아예 연결을 차단하는 방법 (0) | 2025.09.05 |
| postgres DB 이원화 (3) | 2025.08.10 |
| Ingress Controller rewrite 안될때 (2) | 2025.07.30 |
| 서버가 달라도 빠르게 통신하는 방법 ( 쿠버네틱스 ) (1) | 2025.07.29 |