此文章是我自己用来记录如何搭建一个以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习惯和代码,可以做到完全无感
只需要在项目入口最前端,加入初始化
本节内容主要是封装了一个好用的日志功能,方便我们的调试和运维,下节我们将为此框架增加更多的功能