log4js的食用方式整理


log4js 是 NodeJS 广泛使用的日志处理模块,包括但不限于:日志分类、日志分级、日志输出等功能。

起步

1
2
3
4
5
6
// test.ts
import {getLogger, Logger} from "log4js";

const logger: Logger = getLogger();
logger.level = "all";
logger.info(`当前时间戳: [${new Date().getTime()}]`);

调用getLogger方法获取Logger实例,用于设置分级、输出日志等操作。
通过level设置日志分级,在后文会提及。

运行 test.ts,输出结果:

1
[2022-04-03T09:04:33.398] [INFO] default - 当前时间戳: [1648947873398]

日志分级 level

1
logger.level = "trace";

log4js 有九个分级, 不同分级的输出颜色不同更容易区分,分级名称及权重见下图。

log4js level分级

如图,设置日志分级来使得 log4js 来确定过滤掉哪些日志的输出,在使用日志时则自动为该条日志定义了分级。
当level设置为debug时,debug以下(包括debug)均会输出。

1
2
3
4
5
6
7
8
import {getLogger, Logger} from "log4js";

const logger: Logger = getLogger();
logger.level = "debug";

logger.trace("这是一条等级为 trace 的日志");
logger.debug("这是一条等级为 debug 的日志");
logger.error("这是一条等级为 error 的日志");

输出结果:

1
2
[2022-04-03T09:45:15.954] [DEBUG] default - 这是一条等级为 debug 的日志
[2022-04-03T09:45:15.956] [ERROR] default - 这是一条等级为 error 的日志

可见等级为 trace 的日志并未打印。

目前log4js的默认level是off,即不输出任何日志,因此起步代码中存在一行代码来使得日志得以输出:

1
logger.level = "all";

日志类型 category

除了 level 可以对日志输出进行区分以外,log4js 还存在 category(类型) 来对日志进行区分。
在创建 Logger 对象时,允许传入一个 参数 来定义通过该对象所输出的日志的 category。

1
2
3
4
5
6
import {getLogger, Logger} from "log4js";

const logger: Logger = getLogger("MARRY");
logger.level = "debug";

logger.info("MARRY类型的日志");

输出结果:

1
[2022-04-03T09:50:28.938] [INFO] MARRY - MARRY类型的日志

可见之前输出结果中的 default 变成了 MARRY。在 log4js 中,日志默认的 category 就是 default。

category 和 level 一样,也可以用作日志的过滤输出,这点将在后面讲到,这里只写一个简单的过滤案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import {configure, getLogger, Logger} from "log4js";

configure({
appenders: {
console: {type: "console"}
},
categories: {
default: {appenders: ["console"], level: "off"},
MARRY: {appenders: ["console"], level: "debug"}
}
});

const loggerDefault: Logger = getLogger();
const loggerMarry: Logger = getLogger("MARRY");
const loggerSeto: Logger = getLogger("SETO");

loggerDefault.info("default类型的info日志");
loggerMarry.trace("MARRY类型的trace日志");
loggerMarry.info("MARRY类型的info日志");
loggerSeto.info("SETO类型的info日志");

输出结果:

1
[2022-04-03T10:04:00.838] [INFO] MARRY - MARRY类型的info日志

可见其他三条都未输出,其中 default 类型的 level 被设置了 off,即不输出日志;MARRY 类型 的 level 为 debug,trace 分级的日志被过滤,而 SETO 类型不在允许输出的列表中,不会输出。

日志输出 Appender

Appender 主要用于解决日志输出到哪里的问题,通过 configure 来配置 appender。

下面是 log4js 目前的默认配置,默认使用的 appender 为 stdout

1
2
3
4
5
6
7
// log4js.js
configure(
{
appenders: {out: {type: "stdout"}},
categories: {default: {appenders: ["out"], level: "OFF"}}
}
);

log4js 提供了一些内置的 appender,这里只解释几个常见的,详见文档

1
2
3
4
5
stdout   # 标准输出流(默认)
console # 输出到当前节点的控制台,仅建议开发环境使用,线上大量输出可能会卡顿
file # 输出到文件
dateFile # 输出到日期滚动文件,如 default-2022-04-03.log、default-2022-04-04.log
tcp # 输出到指定服务器的指定端口

内置 appender 的使用与配置

内置的 appender 都存在默认配置,可以直接拿来使用,仅指定一个 type 即可:

1
2
3
4
5
6
7
8
9
10
import {configure} from "log4js";

configure({
appenders: {
console: {type: "dateFile"}
},
categories: {
// ...
}
});

也可以根据个人需求修改配置项进行定制,各 appender 的配置项详见文档

下面这个案例定义了两个输出,一个采用默认配置输出到控制台,另一个则自定义配置输出到滚动日志文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import {configure} from "log4js";

configure({
appenders: {
console: {type: "console"},
logFile: {
type: "dateFile",
filename: "logs/marry", // 文件名
pattern: "yyyy-MM-dd.log", // 文件名后缀
alwaysIncludePattern: true, // 每个文件都会按pattern命名,否则最新的文件不会按照pattern命名
layout: {type: "JSON"} // 采用名为 JSON 的自定义输出格式,下面会讲
}
},
categories: {
// ...
}
})

布局的使用也很简单,直接在 configure 的另一个必需属性 categories 里指定即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import {configure} from "log4js";

configure({
appenders: {
logFile: {
// ...
}
},
categories: {
cateA: {
appenders: ["logFile"], // 使用名为 logFile 的 appender
level: "debug"
}
}
})

输出格式 Layout

Layout 是 Appender 用来格式化输出日志的函数,以参数事件作为参数,并返回一个字符串。

log4js 内置了五种布局,详见文档,分别如下:

1
2
3
4
5
basic               # 为默认布局,将输出时间戳、级别、类别,和格式化的日志事件数据
coloured/colored # console 和 stdout 的默认格式,在 basic 的基础上根据日志类型添加了不同颜色
messagePassThrough # 仅输出日志的内容
dummy # 仅输出日志时间的第一个传参内容
pattern # 通过 pattern 字段自定义输出内容

自定义 layout 的添加与使用

使用 addLayout(type, fn) 方法添加自己的 Layout。

参数

  • type: Layout 名称
  • fn: 方法返回一个返回值为字符串的布局函数

下面的示例将创建一个名为JSON的Layout:

1
2
3
4
5
6
7
8
9
import {addLayout} from "log4js";

addLayout("JSON", config => event => JSON.stringify({
category: event.categoryName,
level: event.level.levelStr,
color: event.level.colour,
message: event.data[0],
time: event.startTime
}));

使用所创建的名为 JSON 的 Layout:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import {addLayout, configure, getLogger, Logger} from "log4js";

addLayout("JSON", config => event => JSON.stringify({
category: event.categoryName,
level: event.level.levelStr,
color: event.level.colour,
message: event.data[0],
time: event.startTime
}));

configure({
appenders: {
console: {
type: "console",
layout: {type: "JSON"} // 采用名为 JSON 的自定义输出格式
}
},
categories: {
default: {appenders: ["console"], level: "debug"}
}
})

const logger: Logger = getLogger();
logger.info("JSON布局测试");

输出结果:

1
{"category":"default","level":"INFO","color":"green","message":"JSON布局测试","time":"2022-04-03T03:56:14.428Z"}

后记

果然还是要自己整理一遍笔记才能思路通畅,如果只是单纯理解看懂貌似会用就抛之脑后,结果一定是仅仅懂个皮毛了事,可能过几天就会忘光了罢()

ps:这就是你带薪上班花一上午没干正事的理由?