log4js 是一个功能强大且灵活的日志记录库,专为 nodejs 应用程序设计。它提供了丰富的日志记录功能和配置选项。log4js 支持多种日志输出方式(如控制台、文件、数据库等),并且可以根据日志级别进行过滤和格式化。
log4js 的官网链接: https://log4js-node.github.io/log4js-node/index.html
1. 主要特性
- 多种日志输出方式:
- 控制台输出:将日志输出到控制台。
- 文件输出:将日志写入文件,支持文件轮转。
- 数据库输出:将日志存储到数据库中。
- HTTP 输出:将日志发送到远程服务器。
- 日志级别(日志级别从低到高依次为)
ALL:记录所有日志。TRACE:记录细粒度的信息事件,比DEBUG级别更详细。DEBUG:记录细粒度的信息事件,用于调试应用程序。INFO:记录一般信息事件,突出应用程序的进展。WARN:记录潜在的有害情况。ERROR:记录错误事件,但应用程序仍可继续运行。FATAL:记录非常严重的错误事件,通常会导致应用程序中止。MARK:标记级别,通常不用于日志记录,但可以用于标记日志中的特定点。OFF:关闭日志记录
- 日志格式化:
- 支持自定义日志格式,可以根据需要格式化日志输出。
- 提供多种内置格式化选项,如
basic、coloured、json等。
- 配置灵活:
- 支持通过代码或配置文件进行配置。
- 可以动态更新配置,无需重启应用程序。
2. 安装方法
要在你的 Node.js 项目中使用 log4js,可以通过 npm 进行安装:
npm install log4js
3. 基本用法
以下是一个简单的示例,展示了如何在 Node.js 应用程序中使用 log4js:
const log4js = require('log4js');
// 配置 log4js
log4js.configure({
appenders: {
console: { type: 'console' },
file: { type: 'file', filename: 'logs/app.log' }
},
categories: {
default: { appenders: ['console', 'file'], level: 'debug' }
}
});
const logger = log4js.getLogger();
// 记录不同级别的日志
logger.trace('这是一个 TRACE 级别的日志'); // 这个日志不会被记录,因为 trace 比 debug 级别低
logger.debug('这是一个 DEBUG 级别的日志');
logger.info('这是一个 INFO 级别的日志');
logger.warn('这是一个 WARN 级别的日志');
logger.error('这是一个 ERROR 级别的日志');
logger.fatal('这是一个 FATAL 级别的日志');
4. log4js 中的术语
- 级别(level)
- 类别 (category)
- 附加器(appender)
- 日志记录器(logger)
- 日志事件(LogEvent)
级别(level) – 日志级别是日志事件(调试、信息等)的严重性或优先级。附加器是否会看到事件取决于类别的级别。如果该级别小于或等于事件的级别,则事件将被发送到类别的附加器。
类别 (category) – 用于对日志事件进行分组的标签。这可以基于模块(例如“auth”、“payment”、“http”)或任何您喜欢的模块。具有相同类别的日志事件将发送到相同的附加器。Log4js 支持类别的层次结构,使用点来分隔层 – 例如,如果“myapp.submodule”未定义任何附加器,则“myapp.submodule”类别中的日志事件将使用“myapp”的级别,并且还将使用为“myapp”定义的任何附加器。 (可以通过在子类别上设置 inherit=false 来禁用此行为。)当您从 log4js (log4js.getLogger(‘somecategory’)) 获取 Logger 时,将定义日志事件的类别。
附加器(appender) – 附加器负责输出日志事件。它们可能会将事件写入文件、发送电子邮件、将其存储在数据库中或执行任何其他操作。大多数附加器使用布局将事件序列化为字符串以供输出。
日志记录器(logger) – 这是您的代码与 log4js 的主要接口。记录器实例可能有一个可选类别,在您创建实例时定义。记录器提供创建 LogEvents 并将其传递给附加器的信息、调试、错误等函数。
布局(layout) – 用于将 LogEvent 转换为字符串表示的函数。Log4js 提供了几种不同的实现:基本、彩色和更可配置的基于模式的布局。
日志事件(LogEvent) – 日志事件具有时间戳、级别和可选类别、数据和上下文属性。当您调用 logger.info(‘cheese value:’, edam) 时,记录器将创建一个日志事件,其中包含现在的时间戳、INFO 级别、创建记录器时选择的类别以及具有两个值(字符串“cheese value:”和对象“edam”)的数据数组,以及添加到记录器的任何上下文数据。
5. 自定义 layout
const log4js = require("log4js");
// json 形式输出
log4js.addLayout("json", function (config /* type: json 对应的layout的配置 */) {
return function (logEvent) {
return JSON.stringify(logEvent) + config.separator;
};
});
log4js.configure({
appenders: {
out: { type: "stdout", layout: { type: "json", separator: "," } },
},
categories: {
default: { appenders: ["out"], level: "info" },
},
});
const logger = log4js.getLogger("json-test");
logger.info("this is just a test");
logger.error("of a custom appender");
logger.warn("that outputs json");
6. 日志优先级的注意点
比如使用了 ERROR 级别,那么比 ERROR 级别低的级别不会被记录,INFO, WARN 这些方法输出时,不会打到日志库中
7. log4js 适配 nestjs 的 common logger
如果要使用 log4js 作为 nestjs 的日志记录器, logger 不但可以输出到控制台,还可以记录日志到文件中,或者网络传输日志 等
一般在初始化 app.module.ts 后,使用自定义的 Logger 替换 @nestjs/common 的 Logger
import { Injectable, LoggerService } from '@nestjs/common';
import { Logger } from 'log4js';
@Injectable()
export class Log4jsLogger implements LoggerService {
constructor(private readonly logger: Logger) {}
updateContext(context?: string) {
if (context && context.length > 0) {
this.logger.addContext('name', context);
} else {
this.logger.addContext('name', '');
}
}
verbose(message: any, context?: string) {
this.updateContext(context);
this.logger.trace(message);
}
debug(message: any, context?: string) {
this.updateContext(context);
this.logger.debug(message);
}
log(message: any, context?: string) {
this.updateContext(context);
this.logger.info(message);
}
warn(message: any, context?: string) {
this.updateContext(context);
this.logger.warn(message);
}
error(message: any, trace?: string, context?: string) {
this.updateContext(context);
this.logger.error(message, trace);
}
static getTimestamp() {
const localeStringOptions = {
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
day: '2-digit',
month: '2-digit',
} as const;
return new Date(Date.now()).toLocaleString(undefined, localeStringOptions);
}
getTimestamp() {
return Log4jsLogger.getTimestamp();
}
}