記錄nodejs使用express搭建一個api服務器程序(3)-封裝非常好用的日誌輸出功能log4js

此文章是我自己用來記錄如何搭建一個以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的功能

  1. 使用npm命令 下載log4js的包
    npm install --save log4js
  2. 新建一個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習慣和代碼,可以做到完全無感
只需要在項目入口最前端,加入初始化
在這裏插入圖片描述
本節內容主要是封裝了一個好用的日誌功能,方便我們的調試和運維,下節我們將爲此框架增加更多的功能

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章