← Home

Adding a timestamp and additional fields to log entries with Winston for Node.js

AWS Lambda functions can simply log messages to the console, where they appear in CloudWatch Logs shortly afterwards.

One of the nice features of AWS CloudWatch, is that you can then configure metrics to be extracted from the logs. Unlike Splunk, CloudWatch only supports space delimited metrics, or JSON, so it makes it much easier if you use JSON logging:

  • How many milliseconds something took: { "operation_time_taken_ms": 200 }
  • An event happened: { "login_event": 1 }

In Go, I use logrus for this, in .NET Serilog does the trick.

For Node.js, I’m using winston, but the documentation doesn’t include how to add additional values to the JSON output, or how to add a timestamp.

The timestamp isn’t really required when you’re output CloudWatch logs with a Lambda, because the ingestion time is tracked, but if you extract the logs later, you’ll lose it.

winston doesn’t include a timestamp by default(!), so you need to customise the log format.

Here’s my take on doing that in winston 3.0-rc1:

const winston = require('winston');
const MESSAGE = Symbol.for('message');

const jsonFormatter = (logEntry) => {
  const base = { timestamp: new Date() };
  const json = Object.assign(base, logEntry)
  logEntry[MESSAGE] = JSON.stringify(json);
  return logEntry;
}

const logger = winston.createLogger({
  level: 'info',
  format: winston.format(jsonFormatter)(),
  transports: new winston.transports.Console(),
});

logger.info('message content', { "context": "index.js", "metric": 1 })
logger.info('message content 2')