All files / lib/logger Logger.ts

77.77% Statements 28/36
40% Branches 4/10
66.66% Functions 6/9
76.47% Lines 26/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 1345x 5x   5x 5x 5x 5x 5x 5x     5x                             5x                   1x                 8x 1x 1x   8x                         9x 9x 9x 9x   9x 9x   9x                   9x 9x                                       7x                   2x                                            
import { Service } from '../di/di';
import { Writer } from './Writer';
 
enum LogLevel {
  DEBUG,
  INFO,
  WARN,
  ERROR,
  CRITICAL,
}
 
const colors = {
  [LogLevel.DEBUG]: '\x1b[37m', // white
  [LogLevel.INFO]: '\x1b[34m', // blue
  [LogLevel.WARN]: '\x1b[33m', // yellow
  [LogLevel.ERROR]: '\x1b[38;5;208m', // orange
  [LogLevel.CRITICAL]: '\x1b[31m', // red
  reset: '\x1b[0m',
};
 
/**
 * @class Logger
 * @description A singleton logger class that provides methods for logging messages at different levels.
 * It uses a Writer instance to write logs to files.
 */
@Service()
export class Logger {
  private static instance: Logger;
  private writer: Writer;
 
  /**
   * @constructor
   * @private
   * @param {Writer} writer - An instance of the Writer class for log file operations.
   */
  private constructor(writer: Writer) {
    this.writer = writer;
  }
 
  /**
   * @method getInstance
   * @description Gets the singleton instance of the logger. If an instance doesn't exist, it creates one with a new Writer.
   * @returns {Logger} The singleton logger instance.
   */
  public static getInstance(): Logger {
    if (!Logger.instance) {
      const writer = new Writer();
      Logger.instance = new Logger(writer);
    }
    return Logger.instance;
  }
 
  /**
   * @method log
   * @private
   * @description Logs a message to the console and a file with a given log level.
   * If an argument is an Error, its stack trace is logged.
   * @param {LogLevel} level - The log level (e.g., DEBUG, INFO, ERROR).
   * @param {string} message - The main message to log.
   * @param {any[]} args - Additional arguments to log, including Error objects.
   */
  private log(level: LogLevel, message: string, ...args: any[]): void {
    const timestamp = new Date().toISOString();
    const levelString = LogLevel[level];
    const color = colors[level];
    const logMessage = `[${timestamp}] [${levelString}] ${message}`;
 
    let fileMessage = `${logMessage}`;
    const consoleArgs = [];
 
    for (const arg of args) {
      if (arg instanceof Error) {
        fileMessage += ` ${arg.stack || arg.message}`;
        consoleArgs.push(arg.stack || arg.message);
      } else {
        fileMessage += ` ${JSON.stringify(arg)}`;
        consoleArgs.push(arg);
      }
    }
 
    console.log(`${color}${logMessage}${colors.reset}`, ...consoleArgs);
    this.writer.write(fileMessage);
  }
 
  /**
   * @method debug
   * @description Logs a debug message.
   * @param {string} message - The message to log.
   * @param {any[]} args - Additional arguments to log.
   */
  public debug(message: string, ...args: any[]): void {
    this.log(LogLevel.DEBUG, message, ...args);
  }
 
  /**
   * @method info
   * @description Logs an info message.
   * @param {string} message - The message to log.
   * @param {any[]} args - Additional arguments to log.
   */
  public info(message: string, ...args: any[]): void {
    this.log(LogLevel.INFO, message, ...args);
  }
 
  /**
   * @method warn
   * @description Logs a warning message.
   * @param {string} message - The message to log.
   * @param {any[]} args - Additional arguments to log.
   */
  public warn(message: string, ...args: any[]): void {
    this.log(LogLevel.WARN, message, ...args);
  }
 
  /**
   * @method error
   * @description Logs an error message.
   * @param {string} message - The message to log.
   * @param {any[]} args - Additional arguments to log.
   */
  public error(message: string, ...args: any[]): void {
    this.log(LogLevel.ERROR, message, ...args);
  }
 
  /**
   * @method critical
   * @description Logs a critical message.
   * @param {string} message - The message to log.
   * @param {any[]} args - Additional arguments to log.
   */
  public critical(message: string, ...args: any[]): void {
    this.log(LogLevel.CRITICAL, message, ...args);
  }
}