记录nodejs使用express搭建一个api服务器程序(3)-封装非常好用的日志输出功能log4js

此文章是我自己用来记录如何搭建一个以express为基础的api服务器框架的过程,并不是什么新手教程,并不会每一步都写得非常详细,如果您要阅读此文,需要一点nodejs和编写代码的基础知识

文接上篇 链接: 地址 https://blog.csdn.net/goodboy31985/article/details/106236505
在上文基础上,修改和完善api服务器的框架

使用express搭建一个api服务器,处理http请求-增加好用的日志功能

  • 用log4js包 来增强和优化日志
  • 封装log4js包,重写console.log的功能

用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
    在这里插入图片描述
    文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// 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习惯和代码,可以做到完全无感
只需要在项目入口最前端,加入初始化
在这里插入图片描述
本节内容主要是封装了一个好用的日志功能,方便我们的调试和运维,下节我们将为此框架增加更多的功能