【问题标题】:Log js file name and function name记录js文件名和函数名
【发布时间】:2018-03-14 08:23:59
【问题描述】:

我希望我的 node.js 项目生成有点类似于 log4j 格式的日志文件,因为我希望每个日志行都以日志请求的文件名和 js 函数名开头。

例如: 如果我的 js 文件称为 aNiceFile.js 并且我的 js 函数称为 doImportantStuff() 并且我使用以下内容调用日志语句:

log.info('About to start on the important stuff')

我希望我的日志文件看起来有点像:

2018-03-14 06:33:26:619 INFO aNiceFile.js doImportantStuff() About to start on the important stuff.

我想做很多日志记录,所以我不介意预先设置它,但我在添加到我的代码中的每个文件/函数的额外工作量最少。

我今天正在使用Winston,如果有必要,我很高兴切换到其他东西,对于 Winston,如果不付出我的努力,这似乎是不可能的:https://github.com/winstonjs/winston/issues/200

为了完整起见,我不需要行号,但如果有它们也不错。

我目前笨拙的工作是:

1) 以此开始每个文件以获取当前文件名:

const sn = path.basename(__filename) // this script file name, used  for logging purposes

这一步我没问题,不繁琐,在每个文件的顶部粘贴一行相同的行,我可以接受。

2) 以 this 启动每个函数以获取当前函数名:

const fn = '<I copy/paste the function name into this string constant :( >'

我不喜欢这一步,我必须将函数名复制到字符串常量中,如果我重命名函数,以后可能会不同步。

如果我能把它变成下面的版本会更好,不知道该怎么做:

const fn = getCurrentFunctionName() 

3) 我这样写每个日志语句:

log.info(`${sn}:${fn} Starting important stuff`)

我不喜欢这一步,因为我所有的日志语句都以这个 (${sn}:${fn}) 噪音开头。

如您所见,这是原始的,但确实有效。我真的应该在这里做什么?

我对性能感兴趣,因此需要生成 Error 对象以从中获取堆栈跟踪的解决方案可能是不可接受的。

【问题讨论】:

    标签: javascript node.js logging winston


    【解决方案1】:

    编辑添加所有内容。

    这是文件名、行、列和调用函数的基本示例。也许你需要适应一些东西。但这就是想法。

    let log = {
    	info: function info(message) {
    		const callerInfo = getFileName(info.caller.name);
    		console.log(
    			new Date() +
    				' ' +
    				arguments.callee.name.toUpperCase() +
    				' ' +
    				callerInfo.filename +
    				':' +
    				callerInfo.line +
    				':' +
    				callerInfo.column +
    				' ' +
    				info.caller.name +
    				'() ' +
    				message
    		);
    	},
    };
    
    function getFileName(caller) {
      const STACK_FUNC_NAME = new RegExp(/at\s+((\S+)\s)?\((\S+):(\d+):(\d+)\)/);
    	let err = new Error();
    	
    	Error.captureStackTrace(err);
    
    	let stacks = err.stack.split('\n').slice(1);
    
    	let callerInfo = null;
    	for (let i = 0; i < stacks.length; i++) {
    		callerInfo = STACK_FUNC_NAME.exec(stacks[i]);
        
    		if (callerInfo[2] === caller) {
    			return {
    				filename: callerInfo[3],
    				line: callerInfo[4],
    				column: callerInfo[5],
    			};
    		}
    	}
    
    	return null;
    }
    
    function iWantToLog() {
    	log.info('Testing my log');
    }
    
    iWantToLog();

    【讨论】:

    • 感谢@F.bernal,输出很完美。我唯一的问题是使用“let err = new Error();”声明,我的印象是从性能的角度来看是昂贵的。我会试一试,看看对我的项目的性能影响。
    • 新的错误是获取调用堆栈并获取文件名和行。如果您可以通过其他方式获取文件名,则可以将其删除。
    【解决方案2】:

    一位同事建议使用 Gulp PreProcess 来解决此问题。我的想法是我不会执行上述任何手动步骤 1) 2) 和 3),但是在运行/部署我的代码之前,我会通过 Gulp 预处理来提供它,该预处理将更新我的所有 js 源代码,添加所有步骤 1) 2) 和 3) 中描述的代码。

    我没有太多使用 Gulp,但从表面上看,这听起来是一个很有前途的想法。好的一面:

    1. 只要 Gulp 可以根据需要更新我的源文件,它就可以工作
    2. 不应导致任何重大的运行时 js 性能问题,不需要生成 js 错误对象来创建从中提取脚本和函数名称的堆栈跟踪
    3. 我的源代码不会被任何用于记录脚本名称和函数名称的额外代码弄得乱七八糟

    不利的一面:

    1. 需要让 Gulp 成为我工作流程的一部分 - 这似乎可以接受
    2. 我需要设置 gulp 预处理器来更改我的 js 源 - 不知道这有多难,gulp pre-process 会是我的起点吗?
    3. 当我对 js 源文件进行代码更改时,Gulp 每次都需要重新运行,这会影响我的迭代时间

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 2021-04-13
    • 1970-01-01
    • 2020-10-04
    • 2014-03-10
    相关资源
    最近更新 更多