8754. Logging with WinstonExpress and Winston
Introduce how to use Winston for logging in express server.
1. Winston
Winston a versatile async logging library for Node.js.
1.1 Logging Levels
Winston provides the following default log levels. They are prioritized from 0 to 5 (highest to lowest)
const levels = { error: 0, warn: 1, info: 2, verbose: 3, debug: 4, silly: 5 }
You can pass a string representing the logging level to the log() method or use the level specified methods defined on every winston logger.
logger.log('info', "hello world!");
logger.log('error', "Ops, you got an error!");
// equivalent to
logger.info("hello world!");
logger.error("Ops, you got an error!");
// same output
// info: hello world!
// error: Ops, you got an error!
1.2 Transports
A transport is essentially a storage device for your logs. Each Winston logger can have multiple transports configured at different levels. Winston provides two default transports, Console and File.
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'combined.log' })
]
1.3 Multiple Transports of Same Type
It is possible to use multiple transports of the same type e.g. winston.transports.File when you construct the transport.
const logger = winston.createLogger({
transports: [
new winston.transports.File({
filename: 'combined.log',
level: 'info'
}),
new winston.transports.File({
filename: 'errors.log',
level: 'error'
})
]
});
2. Examples
2.1 Print Logs to Console
Create winston logger.
//winston-config-console.js
var path = require("path");
var winston = require("winston");
const logger = winston.createLogger({
transports: [
new winston.transports.Console({
colorize: true
})
]
});
module.exports = logger;
Express server.
// server.js
var express = require("express");
var logger = require("./config/winston-config-console");
var app = express();
app.get("/", function(req, res) {
logger.info("Hello world");
res.send("hello, world!");
});
app.use(function(req, res) {
logger.error("File not found");
res.status(404).send("File not found!");
});
app.listen(3000, function() {
console.log("Web Server started on port 3000");
});
Start the server and access http://localhost:3000/ and http://localhost:3000/random in browser. You should see the output in console.
Web Server started on port 3000
{"message":"File not found","level":"error"}
{"message":"Hello world","level":"info"}
Add format to transport.
const logger = winston.createLogger({
transports: [
new winston.transports.Console({
format: winston.format.simple(),
colorize: true
})
]
});
Try to access those two URLs again. This time you would see the following logs.
Web Server started on port 3000
info: Hello world
error: File not found
2.2 Write Logs to File
Create another winston logger.
//winston-config-file.js
var path = require("path");
var fs = require("fs");
var appRoot = require("app-root-path");
var winston = require("winston");
// ensure log directory exists
var logDirectory = path.resolve(`${appRoot}`, "logs");
fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory);
var options = {
infofile: {
level: "info",
filename: path.resolve(logDirectory, "info.log"),
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB
maxFiles: 5
},
errorfile: {
level: "error",
filename: path.resolve(logDirectory, "error.log"),
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB
maxFiles: 5
}
};
const logger = winston.createLogger({
transports: [
new winston.transports.File(options.infofile),
new winston.transports.File(options.errorfile)
]
});
module.exports = logger;
Update server.js with the new winston logger.
// server.js
var express = require("express");
//var logger = require("./config/winston-config-console");
var logger = require("./config/winston-config-file");
...
Start the server and access http://localhost:3000/ and http://localhost:3000/random in browser. This time you won’t see any log in console. Instead, you should see the following logs in ./logs/error.log.
{"message":"File not found","level":"error"}
And the following logs in ./logs/info.log
{"message":"Hello world","level":"info"}
{"message":"File not found","level":"error"}
Notice that, the error log is also recorded. This is because, for level ‘info’, all level value less or equals 2 will be logged. Logs for level ‘error: 0’, ‘warn: 1’ and ‘info: 2’ are all saved to this file.
2.3 Log File Rotation
Winston supports to log rotation by winston-daily-rotate-file
. The DailyRotateFile transport can rotate files by minute, hour, day, month, year or weekday.
//winston-config-rotate.js
var path = require("path");
var fs = require("fs");
var appRoot = require("app-root-path");
var winston = require("winston");
require("winston-daily-rotate-file");
// ensure log directory exists
var logDirectory = path.resolve(`${appRoot}`, "logs");
fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory);
var transport = new winston.transports.DailyRotateFile({
filename: path.resolve(logDirectory, "application-%DATE%.log"),
datePattern: "YYYY-MM-DD-HH",
zippedArchive: true,
maxSize: "20m",
maxFiles: "14d" // keep logs for 14 days
});
transport.on("rotate", function(oldFilename, newFilename) {
// do something fun
});
const logger = winston.createLogger({
transports: [transport]
});
module.exports = logger;
Update server.js with the new winston logger.
// server.js
var express = require("express");
//var logger = require("./config/winston-config-console");
//var logger = require("./config/winston-config-file");
var logger = require("./config/winston-config-rotate");
...
Start the server then access http://localhost:3000/ and http://localhost:3000/random in browser. You would see multiple log files in directory ./logs. Each file name has the format ‘application-YYYY-MM-DD-HH.log’. From the following screenshot, we see multiple log files are created from 11:00 to 16:00 on Jan 08, 2018.