日志实践
虽然 console 支持 log、info、warn、error、debug 等方法,但它们只能输出日志到标准输出、标准错误。相当于实际只有 log、error 两个日志等级,需要开发以进一步细分。
使用日志框架如 winston、log4js,可以满足日志实践中的多数需求。
winston
winston 旨在成为支持多种传输的简单通用日志记录库,但它的API用法一点都不简单。
自定义日志实例,将日志打印到控制台
jsconst { createLogger, transports } = require("winston") const logger = createLogger({ transports: [new transports.Console()], // 将日志打印到控制台 }) logger.info('logger info') logger.log({ level: 'info', message: 'logger log info' })
控制台输出:
json{"level":"info","message":"logger info"} {"level":"info","message":"logger log info"}
自定义日志实例,将日志输出到文件
jsconst { createLogger, transports, format } = require("winston") const { combine, label, timestamp, json } = format const logger = createLogger({ format: combine( label({label: 'this is label'}), // 附加内容 timestamp(), // 附加时间戳 json() // 按json输出 ), // 输出到文件 transports: [new transports.File({ filename: 'test.log' })], }) logger.info('logger info') logger.log({ level: 'info', message: 'logger log info' })
执行后 test.log 文件内容
json{"label":"this is label","level":"info","message":"logger info","timestamp":"2023-10-01T12:10:25.416Z"} {"label":"this is label","level":"info","message":"logger log info","timestamp":"2023-10-01T12:10:25.417Z"}
日志格式化输出
jsconst { createLogger, format, transports } = require('winston') const { combine, timestamp, label, printf } = format const logger = createLogger({ format: combine( label({ label: 'right meow!' }), timestamp(), printf(({ level, message, label, timestamp }) => { return `${timestamp} [${label}] ${level}: ${message}` }) ), transports: [new transports.Console()], }) logger.info('This is formatted message')
控制台输出:
2023-10-01T12:27:40.887Z [right meow!] info: This is formatted message
自动记录未捕获的错误
jscreateLoggler({ exceptionHandlers: [new transports.File({ filename: "exceptions.log" })], rejectionHandlers: [new transports.File({ filename: "rejections.log" })], })
exceptions.log
将记录 uncaughtException 事件捕获的错误,rejections.log
将记录 unhandledRejection 事件捕获的错误, 它们都以createLoggler
配置的格式输出。
log4js
log4js 是一个开箱即用的日志记录器。
开箱即用
jsconst log4js = require('log4js') const logger = log4js.getLogger() logger.level = 'debug' // 指定 logger 可记录的最高日志级别,默认为最低 off 不记录。 logger.info('logger info')
控制台输出:
[2023-10-01T21:34:45.864] [INFO] default - logger info
将日志输出到控制台和文件
jsconst log4js = require('log4js') log4js.configure({ appenders: { stdout: { type: 'stdout' }, file: { type: 'file', filename: 'test.log' }, }, categories: { default: { appenders: ['stdout', 'file'], level: 'trace', }, }, }) const logger = log4js.getLogger() logger.info('logger info')
控制台和文件有相同的输出
[2023-10-01T21:35:38.844] [INFO] default - logger info
日志格式化输出 将日志通过自定义布局,格式化为 json 输出
jsconst log4js = require('log4js') log4js.addLayout('json', function (config) { return function (logEvent) { return JSON.stringify({ timestamp: logEvent.startTime, level: logEvent.level.levelStr, message: logEvent.data.join(', '), }) } }) log4js.configure({ appenders: { stdout: { type: 'stdout', layout: { type: 'json' } }, }, categories: { default: { appenders: ['stdout'], level: 'trace', }, }, }) const logger = log4js.getLogger() logger.info('logger info')
控制台输出:
json{"timestamp":"2023-10-01T13:46:57.804Z","level":"INFO","message":"logger info"}
log4js 相比 winston 有着更适合 JS 开发者的 API,相对轻量(Unpacked Size:160 kB < 268 kB),推荐使用。