Winston과 Pino로 구조화 로그 만들기
Winston과 Pino를 비교해 Node.js 환경에서 구조화 로그를 설계·구현하고 모니터링 연동과 배포 고려사항까지 정리한 설명
목차
왜 구조화 로그가 필요한가
로그는 서비스 상태를 파악하는 핵심 데이터다. 단순 텍스트는 사람이 읽기에는 편하지만, 검색과 집계에는 한계가 있다. 구조화 로그는 JSON 같은 키-값 형태로 정보를 담아 로그 수집기와 모니터링 도구에서 효율적으로 처리된다. 특히 분산 시스템이나 마이크로서비스 환경에서는 요청 ID, 서비스 이름, 레벨, 타임스탬프 등 메타데이터가 중요하다.
Winston과 Pino 개요
Winston
Winston은 유연한 설정과 다양한 전송 방법을 제공하는 로깅 라이브러리다. 포맷터와 트랜스포트 조합으로 콘솔, 파일, 원격 전송을 쉽게 구성할 수 있다. 대규모 플러그인 에코시스템을 갖추고 있어 확장성이 좋다.
Pino
Pino는 성능 중심의 로거다. JSON 출력을 기본으로 하며, 낮은 오버헤드로 고성능 환경에 적합하다. 로그를 스트림으로 처리하고 외부 프로세스와 연계해 후처리하는 패턴을 권장한다.
설계 원칙
- 일관된 스키마: 모든 로그에 공통 필드(서비스, 환경, 요청ID, 레벨)를 포함
- 검색성: 키-값 구조로 중요한 속성을 노출
- 성능 고려: 동기식 직렬화나 블로킹 I/O를 피함
- 보안·개인정보: 로그에 민감정보를 남기지 않음
Winston 설정 예제
간단한 Winston 설정으로 구조화 로그를 만드는 방법이다. 아래 예제는 JSON 포맷과 파일, 콘솔 트랜스포트를 함께 사용한다.
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
defaultMeta: { service: 'user-service', env: process.env.NODE_ENV },
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'logs/app.log' })
]
});
logger.info('User created', { userId: 123, role: 'admin' });
설명
format.json()을 사용하면 출력이 JSON 형태로 고정된다. defaultMeta에 공통 필드를 넣어 각 로그에 자동으로 포함시키면 검색과 필터링이 쉬워진다. 프로덕션에서는 파일 대신 중앙 로그 수집기로 전송하는 트랜스포트를 추가한다.
Pino 로깅 예제
Pino는 기본적으로 JSON을 출력하므로 설정이 간단하다. 아래 예제는 비동기 직렬화와 요청 컨텍스트를 포함하는 방법을 보여준다.
const pino = require('pino');
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
base: { service: 'user-service', env: process.env.NODE_ENV }
});
logger.info({ userId: 123, role: 'admin' }, 'User created');
성능 팁
- 로그 직렬화는 가능한 비동기화하거나 별도 프로세스로 처리
- 로그 레벨을 환경별로 조정해 불필요한 출력 제한
- 긴 메시지는 필드로 분리해 인덱싱 효율 향상
모니터링과 연동
구조화 로그는 ELK(Elasticsearch, Logstash, Kibana)나 Grafana Loki 같은 수집 스택과 쉽게 연동된다. 방법은 보통 다음과 같다.
- 애플리케이션에서 JSON 로그를 stdout 또는 파일로 출력
- Filebeat나 Fluentd를 통해 중앙 수집기로 전송
- 수집기에서 필요한 필드를 추출·파싱해 저장소에 적재
- 대시보드와 경고 규칙을 정의해 모니터링
배포 시 고려사항
- 로그 레벨과 샘플링 정책 설정으로 비용 통제
- 민감 정보 마스킹 또는 제거 로직 적용
- 로그 포맷 변경 시 하위 호환성 유지
- 장애 발생 시 로그 손실 방지를 위한 버퍼링 고려
마무리 비교와 추천
Winston은 다양한 전송과 포맷 조합이 필요한 환경에 적합하다. 반면 Pino는 처리량과 지연이 중요한 서비스에 유리하다. 실제 선택은 성능 요구치, 운영 환경, 기존 수집 스택과의 연동 편의성에 따라 달라진다. 소개한 설정을 바탕으로 프로덕션 요구사항에 맞게 구조화 로그를 설계하면 모니터링과 문제해결 속도를 크게 높일 수 있다.
추가 리소스
- Winston 설정 Node.js 관련 문서와 예제 코드 참고
- Pino 로깅 예제 Node 실습으로 성능 차이 검증
- 구조화 로그 Node.js 구현 시 로그 스키마 설계 템플릿 적용