對于一個應用程序來說,日志記錄是非常重要的。日志可以幫助開發人員快速定位線上問題,定制解決方案;日志中包含大量用戶信息,通過日志分析還可以獲取用戶行為、興趣偏好等信息,通過這些信息可以得到用戶畫像,對公司戰略的制定提供參考。本文將要介紹如何在node服務中處理日志。
一、技術選型
選擇了3種主流的技術進行對比:
1.1
是一種node日志管理工具,可以將自定義格式的日志輸出到各種渠道。對于控制臺的日志輸出可以呈現彩色日志,對于文件方式的日志輸出,可以根據文件大小或者日期進行日志切割。
熟悉java的開發人員會發現與一種常用的java日志工具log4j很像。沒錯,是log4j的版,使用方式也相似。
1.2
也是一種非常流行的node日志管理工具,支持多傳輸。默認輸出格式為json,也可以自定義輸出格式。如果想要對日志進行切割還需要使用 -daily--file 模塊。
1.3 PM2
PM2實際是node進程管理工具,具有性能監控、進程守護、負載均衡、日志管理等功能。使用PM2進行日志管理,只需要項目中增加方法調用,無需添加額外的代碼。要對日志進行切割,需要使用pm2-。
由于團隊內部服務端系統很多是基于java的,這些系統大部分使用log4j生成日志。日志管理相關的日志歸集系統和日志查詢系統對log4j格式的日志支持的更好,所以自己最終選用了log4j的版來生成日志,下面會對的基本使用進行介紹。
二、基本概念2.1 日志級別
的默認日志級別分為9級,按優先級從低到高排列如下:
ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < MARK < OFF
2.2
主要是用來定義以怎樣的方式輸出log日志分析用戶行為,輸出到哪里。可以將日志寫入到文件、發送電子郵件、通過網絡發送數據等。可以通過配置對象的屬性定義多個。
的常用類型有:
2.3
是日志的類型,指定一個或者多個為某種類型的日志,不同類型的日志可以指定不同的日志級別。可以通過配置對象的屬性定義多個。必須指定類型,用來獲取默認的實例,還可以通過類型名來獲取指定類型的實例。
綜上所訴, 定義了日志輸出到哪里, 將 進行了分類,不同類型指定不同的日志級別。
三、使用.1 安裝
npm --save
或者
yarn add
3.2 簡單使用
下面示例利用創建日志對象,通過調用.debug、、.warn、.error 等方法將日志輸出到控制臺和日志文件。
const path = require('path');
const log4js = require('log4js');
// 配置log4js

log4js.configure({
appenders: {
// 控制臺輸出
console: { type: 'console' },
// 日志文件
file: { type: 'file', filename: path.join(__dirname, '../../logs/server.log')}
},
categories: {
// 默認日志
default: { appenders: [ 'file', 'console' ], level: 'debug' },
}
});
// 獲取默認日志
const logger = log4js.getLogger();
module.exports = logger;
再通過調用. info 輸出INFO 級別的日志,這里web開發框架使用的Koa。
const Koa = require('koa');
const router = require('./router');
const logger = require('./util/log4jsLogger');
const port = 3000;
const app = new Koa()
.use(router.routes())
.use(router.allowedMethods());

app.listen(port, () => {
logger.info(`Server running on port ${port}`);
});
3.3 日志格式
通過 設置日志格式,內置的有:
示例:
默認的日志格式:
[2020-04-01T11:33:43.317] [INFO] default - Server running on port 3000
自定義的日志格式:
2020-04-01 11:33:43.317 [INFO] Server running on port 3000
代碼:
// 自定義日志格式
const layout = {
type: 'pattern',
pattern: '%d{yyyy-MM-dd hh:mm:ss.SSS} [%p] %m'
};
log4js.configure({
appenders: {
// 控制臺輸出
console: { type: 'console' },
// 日志文件,通過設置layout 設置日志格式
file: { type: 'file', filename: path.join(__dirname, '../../logs/server.log'), layout}
},
categories: {
// 默認日志
default: { appenders: [ 'file', 'console' ], level: 'debug' },

}
});
3.4 日志切割
如果日志全部輸出到一個文件,日志文件會越來越大,導致日志的備份和查看都很不方便。通過將 指定為 類型可以實現按日期將日志進行切割。
// 日志配置
log4js.configure({
appenders: {
// 控制臺輸出
console: { type: 'console' },
// 日志文件
file: {
type: 'dateFile',
filename: path.join(__dirname, '../../logs/server.log'),
// 日志切割后文件名后綴格式
pattern: '.yyyy-MM-dd'
}
},
categories: {
// 默認日志
default: { appenders: [ 'file', 'console' ], level: 'debug' },
}
});
假如4月1日部署的服務,日志會輸出到.log文件,到4月2日會將.log更名為.log.2020-04-01,然后創建新的.log文件,新的日志將繼續輸出到.log文件。
3.5 輸出多個文件
下面示例除了將完整日志輸出到.log,還會將error及以上級別的日志輸出到-error.log。
const path = require('path');

const log4js = require('log4js');
// 配置log4js
log4js.configure({
appenders: {
// 控制臺輸出
console: { type: 'console' },
// 全部日志文件
allFile: { type: 'file', filename: path.join(__dirname, '../../logs/server.log')},
// 錯誤日志文件
errorFile: { type: 'file', filename: path.join(__dirname, '../../logs/server-error.log')}
},
categories: {
// 默認日志,輸出debug 及以上級別的日志
default: { appenders: [ 'allFile', 'console' ], level: 'debug' },
// 錯誤日志,輸出error 及以上級別的日志
error: { appenders: [ 'errorFile' ], level: 'error' },
}
});
// 獲取默認日志
const defaultLogger = log4js.getLogger();
// 獲取錯誤級別日志
const errorLogger = log4js.getLogger('error');
// 日志代理,同時調用默認日志和錯誤日志
const loggerProxy = {};
const levels = log4js.levels.levels;

levels.forEach(level => {
const curLevel = level.levelStr.toLowerCase();
loggerProxy[curLevel] = (...params) => {
defaultLogger[curLevel](...params);
errorLogger[curLevel](...params);
}
});
module.exports = loggerProxy;
3.6 覆蓋
由于使用需要調用.debug、、.warn、.error等方法,對于已經調用 方法輸出日志的項目,全部改為調用的方法,改動起來很麻煩,可以通過覆蓋的方法來使用輸出日志。
/**
* 創建日志代理方法
* @param logLevel 日志級別
* @param logger 日志對象
* @return {function}
*/
function createLogProxy (logLevel, logger) {
return (...param) => {
logger[logLevel](...param);
};
}
console.log = createLogProxy('debug', logger);
console.info = createLogProxy('info', logger);
console.warn = createLogProxy('warn', logger);
console.error = createLogProxy('error', logger);
為了保證所有日志都能輸出到日志文件,獲取 對象和覆蓋方法要盡早執行。
四、總結
本章介紹了的基本使用log日志分析用戶行為,并給出了常用功能的使用示例,要了解的更多功能,請參考的官網:-node..io/-node/。另外,本文相關的代碼已提交到以供參考,項目地址://node--log-demo。