128

I want to add timestamp to logs.

What is the best way to achieve this?

Thanks.

Jerry Chong
  • 7,954
  • 4
  • 45
  • 40
kolrie
  • 12,562
  • 14
  • 64
  • 98

9 Answers9

141

Above answers did not work for me. In case you are trying to add timestamp to your logs using the latest version of Winston - 3.0.0-rc1, this worked like charm:

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

    const logger = createLogger({
        format: format.combine(
            format.timestamp(),
            format.json()
        ),
        transports: [
            new transports.Console(),
            new transports.File({filename: 'logs/error/error.log', level: 'error'}),
            new transports.File({filename: 'logs/activity/activity.log', level:'info'})
        ]
    });

I used 'format.combine()'. Since I needed timestamp on all my transports, I added the formatting option within the createLogger, rather than inside each transport. My output on console and on file (activity.log) are as follows:

{"message":"Connected to mongodb","level":"info","timestamp":"2018-02-01T22:35:27.758Z"}
{"message":"Connected to mongodb","level":"info","timestamp":"2018-02-01T22:35:27.758Z"}

We can add formatting to this timestamp in 'format.combine()' as usual using:

format.timestamp({format:'MM-YY-DD'})
Siva Kiran
  • 1,817
  • 1
  • 12
  • 8
120

I was dealing with the same issue myself. There are two ways I was able to do this.

When you include Winston, it usually defaults to adding a Console transport. In order to get timestamps to work in this default case, I needed to either:

  1. Remove the console transport and add again with the timestamp option.
  2. Create your own Logger object with the timestamp option set to true.

The first:

var winston = require('winston');
winston.remove(winston.transports.Console);
winston.add(winston.transports.Console, {'timestamp':true});

The second, and cleaner option:

var winston = require('winston');
var logger = new (winston.Logger)({
    transports: [
      new (winston.transports.Console)({'timestamp':true})
    ]
});

Some of the other options for Console transport can be found here:

  • level: Level of messages that this transport should log (default 'debug').
  • silent: Boolean flag indicating whether to suppress output (default false).
  • colorize: Boolean flag indicating if we should colorize output (default false).
  • timestamp: Boolean flag indicating if we should prepend output with timestamps (default false). If function is specified, its return value will be used instead of timestamps.
Wilfred Springer
  • 10,869
  • 4
  • 55
  • 69
imagreenplant
  • 1,348
  • 1
  • 8
  • 3
  • 1
    Amazing and simple at the same time. Thank you! – kolrie Apr 27 '12 at 00:50
  • 7
    This is great. I usually wrap this in a dedicated file so that I can easily get my configured logger from any file, i.e., I put the above code (option 2) in a new file logger.js, followed by module.exports = logger; then from any file I do var logger = require('./logger.js') and can then do logger.info('hello') from any file and get the same configuration of Winston. – JHH May 28 '15 at 08:58
  • TypeError: (intermediate value) is not a function – Urasquirrel Jul 24 '19 at 19:37
  • 3
    This does not appear to work in the current version of Winston. Try one of the other answers instead. – AverageHelper Apr 14 '21 at 04:15
36

We can do like this also

var winston = require('winston');
const { createLogger, format, transports } = require('winston');
var config = require('../configurations/envconfig.js');

var loggerLevel = process.env.LOGGERLEVEL ||  config.get('LOGGERLEVEL');

var logger = winston.createLogger({
  format: format.combine(
    format.timestamp({
      format: 'YYYY-MM-DD HH:mm:ss'
    }),
    format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`+(info.splat!==undefined?`${info.splat}`:" "))
  ),
  transports: [
    new (winston.transports.Console)({ level: loggerLevel }),
  ]
});
module.exports = logger;
Ynjxsjmh
  • 28,441
  • 6
  • 34
  • 52
Biswadev
  • 1,456
  • 11
  • 24
  • Does this also work for `logger.info('Message', someObject)`? I setup a custom format using combine and I can't seem to get the `someObject` included in the log message. – SomethingOn Jun 25 '18 at 19:20
  • 2
    I was able to get `someObject` included by using the following printf statement `${info.timestamp} [${info.level.toUpperCase()}]: ${info.message} ${JSON.stringify(info)}`. It includes the level, timestamp and message which I guess I could delete. – SomethingOn Jun 25 '18 at 19:28
10

You can use built-in util and forever to achieve logging with timestap for your nodejs server. When you start a server add log output as part of the parameter:

forever start -ao log/out.log server.js

And then you can write util in your server.js

server.js

var util = require('util');
util.log("something with timestamp");

The output will look something like this to out.log file:

out.log

15 Mar 15:09:28 - something with timestamp
KTU
  • 445
  • 4
  • 16
7

I took Biswadev's answer and created a stringified JSON object. This way if i need to process the logs later it will be in a well structured format.

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

const dotenv = require('dotenv');
dotenv.config();

var logger = createLogger({
    level: 'info',
    format: format.combine(
        format.timestamp({
            format: 'YYYY-MM-DD HH:mm:ss',
        }),
        format.printf((info) =>
            JSON.stringify({
                t: info.timestamp,
                l: info.level,
                m: info.message,
                s: info.splat !== undefined ? `${info.splat}` : '',
            }) + ','
        )
    ),
});

if (process.env.NODE_ENV !== 'PRODUCTION') {
    logger.add(new transports.Console({ format: winston.format.cli() }));

    // Turn these on to create logs as if it were production
    // logger.add(new transports.File({ filename: 'log/output/error.log', level: 'error' }));
    // logger.add(new transports.File({ filename: 'log/output/warn.log', level: 'warn' }));
    // logger.add(new transports.File({ filename: 'log/output/info.log', level: 'info' }));
} else {
    logger.add(new transports.File({ filename: 'log/output/error.log', level: 'error' }));
    logger.add(new transports.File({ filename: 'log/output/warn.log', level: 'warn' }));
    logger.add(new transports.File({ filename: 'log/output/info.log', level: 'info' }));
}

module.exports = {
    logger,
};

Usage:

app.listen(port, () => logger.info(`app is running on port ${port}`));

Output:

info.log file:

{"t":"2020-08-06 08:02:05","l":"info","m":"app is running on port 3001","s":""},

Console:

info:    app is running on port 3001
Steve
  • 4,372
  • 26
  • 37
5

Although I'm not aware of winston, this is a suggestion. I use log4js for logging & my logs by default look like this

[2012-04-23 16:36:02.965] [INFO] Development - Node Application is running on port 8090
[2012-04-23 16:36:02.966] [FATAL] Development - Connection Terminated to  '127.0.0.1' '6379'

Development is the environment of my node process & [INFO|FATAL] is log level

Maintaining different profiles for logging is possible in log4js. I have Development & Production profiles. Also there are logger types like rolling file appender, console appender, etc. As a addon your log files will be colorful based on the log level [Trace, Info, Debug, Error, Fatal] ;)

log4js will override your console.log It is a configurable parameter now in 0.5+

Tamil
  • 5,260
  • 9
  • 40
  • 61
4

we could use console-stamp to add timestamp and log level to the existing console: require('console-stamp')(console, '[yyyy-mm-dd HH:MM:ss.l]')

See https://github.com/starak/node-console-stamp for the details

Arkadiusz Cieśliński
  • 5,307
  • 3
  • 23
  • 19
khoi nguyen
  • 399
  • 2
  • 12
2

Sometimes default timestamp format can be not convenient for you. You can override it with your implementation.

Instead of

var winston = require('winston');
var logger = new (winston.Logger)({
transports: [
  new (winston.transports.Console)({'timestamp':true})
]
});

you can write

var winston = require('winston');
var logger = new (winston.Logger)({
transports: [
  new (winston.transports.Console)({
     'timestamp': function() {
        return <write your custom formatted date here>;
     }
  })
]
});

See https://github.com/winstonjs/winston#custom-log-format for the details

walv
  • 2,680
  • 3
  • 31
  • 36
2

Another solution is wrapping the logger into a file that exports some functions like logger.info(), logger.error(), etc. then you just pass an extra key to be sent on every message log.

loggerService.js

const logger = winston.createLogger({ ... })

function handleLog(message, level) {
  const logData = {
    timestamp: Date.now(),
    message,
  }

  return logger[level](logData)
}

function info(message) {
  handleLog(message, 'info')
}

function error(message) {
  handleLog(message, 'error')
}

function warn(message) {
  handleLog(message, 'warn')
}

module.exports = {
  info,
  error,
  warn
}

whatever-file.js

const logger = require('./services/loggerService')

logger.info('Hello World!')

your-log.log

{"timestamp":"2019-08-21 06:42:27","message":"Hello World!","level":"info"}
Renan Coelho
  • 1,360
  • 2
  • 20
  • 30