最新的 log4j (5.1.0)剖析开篇
Posted 前端新视野
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最新的 log4j (5.1.0)剖析开篇相关的知识,希望对你有一定的参考价值。
log4j 其实本身经历了多个版本的迭代,大部分老项目或者一些教程都是比较老的版本了,最新的版本已经到了 5.1.0
可以查看:https://registry.npmjs.org/log4js。当然,并不代表版本差异会出现很大的问题。
v3 的变化:
https://log4js-node.github.io/log4js-node/v3-changes.md
v2 的变化:
https://github.com/log4js-node/log4js-node/blob/master/v2-changes.md
API 使用其实比较简单,一开始呢,出现了:
最外层:
configure
getLogger
configure 里面:这两个后面我们会重点一个一个介绍和剖析
appenders
categories
基本的使用方法很简单,如下:
调用了顶层的 getLogger,没有传入参数
var log4js = require('log4js');
var logger = log4js.getLogger();
logger.debug("Noderjs debug messages in 新视野");
我们发现是不会产生任何日志,我们修改一下:
logger.level = 'debug';
设置了 level 为 debug,就输出了以下日志:
[default - Noderjs debug messages in 新视野 ] [DEBUG]
我们再修改一下:
var logger = log4js.getLogger('odin');
对应的日志变化了:
[in 新视野 ] [DEBUG] odin - Noderjs debug messages
我们对比一下,发现日志分几步:
[2019-09-10T23:33:04.957]
[DEBUG]
odin
Noderjs debug messages in 新视野
一共 4 个部分:
当前日期
类型 ==> logger.debug 调用了 debug 方法
getLogger 的参数
真正的日志内容 ==> logger.debug 函数里面的
顺着上面,我们来解释一下:
为什么不设置 logger.debug 就不会出现任何日志?
原因就在顶层的 getLogger 函数内部:
function getLogger(category) {
configure({
appenders: {
out: {
type: "stdout"
}
},
categories: {
default: {
appenders: ["out"],
level: "OFF"
}
}
})
}
默认情况下: level 对应的是 OFF。
level 其实也是 log4j 或者说日志框架里面一个比较核心的概念。
在 libs/levels.js 版本为最新版本 5.1.0,我们可以看到:
class Level {
constructor(level, levelStr, colour) {
this.level = level;
this.levelStr = levelStr;
this.colour = colour;
}
static getLevel(sArg, defaultLevel) {}
static addLevels(customLevels) {}
isEqualTo(otherLevel) {}
isGreaterThanOrEqualTo(otherLevel) {}
isLessThanOrEqualTo(otherLevel) {}
}
内置的 level 分为以下:
ALL
TRACE
DEBUG
INFO
WARN
ERROR
FATAL
MARK
OFF
每一个都有对应的 value,由小到大
一开始定义了一个数组,key 是 levels
然后调用了 addLevels 函数,传入了下面这个对象:
Level.levels = [];
Level.addLevels({
ALL: { value: Number.MIN_VALUE, colour: 'grey' },
TRACE: { value: 5000, colour: 'blue' },
DEBUG: { value: 10000, colour: 'cyan' },
INFO: { value: 20000, colour: 'green' },
WARN: { value: 30000, colour: 'yellow' },
ERROR: { value: 40000, colour: 'red' },
FATAL: { value: 50000, colour: 'magenta' },
MARK: { value: 9007199254740992, colour: 'grey' }, // 2^53
OFF: { value: Number.MAX_VALUE, colour: 'grey' }
});
看看对应的 addLevels 方法:
static addLevels(customLevels) {
if (customLevels) {
const levels = Object.keys(customLevels);
levels.forEach((l) => {
const levelStr = l.toUpperCase();
Level[levelStr] = new Level(
customLevels[l].value,
levelStr,
customLevels[l].colour
);
const existingLevelIndex = Level.levels.findIndex(lvl => lvl.levelStr === levelStr);
if (existingLevelIndex > -1) {
Level.levels[existingLevelIndex] = Level[levelStr];
} else {
Level.levels.push(Level[levelStr]);
}
});
Level.levels.sort((a, b) => a.level - b.level);
}
}
一步一步拆解:
函数:上面调用的 addLevels 就是在这里定义的,所以 customLevels 被赋值了那个大对象
static addLevels(customLevels) {
}
循环:获取对象的所有 keys,这里的 levels 对应的便是:
levels ==> [
'ALL',
'TRACE',
'DEBUG',
'INFO',
'WARN',
'ERROR',
'FATAL',
'MARK',
'OFF' ]
具有源码实现:
const levels = Object.keys(customLevels);
levels.forEach((l) => {})
内部:
会进行 toUpperCase,然后把对应的 value 给 level
const levelStr = l.toUpperCase();
new Level(
customLevels[l].value,
levelStr,
customLevels[l].colour
);
进过排序之后,
Level.levels.sort((a, b) => a.level - b.level);
Level.levels 变成了:
[
Level { level: 5e-324, levelStr: 'ALL', colour: 'grey' },
Level { level: 5000, levelStr: 'TRACE', colour: 'blue' },
Level { level: 10000, levelStr: 'DEBUG', colour: 'cyan' },
Level { level: 20000, levelStr: 'INFO', colour: 'green' },
Level { level: 30000, levelStr: 'WARN', colour: 'yellow' },
Level { level: 40000, levelStr: 'ERROR', colour: 'red' },
Level { level: 50000, levelStr: 'FATAL', colour: 'magenta' },
Level { level: 9007199254740992, levelStr: 'MARK', colour: 'grey' },
Level {
level: 1.7976931348623157e+308,
levelStr: 'OFF',
colour: 'grey' } ]
所以:
level: 'MARK' 的会只打印 mark 的日志
level: 'FATAL' 的会只打印 fatal 和 mark 的日志
我们再看一段日志:
{"startTime":"2019-09-10T16:08:06.242Z",
"categoryName":"json-test","data":["this is just a test"],
"level":{"level":20000,"levelStr":"INFO","colour":"green"},
"context":{},"pid":2719}
相比上面的,日志格式首先有一个比较大的转变:json 格式
我们看一下对应的代码:
log4js.configure({
appenders: {
out: {
type: 'stdout',
layout: { type: 'json', separator: ',' }
}
},
categories: {
default: { appenders: ['out'], level: 'info' }
}
});
这里的 layout 里面的 type 为 json:
我们通过顶层的 addLayout 函数,增加了新的类型 json:
log4js.addLayout('json', config => function (logEvent) {
return JSON.stringify(logEvent) + config.separator;
});
type 设置为:
stderr
stdout
核心点:
process.stdout.write
process.stderr.write
开篇就现在这里介绍把,后面还有哦,记得关注~
以上是关于最新的 log4j (5.1.0)剖析开篇的主要内容,如果未能解决你的问题,请参考以下文章