shawn bright
shawn bright

Reputation: 93

how to pass a filename to winston logger?

I have winston set up as a logger and it works great. However, I have several processes that I would like to log to different files. How can I pass the filename into a logger instance?

I am using this as my block

'use strict';
const { createLogger, format, transports } = require('winston');
require('winston-daily-rotate-file');
const fs = require('fs');
const path = require('path');
const logDir = '/codeforge/log';

const dailyRotateFileTransport = new transports.DailyRotateFile({
  filename: `${logDir}/%DATE%-engine.log`,
  maxSize: "1g",
  maxDays: "3d",
  zippedArchive: true,
  datePattern: 'YYYY-MM-DD'
});

const logger = createLogger({
  // change level if in dev environment versus production
  level: 'debug', 
  maxsize: '500m',
  format: format.combine(
    format.timestamp({
      format: 'YYYY-MM-DD HH:mm:ss'
    }),
    // for the log file
    format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`)
  ),
  transports: [
    new transports.Console({
      level: 'info',
      format: format.combine(
        format.colorize(),
        format.printf(
          info => `${info.message}`
        )
      )
    }),
    dailyRotateFileTransport
  ]
});

module.exports = logger

I would like to pass in a filename to replace the "-engine" part to create or append a log file for it.

thanks for any tips.

Upvotes: 6

Views: 13556

Answers (3)

Roko C. Buljan
Roko C. Buljan

Reputation: 205987

If you're using ES6 module imports, here's a feasible suggestion:

logger.js

import winston from "winston";
import { resolve } from "path";
import { fileURLToPath } from "url";

const { format, transports, createLogger } = winston;
const { combine, timestamp, printf } = format;

export default (meta_url) => {

  const root = resolve("./");
  const file = fileURLToPath(new URL(meta_url));
  const file_path = file.replace(root, "");

  const customFormat = printf(({ level, message, timestamp, stack }) => {
    return `${timestamp} [${level}] ${file_path}: ${stack || message}`;
  });

  const loggerInstance = createLogger({
    level: "info",
    format: combine(
      timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
      format.splat(),
      format.errors({ stack: true }),
      customFormat
    ),
    defaultMeta: { service: "user-service" },
    transports: [
      new transports.File({ filename: "log/error.log", level: "error" }),
      new transports.File({ filename: "log/common.log" }),
    ],
  });

  // Log also to console if not in production
  if (process.env.NODE_ENV === "development") {
    loggerInstance.add(
      new transports.Console({
        format: combine(colorize(), customFormat),
      })
    );
  }

  return loggerInstance;
};

server/index.js

import Logger from "../logger.js";
const logger = Logger(import.meta.url);

logger.info("App running on http://localhost:%i", 5000);

Result:

2021-12-17 15:09:38 [info] /server/index.js: App running on http://localhost:5000

How it works:

Inside logger.js, instead of immediately returning the logger instance, we return a wrapper function that accepts as argument the file's import.meta.url, and then returns the Logger instance.

Inside the logger we simplify the absolute path and we pass it to the custom Logger formats to output. If you don't want to beautify the path, simply use const file_path = fileURLToPath(new URL(meta_url))

Upvotes: 2

vanduc1102
vanduc1102

Reputation: 6245

I dont want to create or reinitialize the Logger instance many times, We can check by running

DEBUG=winston* yarn start

I am using child logger , here is my logger with typescript,

import winston from 'winston';

const { transports, format } = winston;

const { LOG_LEVEL, APP_ENV } = process.env;

const logFormatter = APP_ENV === 'dev'
  ? format.combine(
      winston.format.timestamp(),
      winston.format.colorize(),
      winston.format.printf((meta: any) => {
        const { level, message, timestamp, namespace, stack, ...restMeta } = meta;
        const displayNamespace = namespace ? `[${namespace}] -` : '';
        const stackMessage = stack ? `\n${stack}` : '';
        const otherMetaMessage = Object.keys(restMeta).length > 0 ? `\n${JSON.stringify(restMeta)}` : '';
        return `${timestamp} ${displayNamespace} ${level}: ${message} ${otherMetaMessage}${stackMessage}`;
      })
    )
  : format.combine(winston.format.timestamp(), winston.format.json());

const logger = winston.createLogger({
  level: LOG_LEVEL || 'debug',
  format: logFormatter,
  transports: [
    new winston.transports.Console({
      silent: APP_ENV === 'test',
    }),
  ],
});

export const Logger = (namespace?: string) => {
  if (namespace) {
    return logger.child({ namespace });
  }
  return logger;
};

Usage: service-abc.js

const LOGGER = Logger('service:abc');
export class serviceAbc{
   doSomething(){
      LOGGER.info("do something");
   }
}

Upvotes: 1

Cody Geisler
Cody Geisler

Reputation: 8617

Make your logger into a function that you call like

const log = require('logger')('myfilename');
log.info('happy logging')

Code:

'use strict';
const { createLogger, format, transports } = require('winston');
require('winston-daily-rotate-file');
const fs = require('fs');
const path = require('path');
const logDir = '/codeforge/log';

const dailyRotateFileTransport = filename => new transports.DailyRotateFile({
  filename: `${logDir}/%DATE%-${filename}.log`,
  maxSize: "1g",
  maxDays: "3d",
  zippedArchive: true,
  datePattern: 'YYYY-MM-DD'
});

const logger = function(filename){
  return createLogger({
    // change level if in dev environment versus production
    level: 'debug', 
    maxsize: '500m',
    format: format.combine(
      format.timestamp({
        format: 'YYYY-MM-DD HH:mm:ss'
      }),
      // for the log file
      format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`)
    ),
    transports: [
      new transports.Console({
        level: 'info',
        format: format.combine(
          format.colorize(),
          format.printf(
            info => `${info.message}`
          )
        )
      }),
      
      dailyRotateFileTransport(filename)
    ]
  });
}

module.exports = logger // is now a function

Upvotes: 10

Related Questions