每日前端夜话0xBB
每日前端夜话,陪你聊前端。
每天晚上18:00准时推送。
正文共:2843 字
预计阅读时间:13 分钟
作者:Mahesh Haldar
翻译:疯狂的技术宅
来源:bitsrc.io
日志记录是每个开发人员从第一天编写代码时就要做的事情,但很少有人知道它可以产生的价值和最佳实践。
在本文中,我们将讨论以下主题:
日志是反映程序各个方面的事件,如果能够正确编写,那么它就是最简单的故障排除和诊断程序的模式。
当你启动 Node.js 服务器时,如果数据库由于某些问题而没有运行,或服务器端口已经被占用时,如果没有日志,你将永远不知道服务器失败的原因。
作为开发人员,你经常需要调试一些问题,我们很喜欢用调试器和断点来定位故障的位置和内容。
当你的程序在生产环境中运行时,你会做些什么?你能在那里附加调试器并重现 bug 吗?显然没有。因此,这是日志记录能够帮助你的地方。
在不使用调试器的情况下,你可以通过浏览日志找到问题并了解出现问题的原因和位置。
程序日志既适用于人类,也适用于机器。人类参考日志来调试问题,机器用日志生成各种图表,并通过数据分析来产生关于客户使用的各种结论。
每个日志都应包含三个最重要的部分:
The operation failed!
有意义的上下文应该是是:
Failed to create user, as the user id already exist
import logger from '../logSetup';
getInstallment(month: number, count: number ): number {
logger.debug(`>>>> Entering getInstallment(month = ${month}, count= ${count}");
// process
const installment: number = 3;
log.debug("<<<< Exiting getIntallment()");
return installment;
}
通过日志 >>>>
和 <<<<
将给出函数输入和退出的信息。这是受到了 git merge 冲突的启发。
userService.getUser()
可以返回 null
,且 .getId()
可以抛出异常,所以要避免这些情况。import logger from '../logSetup';
processLoan(...) {
logger.debug(">>>> Entering processLoan()");
// ... process
logger.debug(`Processing user loan with id ${userService.getUser().getId()}`);
// this might throw error, when getUser returns undefined
logger.debug("<<<< Exiting processLoan()");
return true;
}
你应该用 Aspect js 自动执行函数级日志。
import logger from '../logSetup';
createUser() {
logger.debug(">>>> Entering createUser");
// ... process
logger.debug("Saving user loan {}", userInfoRepository.save(userInfo)) // don't do this
return true;
}
当描述错误时,请提及尝试的内容及其失败的原因。
记录哪些是失败的和你接下来做什么。
import logger from '../logSetup';
processLoan(id: number, userId: number) {
try {
getLoanDeatilsById()
} catch(error) {
log.error(`Failed to do getLoanDetails with id ${id}, ignoring it and trying to getLoanDetailsByUserId`, error);
// good example: provide what failed, and how you are handling.
// e.g here on fail I am trying to call other function
getLoanDetailsByUserId();
}
}
如果你在 catch
部分中丢弃错误,请记录哪个操作失败并提及你正在抛出错误。
import logger from '../logSetup';
processLoan(id: number, userId: number) {
try {
getLoanDeatilsById()
} catch(error) {
log.error(`Failed to do getLoanDetails with id ${id} hence throwing error`, error);
// good example: provide what failed, and how you are handling.
// e.g here on fail I am throwing
throw error;
}
}
该系列日志应该反映用户在程序中的活动以便调试更容易,并且应该记录错误以便尽快采取措施。日志包含一些信息,例如调用哪些函数,输入的内容,发生的位置和错误等。
记录时我们必须确保不去记录用户名和密码等敏感信息,例如信用卡号、CVV 号码等财务信息。
作为开发人员,我们应该通过与产品团队沟通,来准备敏感信息的列表并在记录之前将其屏蔽。
如果生产环境下的程序具有相当多的用户事务,那么理想的日志设置可能每天会生成 GB 级别的日志,因此我们需要将日志分组为多个组。根据受众,我们可以在运行时切换日志级别,并仅获取适当的日志。
例如,如果产品经理希望在我们的日志记录仪表板中查看有多少客户交易成功或失败,则不应向他展示各种功能调用的杂乱信息,这些信息仅供开发人员使用。当生产环境中存在错误时,开发人员应该看到各种函数成功执行和失败的详细日志。这样就可以尽快发现并修复问题。
要实现这种设置,我们需要更好地了解每个日志级别。
让我们讨论最重要的级别及其用法:
New User created with id xxx
这表示仅记录进度信息。
主要受众是系统操作员或监控系统。
理想情况下,生产环境下的程序应该具有接近零的错误日志。
大多数开发人员使用控制台模块作为获取日志或调试代码的第一个工具,因为它简单容易且全局可用,无需设置。在 Node.Js 中,控制台的实现方式与浏览器不同,控制台模块在使用 console.log
时会在 stdout 中打印消息,如果使用 console.error
它将打印到 stderr。
console.log
、console.debug
和 console.info
都在 stdout 中打印,因此我们将无法关闭或打开调试和及信息。同样,`console.warn
和 console.error
都在 stderr 中打印。
生产环境程序很难切换各种级别。
我们还需要不同类型的配置,如标准格式、把JSON 输出格式发送到 ELK 栈,这些在开箱即用的控制台中不可用。
要克服所有这些问题,可以使用 Winston 日志框架,还有其他一些选项,如Bunyan,Pino等。
在上一节中我们讨论了控制台的一些缺陷,让我们列出 Winston 提供的一些重要功能:
{message: “something wrong”, level: “error"}
如果需要,你也可以创建自定义级别。// log setup
import winston from 'winston';
const transports = {
console: new winston.transports.Console({ level: 'warn' }),
};
const logger = winston.createLogger({
transports: [transports.console, transports.file]
});
logger.info('This will not be logged in console transport because warn is set!');
transports.console.level = 'info'; // changed the level
logger.info('This will be logged in now!');
export default {logger, transport}
我们还可以公开 API 动态更改级别,公开 REST API 并在处理程序中执行第 13 行以更改级别。
import winston from 'winston';
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
//
new winston.transports.File({ filename: 'stdout.log' })
]
});
export default logger;
通过配置 Winston 将我们的日志写入文件,以便任何日志托运代理都可以将日志推送到集中式系统。但是,这超出了本文的范围,我们会在另一篇文章中详细讨论。
如果程序写日志的频率很高,则可能直接影响程序性能。
DEBUG 和 INFO 级别的日志可占到整体的 95% 以上,这就是为什么应该只启用 ERROR 和 WARN 级别,并在想要找出问题时将级别更改为DEBUG,之后再将其切换回 ERROR 。
当应用程序出现问题时,日志就是救星。如果你当前还没有很好的使用日志,请实施日志记录实践并将日志添加到代码审查核对表中。
原文:https://blog.bitsrc.io/logging-best-practices-for-node-js-applications-8a0a5969b94c