Files

66 lines
2.0 KiB
TypeScript

type Level = "debug" | "info" | "warn" | "error";
const PRIORITY: Record<Level, number> = {
debug: 0,
info: 1,
warn: 2,
error: 3,
};
function getMinLevel(): Level {
const env = process.env.LOG_LEVEL as Level | undefined;
if (env && env in PRIORITY) return env;
const appEnv = process.env.APP_ENV;
return appEnv === "production" ? "info" : "debug";
}
function shouldLog(level: Level): boolean {
return PRIORITY[level] >= PRIORITY[getMinLevel()];
}
// TZ 환경변수 기준 로컬 시간 (toISOString은 항상 UTC라 사용하지 않음)
export function timestamp(): string {
const d = new Date();
const pad = (n: number, w = 2) => String(n).padStart(w, "0");
const offMin = -d.getTimezoneOffset();
const sign = offMin >= 0 ? "+" : "-";
const abs = Math.abs(offMin);
return (
`${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}` +
`T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}` +
`.${pad(d.getMilliseconds(), 3)}` +
`${sign}${pad(Math.floor(abs / 60))}:${pad(abs % 60)}`
);
}
function write(
level: Level,
ctx: string,
message: string,
data?: Record<string, unknown>
): void {
if (!shouldLog(level)) return;
const ts = timestamp();
const tag = level.toUpperCase().padEnd(5);
const line = data
? `[${ts}] [${tag}] [${ctx}] ${message} ${JSON.stringify(data)}`
: `[${ts}] [${tag}] [${ctx}] ${message}`;
if (level === "warn" || level === "error") {
console.error(line);
} else {
console.log(line);
}
}
export const logger = {
debug: (ctx: string, message: string, data?: Record<string, unknown>) =>
write("debug", ctx, message, data),
info: (ctx: string, message: string, data?: Record<string, unknown>) =>
write("info", ctx, message, data),
warn: (ctx: string, message: string, data?: Record<string, unknown>) =>
write("warn", ctx, message, data),
error: (ctx: string, message: string, data?: Record<string, unknown>) =>
write("error", ctx, message, data),
isEnabled: (level: Level): boolean => shouldLog(level),
};