typescript-express-starter
Version:
Quick and Easy TypeScript Express Starter
109 lines (101 loc) • 3.33 kB
text/typescript
import { existsSync, mkdirSync } from 'node:fs';
import { join } from 'node:path';
import pino from 'pino';
import { LOG_DIR, LOG_LEVEL, NODE_ENV } from '@config/env';
// 로그 환경 설정
const isProd = NODE_ENV === 'production';
const logRoot = LOG_DIR || 'logs';
const logLevel = LOG_LEVEL || 'info';
// 현재 런타임 위치(프로젝트 실행 디렉토리)에 logs 폴더 생성
const projectRoot = process.cwd(); // 현재 프로세스 실행 디렉토리
const logDir = join(projectRoot, logRoot);
// 로그 디렉토리 생성 (에러 핸들링 포함)
if (!existsSync(logDir)) {
mkdirSync(logDir, { recursive: true });
// console.log(`[Logger Init] Created log directory: ${logDir}`);
} else {
// console.log(`[Logger Init] Log directory already exists: ${logDir}`);
}
// 파일 로깅용 경로
const prodFile = join(logDir, 'app');
const devFile = join(logDir, 'app.dev');
const errorFile = join(logDir, 'error');
// Pino 인스턴스
const transport = pino.transport({
targets: isProd
? [
// prod: 일자/용량 기반 롤링 + 30일 보관 (전체 로그)
{
target: 'pino-roll',
level: logLevel,
options: {
file: prodFile, // 최종 파일: app.2025-08-29.log 등
frequency: 'daily', // 'daily' | 'hourly' | number(ms)
size: '50m', // 용량 기준 분할
dateFormat: 'yyyy-MM-dd',
extension: '.log',
mkdir: true,
symlink: false, // 심볼릭 링크 비활성화로 충돌 방지
limit: { count: 30 }, // 30개 보관
// limit: { count: 30, removeOtherLogFiles: false }, // PM2/클러스터면 주의
},
},
// prod: 에러 전용 파일 (보관 60일 등 별도 정책 가능)
{
target: 'pino-roll',
level: 'error',
options: {
file: errorFile,
frequency: 'daily',
size: '50m',
dateFormat: 'yyyy-MM-dd',
extension: '.log',
mkdir: true,
symlink: false, // 심볼릭 링크 비활성화로 충돌 방지
limit: { count: 60 },
},
},
]
: [
// dev: 예쁜 콘솔 출력
{
target: 'pino-pretty',
level: logLevel,
options: {
colorize: true,
translateTime: 'yyyy-mm-dd HH:MM:ss',
ignore: 'pid,hostname',
},
},
// dev: 파일도 같이 굴리고 싶다면(선택) — 필요 없으면 이 블록을 지워도 됨
{
target: 'pino-roll',
level: logLevel,
options: {
file: devFile,
frequency: 'daily',
size: '20m',
dateFormat: 'yyyy-MM-dd',
extension: '.log',
mkdir: true,
symlink: true,
limit: { count: 7 },
},
},
],
});
// ── Logger 인스턴스
export const logger = pino(
{
level: logLevel,
base: undefined,
timestamp: pino.stdTimeFunctions.isoTime,
redact: {
paths: ['req.headers.authorization', 'password', 'token'],
censor: '[REDACTED]',
},
},
transport,
);
// morgan stream
export const stream = { write: (msg: string) => logger.info(msg.trim()) };