logger.ts 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. const LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 } as const;
  2. type LogLevel = keyof typeof LOG_LEVELS;
  3. function getMinLevel(): LogLevel {
  4. const env = (process.env.LOG_LEVEL ?? 'info').toLowerCase();
  5. return env in LOG_LEVELS ? (env as LogLevel) : 'info';
  6. }
  7. function isJsonFormat(): boolean {
  8. return process.env.LOG_FORMAT === 'json';
  9. }
  10. function formatLine(level: LogLevel, tag: string, args: unknown[]): string {
  11. const timestamp = new Date().toISOString();
  12. const upperLevel = level.toUpperCase();
  13. const msg = args
  14. .map((a) =>
  15. a instanceof Error ? (a.stack ?? a.message) : typeof a === 'string' ? a : JSON.stringify(a),
  16. )
  17. .join(' ');
  18. if (isJsonFormat()) {
  19. return JSON.stringify({ timestamp, level: upperLevel, tag, message: msg });
  20. }
  21. return `[${timestamp}] [${upperLevel}] [${tag}] ${msg}`;
  22. }
  23. export function createLogger(tag: string) {
  24. const emit = (level: LogLevel, args: unknown[]) => {
  25. if (LOG_LEVELS[level] < LOG_LEVELS[getMinLevel()]) return;
  26. const line = formatLine(level, tag, args);
  27. // Console output
  28. const fn =
  29. level === 'debug'
  30. ? console.debug
  31. : level === 'warn'
  32. ? console.warn
  33. : level === 'error'
  34. ? console.error
  35. : console.log;
  36. fn(line);
  37. };
  38. return {
  39. debug: (...args: unknown[]) => emit('debug', args),
  40. info: (...args: unknown[]) => emit('info', args),
  41. warn: (...args: unknown[]) => emit('warn', args),
  42. error: (...args: unknown[]) => emit('error', args),
  43. };
  44. }