This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

The best implementation guidelines for logging were introduced earlier in the Node.js Logging Best Practices Guide. This article will use the Winston library to build a simple logging feature.

Winston is one of the powerful and flexible Node.js open source logging libraries. In theory, Winston is a logger that can record everything. This is a highly intuitive tool that is easy to customize. You can tweak the logic behind it by changing a few lines of code. It makes it easy to log persistent storage locations such as databases or files.

Winston provides the following features:

  • Centralize control over how and when logging occurs: just change the code in one place
  • Control where logs are sent: Synchronously save logs to multiple destinations (such as Elasticsearch, MongoDB, Postgres, etc.).
  • Custom log format: prefix with timestamp, color log level, JSON format, etc.

Winston practice

The practice code will add logging functionality to the project pretender-service, installing dependencies:

npm install winston --save
Copy the code

Initialize logger. Since a logger.js file already exists in the project, create winstonLogger.js as follows:

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

module.exports = createLogger({
    transports: [
        new transports.File({
            filename: "logs/server.log",
            level: "info",
            format: format.combine(
                format.timestamp({ format: "MMM-DD-YYYY HH:mm:ss" }),
                format.align(),
                format.printf(
                    (info) =>
                        `${info.level}: ${[info.timestamp]}: ${info.message}`
                )
            ),
        }),
    ],
});
Copy the code

Initialize the logger by calling the createLogger function from the Winston library. In a TranSports object, you can provide a file name to store the log in the file. By default, logging is unformatted and printed as a JSON string with two parameters, the log message and the rank.

The following changes will be made to the previous logger, and Winston will be added to the logger. See the code for details of how to modify the logger and how to use it:

const winlogger = require("./winstonLogger"); Winlogger. info(" log content ");Copy the code

After executing the program, the corresponding log file logs/server.log can be generated in the root directory

You can also change the log level, modify logger, and use Winston only in console.error mode:

Database connection error messages are logged, and the above information is for demonstration purposes only.

Many transports

Winston allows multiple transport Settings. In WinstonLogger. js change the createLogger function as follows:

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

module.exports = createLogger({
    format: format.combine(
        format.timestamp({ format: "MMM-DD-YYYY HH:mm:ss" }),
        format.align(),
        format.printf((i) => `${i.level}: ${[i.timestamp]}: ${i.message}`)
    ),
    transports: [
        new transports.File({
            filename: "logs/info.log",
            level: "info",
            format: format.combine(
                format.printf((i) =>
                    i.level === "info"
                        ? `${i.level}: ${i.timestamp} ${i.message}`
                        : ""
                )
            ),
        }),
        new transports.File({
            filename: "logs/error.log",
            level: "error",
        }),
    ],
});
Copy the code

Log and info.log files. Since info is not set in Logger, the contents of info.log are empty and the contents of error.log are the same as above.

Multiple loggers

Winston allows you to set up multiple loggers, in a real project you can create one logger per module, with the following code to create a user logger and login verification logger:

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

const customFormat = format.combine(
    format.timestamp({ format: "MMM-DD-YYYY HH:mm:ss" }),
    format.align(),
    format.printf((i) => `${i.level}: ${[i.timestamp]}: ${i.message}`)
);

const globalLogger = createLogger({
    format: customFormat,
    transports: [
        new transports.File({
            filename: "logs/info.log",
            level: "info",
            format: format.combine(
                format.printf((i) =>
                    i.level === "info"
                        ? `${i.level}: ${i.timestamp} ${i.message}`
                        : ""
                )
            ),
        }),
        new transports.File({
            filename: "logs/error.log",
            level: "error",
        }),
    ],
});

const authLogger = createLogger({
    transports: [
        new transports.File({
            filename: "logs/authLog.log",
            format: customFormat,
        }),
    ],
});

module.exports = {
    globalLogger: globalLogger,
    authLogger: authLogger,
};
Copy the code

This code creates a globalLogger and an authentication logger, corresponding to logger.js:

const { globalLogger } = require("./winstonLogger");
globalLogger.error(message);
Copy the code

Daily scroll log files

As mentioned in the best practices described earlier, log files are split based on specific criteria, usually by date, size, and set the number of days the logs are saved. To implement these requirements, there will be an installation of a Winston dependent library.

npm install winston-daily-rotate-file --save
Copy the code

After installation, update the winstonLogger.js file with the following code:

const { createLogger, format, transports } = require("winston");
require("winston-daily-rotate-file");

const customFormat = format.combine(
    format.timestamp({ format: "MMM-DD-YYYY HH:mm:ss" }),
    format.align(),
    format.printf((i) => `${i.level}: ${[i.timestamp]}: ${i.message}`)
);
const defaultOptions = {
    format: customFormat,
    datePattern: "YYYY-MM-DD",
    zippedArchive: true,
    maxSize: "20m",
    maxFiles: "14d",
};
const globalLogger = createLogger({
    format: customFormat,
    transports: [
        new transports.DailyRotateFile({
            filename: "logs/info-%DATE%.log",
            level: "info",
            ...defaultOptions,
        }),
        new transports.DailyRotateFile({
            filename: "logs/error-%DATE%.log",
            level: "error",
            ...defaultOptions,
        }),
    ],
});

const authLogger = createLogger({
    transports: [
        new transports.DailyRotateFile({
            filename: "logs/authLog-%DATE%.log",
            ...defaultOptions,
        }),
    ],
});

module.exports = {
    globalLogger: globalLogger,
    authLogger: authLogger,
};
Copy the code

Run the project and you can see the log file:

Now that Winston’s basic usage guide is out of the way, this should be enough for everyday projects.