An-droid
An-droid

Reputation: 6485

Multiple log files with winston with max size and daily rotation

For now I'm using winston to log with max size and daily rotation

I would like to have this behavior with one file per API endpoint thus defining multiple log files

How could I achieve that ?

Here is my winston helper class

import * as winston from 'winston';
import { config } from '../config';

export const logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)({
      timestamp: () => (new Date().toLocaleTimeString()),
      colorize: true,
      level: config.application.mode === 'test' ? 'emerg' : 'info',
    }),
    new (require('winston-daily-rotate-file'))({
      filename: `${process.cwd()}${config.application.log.dir}/.log`,
      timestamp: () => (new Date().toLocaleTimeString()),
      datePattern: 'yyyy-MM-dd',
      prepend: true,
      level: config.application.mode === 'test' ? 'emerg' : 'info',
      maxsize: 100000000, // en octet
      colorize: false,
      json: false,
    }),
  ],
});

export const generateLog = function (data: object): string {
  let log = 'id="easy_tms" ';
  for (const key in data) {
    const value = (data[key] !== undefined && data[key] !== null) ? data[key] : '';
    if (value instanceof Date) {
      log += key + '="' + value.toISOString() + '" ';
    } else if (Array.isArray(value) === true) {
      log += key + '="' + value.join(',');
    } else {
      log += key + '="' + value.toString().replace(/"/g, '') + '" ';
    }
  }
  return log;
};

EDIT :

I tested this solution that works, but I'm not really sure if I'm doing it right :

export function apiLogger(level: string, log: {
  method?: any,
  url?: any,
  requestStep?: string,
  responseStatus?: any,
  responseMessage?: any,
  response?: any,
}, endPoint: string): void {

  const transportMain = new winston.transports.File({
    timestamp: () => (new Date().toLocaleTimeString()),
    datePattern: 'yyyy-MM-dd',
    level: config.application.mode === 'test' ? 'emerg' : 'info',
    filename: path.join(process.cwd(), config.application.log.dir, endPoint + '.log'),
    maxsize: 1024 * 1024 * 100, // 100MB
    colorize: false,
    prepend: true,
    json: false,
  });

  const loggerInstance = new (winston.Logger)({
    transports: [
      transportMain,
    ],
  });

  switch (level) {
    case 'info':
      loggerInstance.info(generateLog(log));
      break;
    case 'error':
      loggerInstance.error(generateLog(log));
      break;
    case 'warn':
      loggerInstance.warn(generateLog(log));
      break;
    case 'verbose':
      loggerInstance.verbose(generateLog(log));
      break;
    case 'debug':
      loggerInstance.debug(generateLog(log));
      break;
    case 'silly':
      loggerInstance.silly(generateLog(log));
      break;
    default:
      loggerInstance.info(generateLog(log));
      break;
  }
}

Upvotes: 0

Views: 3109

Answers (1)

Gabriel Bleu
Gabriel Bleu

Reputation: 10204

You can create one logger per API, each one with it's own file :

const { Logger, transports } = require('winston');

const logger1 = new Logger({
  transports: [new transports.File({ filename: 'log1.log' })]
});

const logger2 = new Logger({
  transports: [new transports.File({ filename: 'log2.log' })]
});

logger1.info('log1');
logger2.info('log2');

Edit

You are creating the logger every time, instead you could do something like :

const apis = ['api1', 'api2'];
const loggers = apis.reduce((memo, api) => {
  memo[api] = new Logger({
    transports: [new transports.File({ filename: `${api}.log` })]
  });
  return memo;
}, {});

const apiLogger = (level, message, api) => {
  loggers[api].log(level, message);
};

apiLogger('info', 'msg1', 'api1');
apiLogger('info', 'msg2', 'api2');

Upvotes: 3

Related Questions