节点应用程序的正确错误日志记录

时间:2018-04-27 14:07:18

标签: node.js logging

我正在开发一个快速项目,其中包含多个模块/服务。文件夹结构看起来大概如下:

-- app.js
 -- payment_service
    -- routes.js
    -- index.js
    -- models
      -- model_1.js
      -- model_2.js

index.js中的API是唯一公开的API,它们可用作此模块/服务的所有请求的网关。

在许多情况下,大多数服务都会引发操作错误,因此可能需要手动干预来解决问题。所以我需要:

  1. 使用适当的上下文正确记录错误,以便某些人/脚本可以满足需要。
  2. 找出失败的原因。
  3. 将有专门的团队拥有每项服务。因此,我应该能够区分每项服务的错误日志,以便将其汇总并转发给相关人员。

    我决定使用ELK stash,以便我可以通过脚本生成报告。

    我面临的主要问题是我不能保持日志之间的相关性。例如;如果一个请求到来并且它通过五个函数并且每个函数都记录了一些东西,那么我就无法将这些日志关联起来。

    一种方法是为每个请求创建一个子记录器并将其传递给所有函数,但这似乎是将记录器实例传递给所有函数的额外开销。

    另一种选择是使用verror之类的东西,只在服务/模块的入口点进行日志记录,以便整个上下文可以包含在日志中。这种方法对于记录错误看起来没问题,但它对信息和调试日志没有帮助 - 它们在开发和测试阶段帮助了我很多。

    为了区分错误日志,我将创建

    1. 每个服务的专用记录器,其日志级别错误。
    2. 用于信息和调试目的的应用程序范围的通用记录器。
    3. 这是正确的方法吗?

      什么是最好的方式,以便我能以最简单的方式达到所有要求?

2 个答案:

答案 0 :(得分:0)

我建议你使用记录器而不需要太复杂的东西。例如:

npm install 12factor-log

然后在app.js附近的根文件夹中创建一个文件(或在/lib文件夹中创建一个文件放置库)

logger.js

const Log = require('12factor-log');

module.exports = (params) => {
  return new Log(params);
}

然后在您的模块中,导入您的记录器并在实例化时传递模块名称,以便您可以跟踪语句的来源......

model_1.js

var log = require('./logger')({name: 'model_1'});

// ... 

log.info("Something happened here");

// ...

try {
  // ...
catch (error) {
  const message = `Error doing x, y, z with value ${val}`;
  log.error(message);
  throw new Error(message);
}

然后在您的控制器上优雅地处理错误 - >查看图层以获得用户友好的体验。

您的日志会打印出类似这样的内容:

{"ts":"2018-04-27T16:37:24.914Z","msg":"Something happened here","name":"model_1","type":"info","level":3,"hostname":"localhost","pid":18}

就日志的关联而言,如果你在上面的输出中看到它包含它运行的机器的主机名,还包括模块的名称和严重性级别。您可以将此JSON导入Logstash并加载到Elasticsearch中,它将存储JSON以便于搜索和索引。

请参阅:https://www.elastic.co/guide/en/logstash/current/plugins-filters-json.html

答案 1 :(得分:0)

记录很复杂,很多人都在研究它。我建议不要自己这样做。

所以,不按照我自己的建议,我创建了自己的日志包:

  

https://www.npmjs.com/package/woveon-logger

npm install woveon-logger

这将打印错误和消息的文件和行号,具有日志记录级别和面向方面的日志记录,并且可以在一次调用中转储堆栈跟踪。它甚至还有颜色编码选项。如果您遇到困难并需要记录功能,请告诉我。

let logger1 = new Logger('log1', {level : 'info', debug : true, showname : true};
let logger2 = new Logger('log2', {level : 'verbose', debug : true, showname : true};
...
log1.info('Here is a log message, that is on line 23.');
log1.verbose('Does not show');
log2.verbose('Shows because log2 is verbose logging');
log2.setAspect('IO', true);
log2.aspect('IO', 'Showing aspect IO logging, for logs for IO related operations');
  

[2018-06-10T10:43:20.692Z] [INFO--] [log1] [path / to / myfile:23]这是一条日志消息,位于第23行。

     

[2018-06-10T10:43:20.792Z] [VERBOS] [log2] [path / to / myfile:25]显示因为log2是详细记录

     

[2018-06-10T10:43:20.892Z] [IO ----] [log2] [path / to / myfile:27]显示方面IO日志记录,用于IO相关操作的日志

此外,还有其他一些功能:

log1.throwError('Logs this as both a line of logging, and throws the error with the same message');
log1.printStack('Prints this label next to the stack trace.');

希望它有所帮助!