在生产环境中调试Node.js错误

7

我有一个在生产环境中运行的nodejs脚本。

不太可能(千分之一的概率)会出现以下错误:

TypeError: value is out of bounds
    at checkInt (buffer.js:1009:11)
    at Buffer.writeUInt16LE (buffer.js:1067:5)
    at Object.foo.bar (/fake/path/name.js:123:1);
    at Object.foo.bar2 (/fake/path/name2.js:123:1);
    at Object.foo.bar3 (/fake/path/name3.js:123:1);

导致生产服务器崩溃...

太好了,我有一个堆栈跟踪!但我想知道每个调用或所有数据的当前数据是什么?

有哪些很棒的工具或代码可用于生产代码的错误日志记录(带有其当前数据)?


请添加您正在使用的操作系统。在某些操作系统中,您可以使用跟踪工具(如dtrace(smartos)等)来查看生产环境中发生的情况,而不必触及您的代码。 - Guido
5个回答

8
我强烈推荐使用WinstonBunyan。选择npm包是您的应用程序决策。
您可以通过查看npm页面中统计信息来基准测试可用的npm包。这些统计数据基本上是以下内容:
  1. 最近一天的下载量
  2. 最近一周的下载量
  3. 最近一个月的下载量
  4. 开放问题和拉取请求。
最近下载量更高将表明长期使用的模块得到了很好的支持。因此这很重要。
Winstan和Bunyan都是市场上最好的日志记录npm包,主要区别在于,Winstan非常适合普通日志记录目的,当然Winstan提供了很多日志记录功能。但是,要利用这些功能,需要比Bunyan付出更多的努力。
另一方面,Bunyan专门支持“分析日志”的事实。因此,Bunyan基本上是用于日志处理的。因此,如果您想要分析日志、日志文件,强烈建议使用Bunyan。与Winstan相比,使用Bunyan调整日志相对容易。
我对Bunyan和Winstan进行了彻底的比较。请检查下面的链接,以查看Winstan和Bunyan如何根据Node应用程序的范围、用例和日志记录的必要性使用。 链接:https://docs.google.com/document/d/1pD9PLyxlcHVxxOvserNLO9tAz-QA_Co-xo6cWLhLghc/edit?usp=sharing 此外,在生产环境中,请确保明智地使用日志记录级别。在生产环境中最常用的日志记录级别是:
  • 错误
  • 信息
  • 调试

4
你可以使用Winston或者Pino
使用winston,你可以在任何地方加载许多日志模块,并且可能在线存储日志。我从未使用过pino,但我读到了一些好的东西。
设置环境变量以选择输出日志的位置,例如,如果您处于开发状态,则只想在stdout上显示输出,而仅在应用程序处于生产状态时才存储在线。

1
我正在使用pm2,它是node.js的进程管理器,还使用rollbar进行错误报告。我认为你应该为出现错误的代码部分定义一些指标。

1
使用decofun调试工具是处理node.js中的异步函数的好方法。 它的主要特点是根据上下文解析代码和匿名函数的名称。 您可以通过运行deco filename.js去除任何匿名函数。
文档中所述,一个简单的例子。
function gravy() {
   return function returnedᅠfromᅠgravyᅠㅣlineᅠ2 () {
       return {
         prop: function asᅠpropertyᅠpropᅠㅣlineᅠ4 () {
           setTimeout(function passedᅠintoᅠsetTimeoutᅠㅣlineᅠ5 () {
             console.trace('Getting a trace...');  
           }, 10)

         }
       }
   }
}
Trace: Getting a trace...
    at passedᅠintoᅠsetTimeoutᅠㅣlineᅠ5 [as _onTimeout] (/home/ubuntu/workspace/node_modules/decofun/examples/loadable/index.js:6:22)
    at Timer.listOnTimeout (timers.js:92:15)

由于它带有嵌入式cute-stack库,该库将当前目录的路径标准化

通过应用命令deco examples/loadable --cute table,输出将显示为

enter image description here

我最喜欢它的地方是,它可以根据对原始函数的调用来转换函数,就像在这个例子中看到的那样。
   function one (a, cb) {

}


one('blah', function () {

})

function two () {
  return function () { }
}


function three () {
  return {
    shoe: function () {}
  }
}

function four () {
  return function () { 
    return function () {

    }
  }
}

function five () {
  return function () {
    return function () {
      return function () {
        foo('blue', function () {

        })
      }
    }
  }
}


var six = function () {

}


var seven = function (err, cb) {

  return function () {
    cb(function () {

    })
  }

}

var o = {};
o.eight = function (cb) { }


o.eight(function () { })

o.eight.nine = function () {}
o.eight.nine(function () { })

var o2;

o2 = function () { }


;(function () {}())

!function () { }()



function toodeep () {
  return function () {
    return function () {
      return function () {

        return function () {
          return function () {
            return function () {

              return function () {
                return function () {
                  return function () {

                    return function () {

                    }                     

                  }
                }
              } 

            }
          }
        }        
      }
    }
  }
}

转换为这个

function one (a, cb) {

}


one('blah', function passedᅠintoᅠoneᅠㅣlineᅠ6 () {

})

function two () {
  return function returnedᅠfromᅠtwoᅠㅣlineᅠ11 () { }
}


function three () {
  return {
    shoe: function asᅠpropertyᅠshoeᅠㅣlineᅠ17 () {}
  }
}

function four () {
  return function returnedᅠfromᅠfourᅠㅣlineᅠ22 () { 
    return function returnedᅠfromᅠᐸᅠreturnedᅠfromᅠfourᅠᐳᅠㅣlineᅠ23 () {

    }
  }
}

function five () {
  return function returnedᅠfromᅠfiveᅠㅣlineᅠ30 () {
    return function returnedᅠfromᅠᐸᅠreturnedᅠfromᅠfiveᅠᐳᅠㅣlineᅠ31 () {
      return function returnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠfiveᅠᐳᅠᐳᅠㅣlineᅠ32 () {
        foo('blue', function passedᅠintoᅠfooᅠㅣlineᅠ33 () {

        })
      }
    }
  }
}


var six = function asvarᅠsixᅠㅣlineᅠ42 () {

}


var seven = function asvarᅠsevenᅠㅣlineᅠ47 (err, cb) {

  return function returnedᅠfromᅠᐸᅠasvarᅠsevenᅠᐳᅠㅣlineᅠ49 () {
    cb(function passedᅠintoᅠcbᅠㅣlineᅠ50 () {

    })
  }

}

var o = {};
o.eight = function asᅠpropertyᅠeightᅠㅣlineᅠ58 (cb) { }


o.eight(function passedᅠintoᅠoːeightᅠㅣlineᅠ61 () { })

o.eight.nine = function asᅠpropertyᅠnineᅠㅣlineᅠ63 () {}
o.eight.nine(function passedᅠintoᅠeightːnineᅠㅣlineᅠ64 () { })

var o2;

o2 = function asvarᅠo2ᅠㅣlineᅠ68 () { }


;(function IIFEᅠㅣlineᅠ71 () {}())

!function IIFEᅠㅣlineᅠ73 () { }()



function toodeep () {
  return function returnedᅠfromᅠtoodeepᅠㅣlineᅠ78 () {
    return function returnedᅠfromᅠᐸᅠreturnedᅠfromᅠtoodeepᅠᐳᅠㅣlineᅠ79 () {
      return function returnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠtoodeepᅠᐳᅠᐳᅠㅣlineᅠ80 () {

        return function returnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠtoodeepᅠᐳᅠᐳᅠᐳᅠㅣlineᅠ82 () {
          return function returnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠtoodeepᅠᐳᅠᐳᅠᐳᅠᐳᅠㅣlineᅠ83 () {
            return function returnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠtoodeepᅠᐳᅠᐳᅠᐳᅠᐳᅠᐳᅠㅣlineᅠ84 () {

              return function returnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠᐸᅠreturnedᅠfromᅠtoodeepᅠᐳᅠᐳᅠᐳᅠᐳᅠᐳᅠᐳᅠㅣlineᅠ86 () {
                return function () {
                  return function () {

                    return function () {

                    }                     

                  }
                }
              } 

            }
          }
        }        
      }
    }
  }
}

希望这能有所帮助!干杯!

1
任何未捕获的异常都会导致服务器停止。为了使服务器在出现未捕获的异常时仍然保持运行状态,我创建了一个单独的集合来存储错误,并在发生未捕获的异常时保存错误并返回。 集合
var ErrorSchema = new mongoose.Schema({
  err_Message:{type:String},
  err_Stack:{type:String},
  date:{type:Date}
});

控制器

process.on('uncaughtException', function (err) {
    console.log(err);
    console.error((new Date).toUTCString() + ' uncaughtException:', err.message);
    console.error(err.stack);

    var newError = new Error;
    newError.err_Message = err.message;
    newError.err_Stack = err.stack;
    newError.date = moment();
    newError.save(function(saveErr,errData){
        if(!saveErr)
            console.log('New Error is saved');
        else
            console.log('Error in saving error');
    });
    //process.exit(1)
});

上述方法将未捕获的异常存储在Error集合中,进程/服务器不会停止。
希望这可以帮到您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接