本文介绍了Winston + PM2两次记录uncaughtException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为NodeJS应用程序使用 winston ,以具有结构化的日志记录格式(JSON)稍后我将处理并通过Filebeat发送到Logstash.

I am using winston for my NodeJS apps, to have a structured logging format (JSON) that later I will process and send to Logstash via Filebeat.

根据PM2和 12factor.net 的建议,我正在使用 winston.transports.Console进行日志记录传输并让PM2处理我的 ecosystem.json 中的 stdout stderr .

As suggested by PM2 and 12factor.net I'm logging using winston.transports.Console transport and letting PM2 to handle the stdoutand stderr in my ecosystem.json.

在我的 logger.js 模块中,我具有以下内容:

In my logger.js module I have the following:

"use strict";
const winston = require("winston");
// Remove logging on console
winston.remove(winston.transports.Console);
// env
const env = process.env.NODE_ENV || 'development';
const isDev = env === "development";
// The default Console transport
const defaultLogLevel = isDev ? "debug" : "info";

const consoleTransport = new winston.transports.Console({
    level: defaultLogLevel,
    colorize: true,
    json: true,
    timestamp: true,
    exceptionsLevel: "error",
    prettyPrint: false,
    handleExceptions: true,
    humanReadableUnhandledException: false,
    exitOnError: true
});

const defaultOptions = {
    transports: [
    consoleTransport
    ]
};


module.exports = function(options)
{
    let initOpts = defaultOptions;
    if(options)
    {
        Object.assign(initOpts, options);
    }
    const logger = new winston.Logger(initOpts);
    // suppress any logger errors
    logger.emitErrs = false;
    winston.handleExceptions(consoleTransport);

    return logger;
};

在我的主应用程序文件 server.js 中,我运行以下代码来模拟引发未处理的异常,需要并没有找到虚假的依赖项:

In my main app file server.js I run this code to simulate an unhandled Exception being thrown, a fake dependency is being required and not found:

"use strict";
var log         = require('./logger')({name: "api-messages"});
log.info("some info message");
log.error("some error message");
var notFound = require("someInexistentPackage");

最后,在我的PM2 ecosystem.json 中,我具有以下内容:

Finally, in my PM2 ecosystem.json I have the following:

{
  "apps":
  [
    {
      "name"            : "my-app",
      "script"          : "server.js",
      "max_restarts"    : 1,
      "error_file"      : "~/.pm2/logs/my-app.log",
      "out_file"        : "~/.pm2/logs/my-app.log",
      "merge_logs"      : true

    }
  ]
}

当我运行 pm2时,启动生态系统.json 的日志文件内容如下:

When I run pm2 start ecosystem.json the contents of the log files are the following:

{
  "level": "info",
  "message": "some info message",
  "timestamp": "2017-06-08T16:10:05.967Z"
}
{
  "level": "error",
  "message": "some error message",
  "timestamp": "2017-06-08T16:10:05.968Z"
}
Error: Cannot find module 'someInexistentPackage'
    at Function.Module._resolveFilename (module.js:470:15)
    at Function.Module._load (module.js:418:25)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/mps/Sites/my-app/server.js:10:20)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
{
  "date": "Thu Jun 08 2017 13:10:05 GMT-0300 (-03)",
  "process": {
    "pid": 50862,
    "uid": 501,
    "gid": 20,
    "cwd": "/Users/mps/Sites/my-app",
    "execPath": "/Users/mps/.nvm/versions/node/v7.10.0/bin/node",
    "version": "v7.10.0",
    "argv": [
      "/Users/mps/.nvm/versions/node/v7.10.0/bin/node",
      "/Users/mps/.nvm/versions/node/v7.10.0/lib/node_modules/pm2/lib/ProcessContainerFork.js"
    ],
    "memoryUsage": {
      "rss": 36724736,
      "heapTotal": 9879552,
      "heapUsed": 6309680,
      "external": 63983
    }
  },
  "os": {
    "loadavg": [
      2.49560546875,
      2.228515625,
      2.0205078125
    ],
    "uptime": 329559
  },
  "trace": [
    {
      "column": 15,
      "file": "module.js",
      "function": "Module._resolveFilename",
      "line": 470,
      "method": "_resolveFilename",
      "native": false
    },
    {
      "column": 25,
      "file": "module.js",
      "function": "Module._load",
      "line": 418,
      "method": "_load",
      "native": false
    },
    {
      "column": 17,
      "file": "module.js",
      "function": "Module.require",
      "line": 498,
      "method": "require",
      "native": false
    },
    {
      "column": 19,
      "file": "internal/module.js",
      "function": "require",
      "line": 20,
      "method": null,
      "native": false
    },
    {
      "column": 20,
      "file": "/Users/mps/Sites/my-app/server.js",
      "function": null,
      "line": 10,
      "method": null,
      "native": false
    },
    {
      "column": 32,
      "file": "module.js",
      "function": "Module._compile",
      "line": 571,
      "method": "_compile",
      "native": false
    },
    {
      "column": 10,
      "file": "module.js",
      "function": "Module._extensions..js",
      "line": 580,
      "method": ".js",
      "native": false
    },
    {
      "column": 32,
      "file": "module.js",
      "function": "Module.load",
      "line": 488,
      "method": "load",
      "native": false
    },
    {
      "column": 12,
      "file": "module.js",
      "function": "tryModuleLoad",
      "line": 447,
      "method": null,
      "native": false
    },
    {
      "column": 3,
      "file": "module.js",
      "function": "Module._load",
      "line": 439,
      "method": "_load",
      "native": false
    }
  ],
  "stack": [
    "Error: Cannot find module 'someInexistentPackage'",
    "    at Function.Module._resolveFilename (module.js:470:15)",
    "    at Function.Module._load (module.js:418:25)",
    "    at Module.require (module.js:498:17)",
    "    at require (internal/module.js:20:19)",
    "    at Object.<anonymous> (/Users/mps/Sites/my-app/server.js:10:20)",
    "    at Module._compile (module.js:571:32)",
    "    at Object.Module._extensions..js (module.js:580:10)",
    "    at Module.load (module.js:488:32)",
    "    at tryModuleLoad (module.js:447:12)",
    "    at Function.Module._load (module.js:439:3)"
  ],
  "level": "error",
  "message": "uncaughtException: Cannot find module 'someInexistentPackage'",
  "timestamp": "2017-06-08T16:10:05.972Z"
}

如您所见,PM2正在将未捕获的异常添加到日志文件,即此代码:

As you can see, PM2 is adding the uncaught Exception to the log file, i.e. this code:

Error: Cannot find module 'someInexistentPackage'
    at Function.Module._resolveFilename (module.js:470:15)
    at Function.Module._load (module.js:418:25)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/mps/Sites/my-app/server.js:10:20)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)

这破坏了日志的格式/结构,因为它是纯文本而不是我从 winston 收到的格式化JSON.

This breaks the format/structure of my logs, since it's plain text instead of the formatted JSON I receive from winston.

我确信这是PM2问题/配置错误,因为如果我运行 node server.js ,则控制台输出只是JSON对象.

I'm confident this is a PM2 issue/misconfiguration, because if I run node server.js the console output are just the JSON objects.

我是否必须在PM2 ecosystem.json 文件中设置特定属性?

Do I have to setup a specific property in PM2 ecosystem.json file?

如何告诉PM2忽略Node的 uncaughtException ?

How can I tell PM2 to ignore Node's uncaughtException?

我想出的唯一选择(我还没有尝试过)是将我的winston传输更改为 winston.transports.File ,重定向 ALL 登录到 stdout 并告诉PM2将 stderr 保存在另一个文件中,但我宁愿坚持使用控制台方法.

The only alternative I have come up with (which I haven't tried yet), is to change my winston transport to winston.transports.File, redirect ALL logs to stdoutand tell PM2 to save stderr in a different file, but I'd rather stick with the console aproach.

推荐答案

防止PM2记录 uncaughtException 的一种方法是将-no-pmx 传递为标志,即 pm2 start --no-pmx myapp.js 或将 pmx:false 添加到 ecosystem.json 文件中.

One way to prevent PM2 from logging the uncaughtException is to pass --no-pmx as a flag, i.e. pm2 start --no-pmx myapp.js or to add pmx: false to the ecosystem.json file.

这将禁用PMX注入PM2,PM2负责记录此 uncaughtException .

This disables PMX injection into PM2, which is the responsible for logging this uncaughtException.

这篇关于Winston + PM2两次记录uncaughtException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-22 14:31