Node.js - logging / Use morgan and winston

node.jsLoggingExpressWinston

node.js Problem Overview


we use morgan in order to log our express transformation:

var morgan  = require('morgan');
morgan('combined');
// a format string
morgan(':remote-addr :method :url :uuid');
// a custom function
morgan(function (req, res) {
  return req.method + ' ' + req.url + ' ' + req.uuid;
})

Also, we use winston in order to log our other logging:

var winston = require('winston');
var logger = new (winston.Logger)({
  transports: [
         new (winston.transports.Console)({ level: 'info' }),
          new (winston.transports.File)({ filename: '/var/log/log-file.log' })
  ]
});

Is there any way to combine the two loggers together? the situation now is that morgan is write to my standard output, when winston writes to /var/log/log-file.log.

I wish that the logger file will combine from the express transformation information, and from the other information I want (logger.info())..

node.js Solutions


Solution 1 - node.js

This article does an excellent job for what you want to do.

http://tostring.it/2014/06/23/advanced-logging-with-nodejs/

For your specific code you probably need something like this:

var logger = new winston.Logger({
    transports: [
        new winston.transports.File({
            level: 'info',
            filename: './logs/all-logs.log',
            handleExceptions: true,
            json: true,
            maxsize: 5242880, //5MB
            maxFiles: 5,
            colorize: false
        }),
        new winston.transports.Console({
            level: 'debug',
            handleExceptions: true,
            json: false,
            colorize: true
        })
    ],
    exitOnError: false
});

logger.stream = {
    write: function(message, encoding){
        logger.info(message);
    }
};

app.use(require("morgan")("combined", { "stream": logger.stream }));

This will set up Winston to write a log to the console as well as a file. Then you can use the last expression to pass output from the morgan middleware into winston.

Solution 2 - node.js

In Typescript:

let logger = new (winston.Logger)({
	exitOnError: false,
	level: 'info',
	transports: [
		new (winston.transports.Console)(),
		new (winston.transports.File)({ filename: 'app.log'})
	]
})

class MyStream {
	write(text: string) {
		logger.info(text)
	}
}
let myStream = new MyStream()
app.use(morgan('tiny', { stream: myStream }));

Solution 3 - node.js

Update the last line to remove warning

app.use(require("morgan")("combined", { stream: logger.stream }));

Solution 4 - node.js

Morgan has the bad habit of ending the message with a \n so to make things orderly you may want to remove that before writing it to winston.

This can be done in many different ways like on the format side in winston, or by updating your stream to not write the \n

class MyStream {
    write(text: string) {
        logger.info(text.replace(/\n$/, ''));
    }
}
let myStream = new MyStream()
app.use(morgan('tiny', { stream: myStream }));

Solution 5 - node.js

for Typescript another way to go about it, without needing to create a class is

let logger = new (winston.Logger)({
    exitOnError: false,
    level: 'info',
    transports: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ filename: 'app.log'})
    ]
})

const myStream = {
    write: (text: string) => {
        logger.info(text)
    }
}

app.use(morgan('combined', { stream: myStream }));

This solution was hived from this Github page https://github.com/winstonjs/winston/issues/1385. However, it is important to note that there is a slight difference between our codes. Instead of:

app.use(morgan('combined', { myStream }));

I use:

app.use(morgan('combined', { stream: myStream }));

This helped me out as am not too big on creating classes.

Solution 6 - node.js

Inspired by this question, this is my easily customizable logger.

import * as winston from "winston";
import * as morgan from "morgan";

export const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      level: 'debug',
      handleExceptions: true,
      format: winston.format.combine(
        winston.format.timestamp({ format: 'HH:mm:ss:ms' }),
        winston.format.colorize(),
        winston.format.printf(
          (info) => `${info.timestamp} ${info.level}: ${info.message}`,
        ),
        //  winston.format.simple(),
      ),
    }),
  ],
  exitOnError: false,
});

if (process.env.NODE_ENV === "dev") {
  logger.add(
    new winston.transports.File({
      level: 'info',
      filename: './logs/all-logs.log',
      handleExceptions: true,
      format: winston.format.combine(
        winston.format.timestamp({
          format: 'YYYY-MM-DD HH:mm:ss',
        }),
        winston.format.errors({ stack: true }),
        winston.format.printf(
          (info) => `${info.timestamp} ${info.level}: ${info.message}`,
        ),
        // winston.format.splat(),
        // winston.format.json()
      ),
      maxsize: 5242880, //5MB
      maxFiles: 5,
    }));
}
logger.info("logging started");

app.use(morgan(function (tokens, req, res) {
    const msg = [
        tokens.method(req, res),
        tokens.url(req, res),
        tokens.status(req, res),
        tokens.res(req, res, 'content-length'), '-',
        tokens['response-time'](req, res), 'ms',
    ].join(' ');
    logger.http(msg);
    return null;
    // return msg;
})
);

sample output

# console
16:32:30:3230 http: GET /users/614daca689f8773a247af93d 200 417 - 1087.858 ms 

# file 
2021-09-24 16:40:08 http: GET /users/614daca689f8773a247af93d 200 417 - 856.263 ms

Solution 7 - node.js

Simplest way for logging data into files in nodejs backend @grdon/logger

Here is example

 const logger = require('@grdon/logger')({
  defaultLogDirectory : __dirname + "/myLogDir",
})
// ...

logger(arg1, 'logfile1.log')
logger([arg1, arg2 ,...], 'lofgfile2.log')

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOr SmithView Question on Stackoverflow
Solution 1 - node.jslindsaymacveanView Answer on Stackoverflow
Solution 2 - node.jsMahyar SEPEHRView Answer on Stackoverflow
Solution 3 - node.jsJohnnyView Answer on Stackoverflow
Solution 4 - node.jsuser566245View Answer on Stackoverflow
Solution 5 - node.jsCris ShakiView Answer on Stackoverflow
Solution 6 - node.jsAli80View Answer on Stackoverflow
Solution 7 - node.jsKandratView Answer on Stackoverflow