文章目录
1. 前言
本文将介绍笔者log4j
时的一些笔记,以期协助读者规避一些问题。
2. 使用步骤
2.1 配置logjs
// src/config/log4js.config.js
// 配置应用名(英文)数组,根据配置的应用名,生成 appenders 、categories
const appNames = ['nginx', 'tomcat']
/**
* 内置两种布局:layout:console(针对控制台、终端)、layout:basic(针对文件)
*
* 代码:
require('@/config/log4js.config')
*/
const path = require('path')
const log4js = require('log4js')
const Logger = require('@/logger')
/**
* 添加控制台的简单布局
*/
log4js.addLayout('layout:console', function (config) {
return function (event) {
const { type, message } = event.data[0]
return `${type}: ${message}`
}
})
/**
* 添加基础布局
*/
log4js.addLayout('layout:basic', function (config) {
return function (event) {
return JSON.stringify(event.data[0])
}
})
const log4jsConfig = {
appenders: {
'appender:console': {
type: 'console',
layout: { type: 'layout:console', separator: ',' },
},
},
categories: {
default: {
appenders: ['appender:console'],
level: 'DEBUG',
enableCallStack: false,
},
},
}
for (const appName of appNames) {
const appenderName = `appender:${appName}`
log4jsConfig.appenders[appenderName] = {
type: 'dateFile',
filename: path.join(Logger.getDefaultDirPath(appName), appName),
maxLogSize: Math.pow(1024, 3),
pattern: 'yyyy-MM-dd.txt',
keepFileExt: true,
fileNameSep: '.',
alwaysIncludePattern: true,
backups: 3,
compress: false,
layout: {
type: 'layout:basic',
},
}
log4jsConfig.categories[appName] = {
appenders: [appenderName, 'appender:console'],
level: 'DEBUG',
enableCallStack: false,
}
}
log4js.configure(log4jsConfig)
2.2 log4js
基础类
// src/logger/index.js
// https://github.com/log4js-node/log4js-example/blob/master/config/log4js.json
// https://log4js-node.github.io/log4js-node/file.html
const log4js = require('log4js')
const moment = require('moment')
const path = require('path')
const { OSUtils, CryptoUtils } = require('s-utils')
/**
* @class Logger
* @classdesc 日志基础类
*/
module.exports = class Logger {
static INFO = 'info'
static ERROR = 'error'
static WARN = 'warn'
static DEBUG = 'debug'
/**
* Creates an instance of Logger.
* @param {string} [appName='log4js'] 应用名称(英文)
* @memberof Logger
*/
constructor (appName = 'log4js') {
// 日志信息数组
this.logs = []
// 当前日志的ID
this.id = 0
// log4js实例
this.logger4js = null
// 应用的名称(英文)
this.appName = appName
this.logger4js = this.getLog4jsLogger()
}
/**
* 获取默认日志目录路径
*
* @param {string} appName 应用的名称(英文名)
* @returns {string}
* @memberof Logger
*/
static getDefaultDirPath (appName) {
return path.join(OSUtils.getHomeDirPath(), `logs/${appName}`)
}
/**
* 获取log4js日志实例
*
* @returns {object}
* @memberof Logger
*/
getLog4jsLogger () {
return log4js.getLogger(this.appName)
}
/**
* 获取当前日志数组
*
* @returns {object[]} 当前日志数组
* @memberof Logger
*/
getLogs () {
return this.logs
}
/**
* 清空当前日志数组
*
* @memberof Logger
*/
emptyLogs () {
this.logs.length = 0
}
/**
* 生成日志
*
* @param {string} type 日志类型
* @param {string} message 日志内容
* @param {object} [extraData={}] 额外的数据,json对象
* @returns {object} 日志信息对象
* @memberof Logger
*/
generateLogInfo (type, message, extraData = {}) {
const time = moment().format('YYYY-MM-DD HH:mm:ss')
const logInfo = {
// 取md5值
id: CryptoUtils.md5(`${this.id}-${time}`),
type,
message,
time,
extraData,
}
this.id++
return logInfo
}
/**
* 记录日志
*
* @param {string} type 日志类型
* @param {string} message 日志内容
* @param {object} [extraData={}] 额外的数据,json对象
* @memberof Logger
*/
log (type, message, extraData = {}) {
var _a
// 内容为空时,不展示日志
if (
!((_a =
message === null || message === void 0 ? void 0 : message.trim) ===
null || _a === void 0
? void 0
: _a.call(message))
) {
return
}
const log = this.generateLogInfo(type, message, extraData)
// 类型对应的日志函数为空时,使用info函数
const logFn = this.logger4js[type]
? this.logger4js[type]
: this.logger4js.info
logFn.call(this.logger4js, log)
this.logs.push(log)
}
/**
* 记录常规日志
*
* @param {string} message 日志内容
* @param {object} [extraData={}] 额外的数据,json对象
* @memberof Logger
*/
info (message, extraData = {}) {
this.log(Logger.INFO, message, extraData)
}
/**
* 记录错误日志
*
* @param {string} message 日志内容
* @param {object} [extraData={}] 额外的数据,json对象
* @memberof Logger
*/
error (message, extraData = {}) {
this.log(Logger.ERROR, message, extraData)
}
/**
* 记录警告日志
*
* @param {string} message 日志内容
* @param {object} [extraData={}] 额外的数据,json对象
* @memberof Logger
*/
warn (message, extraData = {}) {
this.log(Logger.WARN, message, extraData)
}
/**
* 记录调试日志
*
* @param {string} message 日志内容
* @param {object} [extraData={}] 额外的数据,json对象
* @memberof Logger
*/
debug (message, extraData = {}) {
this.log(Logger.DEBUG, message, extraData)
}
}
2.3 创建logger
实例
2.3.1 配置log4js
在业务项目的入口文件,配置
log4js
。必须要先配置后使用。
// src/main.js
require('@/config/log4js.config')
2.3.2 创建实例
const logger = new Logger('nginx')
logger.info('This is test info.', { addtional: 'test' })
特别说明:
OSUtils, CryptoUtils
是笔者自己工具库里的工具函数,可根据需要使用其他方式来替换。
2.4 在pm2中使用log4js
步骤:
- 执行:
pm2 install pm2-intercom
- 在
log4js
中配置:
log4js.configure({
appenders: { out: { type: "stdout" } },
categories: { default: { appenders: ["out"], level: "info" } },
pm2: true,
pm2InstanceVar: "INSTANCE_ID",
});
- 在
pm2
中配置:
// 当使用log4js时,需要配置instance_var
instance_var: 'INSTANCE_ID',
具体请查看这里。
3. 常见问题
3.1 按照如上步骤配置log4js
之后,并未如期记录日志
请检查是否使用了类似
webpack
之类的打包工具。如果使用了,再检查Logger
是否适合业务项目一起构建的,如果Logger
类是单独构建的,就会导致所做的配置不会生效。因为按照log4js
的规则,若要对它正确配置,必须要确保配置时和使用时,在运行的时候是同一个log4js
库,如果使用了webpack
并且Logger
类是单独构建的,单独构建的Logger
类里的log4js
和业务项目里的log4js
不是同一个实例,在业务项目里做的配置,就不会生效。