nukeop/nuclear

View on GitHub
packages/main/src/services/logger/index.ts

Summary

Maintainability
A
1 hr
Test Coverage
/* eslint-disable @typescript-eslint/no-explicit-any */
import { app } from 'electron';
import timber from 'electron-timber';
import path from 'path';
import * as rts from 'rotating-file-stream';

timber.hookConsole();

const errorLogStream = rts.createStream(
  path.join(app.getPath('userData'), 'logs', 'nuclear-error.log'),
  {
    size: '5M',
    compress: 'gzip'
  }
);

/**
 * @see {@link https://github.com/sindresorhus/electron-timber}
 */

interface EventMessage {
  once?: boolean;
  direction: 'in' | 'out';
  event: any;
  data?: any;
}
export interface ILogger {
  log(...args: any[]): void;
  logEvent({ direction, event, data, once }: EventMessage): void;
  warn(...args: any[]): void;
  error(...args: any[]): void;
}

class Logger implements ILogger {
  private logger: typeof timber;
  private name: string;

  constructor(name?: string) {
    this.name = name || 'main';
    this.logger = name ? timber.create({ name }) : timber;
  }

  private getDate() {
    const now = new Date();
    let month = (now.getMonth() + 1).toString();

    if (month.length === 1) {
      month = `0${month}`;
    }
    
    return `[${now.getDate()}/${month}/${now.getFullYear()}-${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}]`;
  }

  writeToFile(name: string, ...args: any[]) {
    args.forEach((log) => {
      if (log.stack) {
        errorLogStream.write(`${this.getDate()}${name} > ${log.stack}`);
      } else if (log.message) {
        errorLogStream.write(`${this.getDate()}${name} > ${log.message}\n`);
      } else if (log.toString) {
        errorLogStream.write(`${this.getDate()}${name} > ${log.toString()}\n`);
      }
    });
  }

  log(...args: any[]): void {
    this.logger.log(...args);
  }

  logEvent({ direction, event, data, once }: EventMessage) {
    const message = `${once ? 'once' : ''} ${direction === 'in' ? '==>' : '<=='} ${event}`;

    let dataMessage: string = typeof data;

    if (dataMessage === 'object') {
      if (Array.isArray(data)) {
        let arrayType;
        if (typeof data[0] === 'object') {
          arrayType = data[0].constructor.name;
        } else if (data[0]) {
          arrayType = typeof data[0];
        } else {
          arrayType = 'void';
        }
        dataMessage = `Array<${arrayType}>`;
      } else if (data) {
        dataMessage = data.constructor.name;
      }
    }

    this.log(message + (data ? `: ${dataMessage}` : ''));
  }
  
  warn(...args: any[]): void {
    this.logger.warn(...args);
  }

  error(...args: any[]): void {
    this.logger.error(...args);
    this.writeToFile(this.name, ...args);
  }
}

export const $mainLogger = Symbol('main-logger');
export const $ipcLogger = Symbol('ipc-logger');
export const $systemApiLogger = Symbol('system-api-logger');
export const $httpApiLogger = Symbol('http-api-logger');

export default Logger;