インフラブログ

とあるWEBサイトのインフラを構築運用するメモ

hubotを使ってあれこれする(mongodbをtailする)

サイトの50xエラー発生時になるべくリアルタイムで社内に周知する。

運用しているサイトで50xエラーが発生した際に、なるべくリアルタイムで社内に周知したいと考えていました。 nginxのログはcapped属性でmongodbにも集約しているので、これを常時tail監視してエラー検知時にアラートを発報するようにします。 さらにhubotのスクリプトとして動くようにすれば、hipchatにも周知しやすくなるので、今回はhubotのスクリプトにしました。(下記のサンプルではhipchatに流していませんが・・・)

簡単な仕様

  • 動きとしては、mongoのカーソル使ってログを500系エラーのログのみtailするようにします。
  • エラーかどうかはngxinログのupstream_statusのステータスコードで判定します。
  • 該当データが発生した場合はonイベントで音を鳴らすようにします。音はafplayコマンドで指定のアラート音を鳴らすだけです。
  • 瞬間的に大量の50xエラーが発生した場合、afplayコマンドが多重で大量に叩かれてプロセス生成できなくなるエラーが発生したので、afplayプロセス起動中は別のafplayが起動できないようにフラグ管理しておきます。
  • フラグはhubotのbrain(redis)で保持します。

  • scripts/mongo_tail.coffee

util = require('util')
mongojs = require('mongojs')
spawn = require("child_process").spawn;

HOST = process.env.MONGO_HOST
DB = process.env.MONGO_DB
COLL = process.env.MONGO_COLL
ALARM = "alarm_flag"
FLAG_RESET_INTERVAL = 1 * 60 * 1000
SITE = "mysite"

module.exports = (robot) ->

  cursor = {}
  db = {}

  robot.brain.set(ALARM, false)

  setInterval(()->
    robot.brain.set(ALARM, false)
  , FLAG_RESET_INTERVAL)

  alarm = (site, doc) ->
    console.log("site:" + site)
    console.log(doc)
    unless robot.brain.get(ALARM)
      robot.brain.set(ALARM, true)
      cli = spawn("/usr/bin/afplay", ["/se/" + site + doc.upstream_status + ".mp3"])
      cli.on 'exit', (code) ->
        robot.brain.set(ALARM, false)

  db = mongojs(HOST + '/' + DB, [COLL])
  cursor = db[COLL].find({upstream_status:/50\d/}, {},
    tailable: true
    timeout: false)

  cursor.on 'data', (doc) ->
    alarm(SITE, doc)
    return