[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"content-alert_in_node":3,"$f35pzi4dnxrm5c":23},{"id":4,"type":5,"slug":6,"title":7,"date":8,"category":9,"tags":10,"body_markdown":14,"permalink":15,"excerpt_src":16,"media_type":16,"media_title":16,"media_author":16,"media_url":16,"rating":16,"layout":16,"pv":17,"admin_only":17,"created_at":18,"updated_at":18,"deleted_at":16,"status":19,"html":20,"excerpt":21,"cover":22},164,"article","alert_in_node","Node.js中低成本实现错误告警","2016-01-27 20:18","web",[11,12,13],"Node","错误","告警","\n相比其他语言（特指PHP）而言，Node.js应用更需要关注出错信息，因为一旦处理不慎，就会导致应用crash。\n\n一种偷懒的方法是使用[PM2](https:\u002F\u002Fgithub.com\u002FUnitech\u002Fpm2)之类的进程管理软件来启动Node.js进程，从而达到出错crash后自动重新启动应用的目的。\n\n当然更好的办法则是手工捕获错误，然后进行适当的处理，防止应用产生未被接住的错误导致crash。\n\n在捕获到Node.js产生的错误后，下一步自然是记录到错误日志中，以便日后可以进行分析，并针对性地排查修改。本文要说的，即是对错误日志的处理方式之一——告警。\n\n告警是运维工作中非常重要的一个环节，它能让开发者（维护者）及时获知应用出错状态和详情，及早介入处理，将线上故障的影响降低到最低。而要实现告警功能，则需要从两方面入手，一方面是对错误信息进行集中处理（分类、分级、合并、限流等），另一方面需要将这些错误信息及时推送出去。\n\n\u003C!-- more -->\n\n## 推送\n\n推送渠道可以有很多种，常见的包括邮件、短信、微信等，Geek一点的还可以考虑用slack、GTalk(死了吧)、Telegram机器人推送什么的。\n\n为了降低开发成本，这里选用了[Server Chan](http:\u002F\u002Fsc.ftqq.com\u002F1.version)作为推送服务，它的使用极其简单，只要登录之后就会获得一个key，然后访问带key的URL `http:\u002F\u002Fsc.ftqq.com\u002F{KEY}.send` 即可完成消息推送。而推送的渠道则有两种，一种是手机客户端，另一种是微信。想要哪种就使用哪种，在网站绑定即可，推送时是不分渠道的。\n\n## 日志\n\n接下来是应用的错误日志收集，在打听了很多方案之后先用了[bunyan](https:\u002F\u002Fgithub.com\u002Ftrentm\u002Fnode-bunyan)这个模块作为日志记录工具。bunyan的优势在于：\n\n- 结构化日志数据，方便后续整理分析\n- 完善的错误分级 `fatal` \u002F `error` \u002F `warn` \u002F `info` \u002F `debug` \u002F `trace` 一应俱全\n- 多种错误处理方式：文件、控制台、流\n- 可扩展：可以通过扩展流的方式自定义错误处理逻辑\n- 日志文件自动滚动\n\n这里我们主要用到bunyan的扩展性，自定义一个流来获取错误，然后在自定义的逻辑中调用推送逻辑完成告警。\n\n大概的代码：\n\n```javascript\nvar ServerChan = require('bunyan-serverchan');\n\nvar logger = bunyan.createLogger({\n\tname: 'myapp',\n\tstreams: [{\n\t\tlevel: 'error',\n\t\tstream: new ServerChan({key:'MY_KEY'})\n\t}]\n});\n```\n\n首先我们定义了一个`logger`用来记录日志，记录到的`error`级别以上的日志会送给`ServerChan`的实例（一个“stream”）。关于`ServerChan`，稍后解释。\n\n接下来，在出错的地方调用`logger`记录错误：\n\n```javascript\nxxx.on('error',function(err){\n\tlogger.error(err, 'Something went wrong:%s',err.message);\n});\n```\n\n此时错误的记录部分就算完成了，bunyan会负责将错误信息传递给`ServerChan`的实例。\n\n## ServerChan模块\n\n在上面的代码中，我们通过`require('bunyan-serverchan')`引入了`ServerChan`，这个模块负责接受错误信息，并调用Server Chan的URL完成推送。\n\n那这个模块到底是什么呢？\n\n没错，是我写的，欢迎到\u003Chttps:\u002F\u002Fgithub.com\u002FTooBug\u002Fbunyan-serverchan>围观。\n\n事实上这个模块的逻辑极其简单，调用构造函数之后会生成一个对象，只要保证这个对向的`write`方法是存在的，即可以用于bunyan的自定义stream。也就是说，虽然bunyan的概念中是一个自定义stream，但我们并不需要真的实现一个stream，只需要一个有`write`方向的对象即可。\n\n`write`方向负责接受错误信息，并完成自定义逻辑（推送）。\n\n## 结\n\nOver，就这么简单。\n","\u002Farticle\u002Falert_in_node.html",null,0,"2026-08-28 04:37:17","published","\u003Cp>相比其他语言（特指PHP）而言，Node.js应用更需要关注出错信息，因为一旦处理不慎，就会导致应用crash。\u003C\u002Fp>\n\u003Cp>一种偷懒的方法是使用\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FUnitech\u002Fpm2\">PM2\u003C\u002Fa>之类的进程管理软件来启动Node.js进程，从而达到出错crash后自动重新启动应用的目的。\u003C\u002Fp>\n\u003Cp>当然更好的办法则是手工捕获错误，然后进行适当的处理，防止应用产生未被接住的错误导致crash。\u003C\u002Fp>\n\u003Cp>在捕获到Node.js产生的错误后，下一步自然是记录到错误日志中，以便日后可以进行分析，并针对性地排查修改。本文要说的，即是对错误日志的处理方式之一——告警。\u003C\u002Fp>\n\u003Cp>告警是运维工作中非常重要的一个环节，它能让开发者（维护者）及时获知应用出错状态和详情，及早介入处理，将线上故障的影响降低到最低。而要实现告警功能，则需要从两方面入手，一方面是对错误信息进行集中处理（分类、分级、合并、限流等），另一方面需要将这些错误信息及时推送出去。\u003C\u002Fp>\n\u003Ch2>推送\u003C\u002Fh2>\n\u003Cp>推送渠道可以有很多种，常见的包括邮件、短信、微信等，Geek一点的还可以考虑用slack、GTalk(死了吧)、Telegram机器人推送什么的。\u003C\u002Fp>\n\u003Cp>为了降低开发成本，这里选用了\u003Ca href=\"http:\u002F\u002Fsc.ftqq.com\u002F1.version\">Server Chan\u003C\u002Fa>作为推送服务，它的使用极其简单，只要登录之后就会获得一个key，然后访问带key的URL \u003Ccode>http:\u002F\u002Fsc.ftqq.com\u002F{KEY}.send\u003C\u002Fcode> 即可完成消息推送。而推送的渠道则有两种，一种是手机客户端，另一种是微信。想要哪种就使用哪种，在网站绑定即可，推送时是不分渠道的。\u003C\u002Fp>\n\u003Ch2>日志\u003C\u002Fh2>\n\u003Cp>接下来是应用的错误日志收集，在打听了很多方案之后先用了\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Ftrentm\u002Fnode-bunyan\">bunyan\u003C\u002Fa>这个模块作为日志记录工具。bunyan的优势在于：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>结构化日志数据，方便后续整理分析\u003C\u002Fli>\n\u003Cli>完善的错误分级 \u003Ccode>fatal\u003C\u002Fcode> \u002F \u003Ccode>error\u003C\u002Fcode> \u002F \u003Ccode>warn\u003C\u002Fcode> \u002F \u003Ccode>info\u003C\u002Fcode> \u002F \u003Ccode>debug\u003C\u002Fcode> \u002F \u003Ccode>trace\u003C\u002Fcode> 一应俱全\u003C\u002Fli>\n\u003Cli>多种错误处理方式：文件、控制台、流\u003C\u002Fli>\n\u003Cli>可扩展：可以通过扩展流的方式自定义错误处理逻辑\u003C\u002Fli>\n\u003Cli>日志文件自动滚动\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>这里我们主要用到bunyan的扩展性，自定义一个流来获取错误，然后在自定义的逻辑中调用推送逻辑完成告警。\u003C\u002Fp>\n\u003Cp>大概的代码：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>var ServerChan = require('bunyan-serverchan');\n\nvar logger = bunyan.createLogger({\n\tname: 'myapp',\n\tstreams: [{\n\t\tlevel: 'error',\n\t\tstream: new ServerChan({key:'MY_KEY'})\n\t}]\n});\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>首先我们定义了一个\u003Ccode>logger\u003C\u002Fcode>用来记录日志，记录到的\u003Ccode>error\u003C\u002Fcode>级别以上的日志会送给\u003Ccode>ServerChan\u003C\u002Fcode>的实例（一个“stream”）。关于\u003Ccode>ServerChan\u003C\u002Fcode>，稍后解释。\u003C\u002Fp>\n\u003Cp>接下来，在出错的地方调用\u003Ccode>logger\u003C\u002Fcode>记录错误：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>xxx.on('error',function(err){\n\tlogger.error(err, 'Something went wrong:%s',err.message);\n});\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>此时错误的记录部分就算完成了，bunyan会负责将错误信息传递给\u003Ccode>ServerChan\u003C\u002Fcode>的实例。\u003C\u002Fp>\n\u003Ch2>ServerChan模块\u003C\u002Fh2>\n\u003Cp>在上面的代码中，我们通过\u003Ccode>require('bunyan-serverchan')\u003C\u002Fcode>引入了\u003Ccode>ServerChan\u003C\u002Fcode>，这个模块负责接受错误信息，并调用Server Chan的URL完成推送。\u003C\u002Fp>\n\u003Cp>那这个模块到底是什么呢？\u003C\u002Fp>\n\u003Cp>没错，是我写的，欢迎到\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FTooBug\u002Fbunyan-serverchan\">https:\u002F\u002Fgithub.com\u002FTooBug\u002Fbunyan-serverchan\u003C\u002Fa>围观。\u003C\u002Fp>\n\u003Cp>事实上这个模块的逻辑极其简单，调用构造函数之后会生成一个对象，只要保证这个对向的\u003Ccode>write\u003C\u002Fcode>方法是存在的，即可以用于bunyan的自定义stream。也就是说，虽然bunyan的概念中是一个自定义stream，但我们并不需要真的实现一个stream，只需要一个有\u003Ccode>write\u003C\u002Fcode>方向的对象即可。\u003C\u002Fp>\n\u003Cp>\u003Ccode>write\u003C\u002Fcode>方向负责接受错误信息，并完成自定义逻辑（推送）。\u003C\u002Fp>\n\u003Ch2>结\u003C\u002Fh2>\n\u003Cp>Over，就这么简单。\u003C\u002Fp>\n","\u003Cp>相比其他语言（特指PHP）而言，Node.js应用更需要关注出错信息，因为一旦处理不慎，就会导致应用crash。\u003C\u002Fp>\n\u003Cp>一种偷懒的方法是使用\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FUnitech\u002Fpm2\">PM2\u003C\u002Fa>之类的进程管理软件来启动Node.js进程，从而达到出错crash后自动重新启动应用的目的。\u003C\u002Fp>\n\u003Cp>当然更好的办法则是手工捕获错误，然后进行适当的处理，防止应用产生未被接住的错误导致crash。\u003C\u002Fp>\n\u003Cp>在捕获到Node.js产生的错误后，下一步自然是记录到错误日志中，以便日后可以进行分析，并针对性地排查修改。本文要说的，即是对错误日志的处理方式之一——告警。\u003C\u002Fp>\n\u003Cp>告警是运维工作中非常重要的一个环节，它能让开发者（维护者）及时获知应用出错状态和详情，及早介入处理，将线上故障的影响降低到最低。而要实现告警功能，则需要从两方面入手，一方面是对错误信息进行集中处理（分类、分级、合并、限流等），另一方面需要将这些错误信息及时推送出去。\u003C\u002Fp>\n","",{"total":24,"totalRoots":25,"comments":26,"pv":17},2,1,[27,34],{"id":28,"content":29,"user_id":30,"nick":31,"link":22,"date":32,"rid":17,"vote_up":17,"vote_down":17,"visible":33},140,"\u003Cp>logger.error(err, 'Something went wrong:%s',err.message); 可以用ES6的模板语法进行嵌套了\u003C\u002Fp>",7,"libo","2016-01-28 12:14:10",true,{"id":35,"content":36,"user_id":24,"nick":37,"link":22,"date":38,"rid":28,"vote_up":17,"vote_down":17,"visible":33},141,"\u003Cp>这个是bunyan的API调用方法啦，不是console.log，所以我不确定能不能这么写。似乎看起来也是可以的哈？\u003C\u002Fp>","TooBug","2016-01-28 13:29:54"]