此文章是我自己用來記錄如何搭建一個以express爲基礎的api服務器框架的過程,並不是什麼新手教程,並不會每一步都寫得非常詳細,如果您要閱讀此文,需要一點nodejs和編寫代碼的基礎知識
文接上篇 鏈接: 地址 https://blog.csdn.net/goodboy31985/article/details/106236505
在上文基礎上,修改和完善api服務器的框架
使用express搭建一個api服務器,處理http請求-增加好用的日誌功能
用log4js包 來增強和優化日誌
我們在進行開發和日常維護的時候,都需要大量用到日誌功能,一些必要的信息和錯誤可以打在日誌中,供我們排查問題,但是nodejs本身提供的日誌功能偏弱,
比如我在代碼中想要輸出一行信息,並且打印一個錯誤,此時運行代碼,控制檯會出現以下的log信息
日誌中既沒有時間,普通的log也沒有代碼位置,而且也無法方便得打印到日誌文件中.
因此,我們需要一個強大且方便的工具來增強日誌功能
強烈建議使用log4js 這個包來增強日誌功能,下面是我封裝好log4js後的輸出日誌
同樣的代碼,現在有了時間戳,文件位置,函數名,提供的信息比之前多了很多,並且同時將日誌信息打印到了文件中,方便以後查看
並且log4js 還可以區分不同的日誌級別,比如開發時候需要打印debug,但是項目上線以後只需要打印info或者是error等,只需要將打印級別作爲運行時候的參數,就可以不動任何代碼的情況下,適應不同的使用場景
封裝log4js包,重寫console.log的功能
- 使用npm命令 下載log4js的包
npm install --save log4js - 新建一個LogHelper類,用來封裝log4js的功能,並重寫console.log
文件內容
// lib/common/LogHelper.ts
import log4js, { configure, getLogger } from "log4js"
import path from 'path'
import { rootDir } from "../../start";
export class LogHelper
{
static logger: log4js.Logger;
//trace debug info warn error fatal
//輸出級別
static logLevel: string = 'trace';
static logLevelDefine:any = {
"trace": 1,
"debug": 2,
"info": 3,
"warn": 4,
"error": 5,
"fatal":6,
}
static Init()
{
//可以用環境變量的形式,向程序傳遞不同的打印級別,適應不同的場景
if (process.env.LOG_LEVEL) {
LogHelper.logLevel = process.env.LOG_LEVEL;
}
configure({
pm2: process.env.NODE_ENV === 'production',//如果使用pm2運行nodejs,可以設置運行環境爲 production
pm2InstanceVar: 'INSTANCE_ID',
disableClustering: true,
//配置不同的輸出目的地-這裏同時打印到文件 和 控制檯
appenders: {
logFile: {
type: 'file',
filename: path.join(rootDir, '../logs/', new Date().toLocaleDateString()+'.log'), //設置文件儲存路徑,這裏用日期作爲文件名
maxLogSize: 500000,
backups: 5,
replaceConsole: true
},
console: {
type: 'console',
replaceConsole: true
},
},
//配置不同的logger類別
//trace debug info warn error fatal
categories: {
default: { appenders: ['console', 'logFile'], level: LogHelper.logLevel },
},
});
LogHelper.logger = getLogger("default");
// log4js.shutdown(
// function ()
// {
// LogHelper.info("Server Stop");
// LogHelper.info("");
// });
//重寫系統的log debug warn等,代替系統原來的打印功能
console.log = function (message: any, ...args: any[])
{
//首先判斷打印級別
if (LogHelper.logLevelDefine[LogHelper.logLevel]>LogHelper.logLevelDefine.debug) {
return;
}
//爲了拿到文件名,行數,函數名等信息,需要解析堆棧信息
let stackInfoStr = LogHelper.stackInfo();
//重新拼裝內容,文件名+行數+方法名
let info = `[${stackInfoStr.file}:${stackInfoStr.line} (${stackInfoStr.method})]`;
//調用log4js的打印
LogHelper.logger.debug(info, message, ...args);
};
console.debug = function (message: any, ...args: any[])
{
if (LogHelper.logLevelDefine[LogHelper.logLevel] > LogHelper.logLevelDefine.debug)
{
return;
}
let stackInfoStr = LogHelper.stackInfo();
let info = `[${stackInfoStr.file}:${stackInfoStr.line} (${stackInfoStr.method})]`;
LogHelper.logger.debug(info, message, ...args);
};
console.warn = function (message: any, ...args: any[])
{
if (LogHelper.logLevelDefine[LogHelper.logLevel] > LogHelper.logLevelDefine.warn)
{
return;
}
let stackInfoStr = LogHelper.stackInfo();
let info = `[${stackInfoStr.file}:${stackInfoStr.line} (${stackInfoStr.method})]`;
LogHelper.logger.warn(info, message, ...args);
};
console.error = function (message: any, ...args: any[])
{
if (LogHelper.logLevelDefine[LogHelper.logLevel] > LogHelper.logLevelDefine.error)
{
return;
}
let stackInfoStr = LogHelper.stackInfo();
let info = `[${stackInfoStr.file}:${stackInfoStr.line} (${stackInfoStr.method})]`;
LogHelper.logger.error(info, message, ...args);
};
console.info = function (message: any, ...args: any[])
{
if (LogHelper.logLevelDefine[LogHelper.logLevel] > LogHelper.logLevelDefine.info)
{
return;
}
let stackInfoStr = LogHelper.stackInfo();
let info = `[${stackInfoStr.file}:${stackInfoStr.line} (${stackInfoStr.method})]`;
LogHelper.logger.info(info, message, ...args);
};
}
//獲取堆棧內容
static stackInfo(num:number=0)
{
var stackReg = /at\s+(.*)\s+\((.*):(\d*):(\d*)\)/i;
var stackReg2 = /at\s+()(.*):(\d*):(\d*)/i;
let err = new Error();
var stacklist = err.stack.split('\n').slice(3);
var s = stacklist[num];
var sp = stackReg.exec(s) || stackReg2.exec(s);
var data: any = {};
if (sp && sp.length === 5)
{
data.method = sp[1];
data.path = sp[2];
data.line = sp[3];
data.pos = sp[4];
data.file = path.basename(data.path);
}
return data;
}
}
這樣我們就封裝好了一個LogHelper,由於我們重寫的系統的log函數,因此,不需要改變我們原有的log習慣和代碼,可以做到完全無感
只需要在項目入口最前端,加入初始化
本節內容主要是封裝了一個好用的日誌功能,方便我們的調試和運維,下節我們將爲此框架增加更多的功能