ボクココ

サービス開発を成功させるまでの歩み

Heroku の Papertrail でログからコードを実行する方法

ども、@kimihom です。

今回は Heroku アドオンの Papertrail の活用方法についてご紹介。

このアドオンが単なるブラウザ上で綺麗にログを見れるだけのアドオンかと思っていたら、それは Papertrail の 3分の1の魅力しか知っていないことになる。Papertrail の本当の威力を発揮するのは、Alert 機能だ。今回は、この Alert 機能を使って、ログから得られたデータを下に任意のコードを実行する方法についてご紹介する。

概要図

今回は特定のログが吐き出された時に、任意のコードを実行するような想定を考える。以下のような構成図だ。

f:id:cevid_cpp:20170608221458p:plain

“Heroku は AWS で動いているだろ” という 細かいツッコミは置いておいていただいて、AWS Lambda と API Gateway の部分は自前の AWS で用意する必要がある。なので今回はその流れについてもご案内する。

STEP 1. JSON のログを書き出す

まずは Papertrail のイベントをキャッチできるようにするために、アプリケーションから特定のログを出力する必要がある。JSON 形式で書き出すようにすると、あとで処理が楽なのでオススメだ。一応 Ruby (Rails) でのサンプルコードを書いておく。

user = User.find_by(params[:id])
log_info = {
  tag: "PTLog",
  name: user.name,
  id: user.id,
  email: user.email
}
logger.info(log_info.to_json.to_s)

ここで任意の “タグ” を用意することが肝心だ。この値を下に Papertrail の Alert として設定するようにする。

STEP 2. Papertrail で Webhook の設定を実施

さて、特定のログをHeroku から出力したら、いよいよ Papertrail の出番だ。Papertrail アドオンをインストールした後の手順をご紹介する。

f:id:cevid_cpp:20170608222342p:plain

  1. 出力した “タグ” にマッチするログだけを出力するために、 “PTLog” と入力し、Search をクリック
  2. Save Search をクリックし、検索を保存
  3. 名前をつけて Save & Setup an Alert

そしたら今度は Alert をセットする方法について選択する項目が出てくる。 Slack や HipChat を使っている場合は、このまま重要なログであれば通知すれば済むだけの話だけど、今回はコードを実行したいので、"Webhook" を選択。

f:id:cevid_cpp:20170608222838p:plain

Frequency に関してはしょっちゅう起きるイベントなら 1min、そうでなければ 10min とかお好みで問題ない。同じログが短期間で一気に来たとしても、 Papertrail は 配列として データを送ってくれるため、心配ご無用だ。

さて、肝心の Webhook の URL が今回のキモだ。

STEP 3. AWS Lambda と API Gateway のセットアップ

最近は便利になったもので、 AWS Lambda に色々とデフォルトで用意されたテンプレートがあるのでそれを利用しよう。

  1. ランタイムの選択で Node.js 6.10 を選択
  2. microservice-http-endpoint を選択
  3. API 名を適当に作り、セキュリティをオープンで Next
  4. 関数名と名前を適当に編集
  5. コードを下のように修正
  6. ロールは無ければ作って次へ
  7. 最終確認して作成ボタンをクリック

Node.js コードのサンプルは以下のようなイメージだ。

exports.handler = (event, context, callback) => {
  console.log('Received event:', JSON.stringify(event, null, 2));

  const done = (err, res) => callback(null, {
    statusCode: err ? '400' : '200',
    body: err ? err.message : JSON.stringify(res),
    headers: {
      'Content-Type': 'application/json'
    }
  });

  let body = event.body;
  let log = JSON.parse(decodeURIComponent(body.slice(8, body.length)));
  console.log(log);

  log.events.forEach((evt) => {
    let json = JSON.parse(evt.message.slice(0, evt.message.length - 1));
    // ログで出力した JSON が処理できる!
  });

  done();
}

ここで decodeURIComponent したり slice したりしているのは Papertrail が Webhook で書き出すデータを微調整するために行っているもので、きっと誰もが共通の処理をすることになるだろう。これで晴れて Heroku のログに出力した関数を AWS Lambda 内で好きに扱うことができるようになった!

おっと、最後に Papertrail の Webhook URL を API Gateway が生成した URL にセットするのをお忘れなく。 https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/yyyyyyyy のような URL になってることかと思う。

あとは煮ても焼いても・・・。お好みに。きっと運用フェーズで例えば外部サービスの API を呼んだりすることで、データ連携や重要な通知をしたりといったことができるはずだ。

終わりに

運用フェーズではいかに効果的にデータを集積し、サービスの改善に生かせるかが課題になってくるかと思う。しかし、通常のアプリケーション内でそのような情報を外部に送るようなコードを書いてしまうと、そのぶんユーザーへのレスポンス速度が遅くなり、ユーザー体験を悪化させてしまう。そんな時はログからイベントをトリガとして発生させ、それに応じてコードを実行させるようにすることでユーザー体験を損ねることなくデータを蓄積していくことが可能だ。

最後に宣伝になるがこのような Heroku の開発/運用 Tips をシェアする Heroku Meetup があるので、よければ参加してほしい!今回は Heroku をガチで使っている方々からの運営事例と、Heroku 最新 Tips をお届けする予定だ。

herokujp.doorkeeper.jp f:id:cevid_cpp:20170608230018p:plain