クラウドワークス エンジニアブログ

日本最大級のクラウドソーシング「クラウドワークス」の開発の裏側をお届けするエンジニアブログ

Rollbar による快適通知生活

こんにちは、エンジニアの Bugfire です。

最初 protoc について書こうかなと思っていたのですが、時間的な都合で Rollbar についての記事を書きます! 入社してから初めて知ったのですがとても良いサービスです。

クラウドワークスでは、モニタリング用に様々なサービスを利用しています、一例をあげると CloudWatch, New Relic, Datadog そして今回の Rollbar です。

過去の記事 「エラーモニタリングサービス Rollbar と GitHub Issue を利用したエラー対応フロー」 でも一度書かれていますが、今回は設定を詳細に記述します。

サンプルは全て Ruby で書かれています。
SDKの組み込み方法については、プラットホーム毎に異なりますので、ここでは記述しません。

公式サイトのドキュメント からの抜粋であり特別なノウハウはあまりありません。

目次

1. Rollbar のエラー登録方法

Rollbar には大きく分けて二つのエラーの登録方法があります。

コードからエラーを登録タイプ
Uncaught exception を自動登録タイプ

※ エラーレベルは debug, info, warning, error, critical から選択が可能です。

コードからエラーを登録タイプ

明示的にコードから API を呼び出し、エラーを登録します。
登録時に任意の Key-Value を付加することができます。(以下 Extra データ)

メッセージログ

コードから API を呼び出し、文字列でエラーを登録します。
スタックトレースは付加されないため、問題を解決する必要十分な情報を自ら登録する必要があります。

また Rollbar Item はメッセージで分類されるため、同じ Rollbar Item で管理したい場合は、メッセージに変数を埋め込まない方が良いでしょう。

#1
Rollbar.error('普通のエラー')
#2
Rollbar.info('エラーですよ', {
    :comment => '本当に',
    :user => 'ザンギエフ'
})

Rollbar.LEVEL(msg, ...) の代わりに、Rollbar.log("LEVEL", msg, ...) と書いても良いです。

f:id:bugfire:20200130181353p:plain:w500
一覧画面(メッセージ)

  • 第一引数は、エラーのタイトルになります。
  • #2 の第二引数の Hash は Extra データ で、Rollbar Item の Occurrences で message.extra.* として表示されます。

f:id:bugfire:20200130181632p:plain:w500
詳細画面(Extra データサンプル)

※ 推奨しませんが Hash のみを渡すことも可能なようです。その場合はエラーのタイトルは Empty message になるようです。

例外ログ

コードから API を呼び出し、例外でエラーを登録します。

begin
    raise '例外です'
rescue Exception => e
    #3
    Rollbar.error(e)
    #4
    Rollbar.error(e, 'よく見えない')
    #5
    Rollbar.error(e, 'これで勝つる', {
        :comment => 'もうついたのか',
        :hayai => 'はやい!'
    })
end

f:id:bugfire:20200130181907p:plain:w500
一覧表示(例外)

  • エラーのタイトルは、#{e.class}: #{e.message} になります。
  • #4 #5 の第二引数の文字列は、Rollbar Item の Occurrences で trace.exception.description というカラムで閲覧ができます。
  • #5 の第三引数の Hash は Extra データ で、Rollbar Item の Occurrences で trace.extra.* として表示されます。

f:id:bugfire:20200130182455p:plain:w500
詳細画面(例外)

例外クラス・スタックトレースのファイル・関数単位で Rollbar Item を作成するため、上の3つの例では同じ Rollbar Item として取り扱われます。

Uncaught exception を登録タイプ

前の項のコードからエラーを出力するタイプ( #例外ログ )と同様です。Uncaught exception は自動的に Rollbar.error() で登録されます。

基本的に例外はエラーレベル error で送信されますが、Rollbar.configure で特定の例外のエラーレベルを変更したり、https://rollbar.com から登録済の Rollbar Item のエラーレベルの変更ができます。

2. グルーピング

基本的に同じエラーは同じ Rollbar Item にまとめられます(以下グルーピング)。

グルーピングの公式サイトでの説明はこちら Grouping Occurrencesです。

メッセージログの自動グルーピング

メッセージから、タイムスタンプや、数値(小数点含む)、HEX表記を削除した文字列の hash を元にグルーピングします。

例外ログの自動グルーピング

例外クラス名と、スタックトレースのうちファイル名・メソッド名の hash を生成し、その hash を元にグルーピングします。

※ 行番号やファイルのハッシュは利用しません
※ 例外メッセージはデフォルトでは利用しませんが、利用するようにする設定項目もあります

Custom Fingerprinting による手動グルーピング

グルーピングのもとになる fingerprint と、関連して表示に使用する title を、例外ログからパターンマッチングで生成することができます。

Custom Fingerprinting の公式サイトでの説明はこちらです。

設定するには エラー発生時の Raw JSON を参考にします。

最初に、Rollbar Item の詳細画面から Occurrences から適当に一つ選択し、

f:id:bugfire:20200131160853p:plain:w500
詳細画面

Occurence 表示画面から Raw JSON のところを参照します。

f:id:bugfire:20200131161203p:plain:w172
詳細画面(Occurrences)

このJSONを元にルールを作成します。

ルール指定

このルールはとても柔軟に記述ができます。設定はルールの配列になっており、ルールはこのようになります。

  • 最上位ノードcondition fingerprint title のみ指定する。condition中間ノードもしくは末端ノードを一つ指定する。
  • 中間ノードany all none とともに、中間ノードもしくは末端ノードの配列を指定する。
  • 末端ノードpathOperator を指定する。

シンプルな例

{
  "body": {
    "trace": {
      "frames": [
        {
          "省略": "省略"
        }
      ], 
      "exception": {
        "message": "Net::ReadTimeout", 
        "class": "Net::ReadTimeout"
      }
    }
  }, 
  "省略": "省略"
}

このように書かれていれば、見るべきは body.trace.exception.class, body.trace.exception.message あたりになります。 この例外を拾うのであれば、

[
  {
    "condition": {
      "eq": "Net::ReadTimeout", 
      "path": "body.trace.exception.class"
    }, 
    "fingerprint": "Net::ReadTimeout", 
    "title": "Net::ReadTimeout {{context}}"
  }
]

と書くことで、一つの例外クラスで fingerprint (グルーピング識別子) を例外共通にすることができます。

最上位ノード

titlefingerprint では以下の Template を使用できます。

Template 説明
{{default_fingerprint}} この例外の持つデフォルトの fingerprint
{{default_title}} この例外の持つデフォルトの title
{{body.trace.exception.class}}
{{ context }}
JSON Path を指定するとそのパスの文字列等を埋め込むことができます

特定の例外で、message 毎に別の Rollbar Item にしたい場合は fingerprint{{default_fingerprint}}-{{body.trace.exception.message}} のようにすることで、メッセージに依存した fingerprint を指定することができます。

Templateの例

[
  {
    "condition": {
      "all": [
        {
          "eq": "Net::ReadTimeout", 
          "path": "body.trace.exception.class"
        }, 
        {
          "eq": "Net::ReadTimeout", 
          "path": "body.trace.exception.message"
        }
      ]
    }, 
    "fingerprint": "Net::ReadTimeout {{context}}", 
    "title": "Net::ReadTimeout {{context}}"
  }
]

中間ノード

Condition 説明
any = or, 配列で指定した中間ノードもしくは末端ノードのいずれかを満たす時
all = and, 配列で指定した中間ノードもしくは末端ノードのすべてを満たす時
none = not, 配列で指定した中間ノードもしくは末端ノードのすべてを満たさない時

末端ノード

path には JSON Path を指定します。

Operator には以下のものがあります。

Operator 説明
eq 指定した値と等しい
neq 指定した値と等しくない
in 指定した文字列もしくはリストに含まれている
nin 指定した文字列もしくはリストに含まれてない
contains 文字列・要素・キーが含まれている
ncontains 文字列・要素・キーが含まれていない、もしくは文字列・配列・オブジェクトではない
startswith 指定の文字列で始まっている
endswith 指定の文字列で終わっている
gt 指定の数字より大きい
gte 指定の数字より大きいまたは等しい
lt 指定の数字より小さい
lte 指定の数字より小さいまたは等しい
regex_match 指定の正規表現で該当したとき

key に Operator を指定して、value に比較する値やリストを指定します。

見れば何となく予想のつきそうなものばかりですが、設定画面にテストツールがあるので、設定しながら試してみるのが良いでしょう。 (私はプロジェクトで全ての設定をまとめた JSON を指定するので、別エディタで変更しながら貼り付けています。)

JSON Path

オブジェクトの key を . で接続し、上位から列挙していきます。配列の場合は key の部分は配列のインデックス(0~)とします。

配列の場合は インデックスを -1 とすることで最後の要素を示し、* とすることで配列中のいずれかにおいて条件を満たす要素があることを指すこともできます。

ネストされた例外

{
  "body": {
    "trace_chain": [
      {
        "frames": [
          {
            "method": "xxx0", 
            "lineno": xxx0, 
            "filename": "/xxx0"
          }
        ], 
        "exception": {
          "message": "xxx0", 
          "class": "xxx0"
        }, 
        "extra": {}
      }, 
      {
        "frames": [
          {
            "method": "xxx1", 
            "lineno": xxx1, 
            "filename": "/xxx1"
          }
        ], 
        "exception": {
          "message": "xxx1", 
          "class": "xxx1"
        }
      }
    ]
  }, 
  "context": "controller#method", 
}

このように、例外がネストされていると body.trace_chain に例外の配列が入ります。
したがって、以下のように記述することになります。

[
  {
    "condition": {
        "eq": "xxx0", 
        "path": "body.trace_chain.0.exception.class"
    }, 
    "fingerprint": "xxx0", 
    "title": "xxx0"
  }
]

メニューからの手動グルーピング

Rollbar Item 一覧画面で複数の Rollbar Item を選び、Merge Item を選ぶことで複数の Rollbar Item を一つにまとめることができます。

f:id:bugfire:20200204194408p:plain:w500
一覧画面(手動グルーピング)

まとめられたグループでは、Rollbar Item 詳細画面の Occurrences の隣に Member Items のタブが表示されます。

f:id:bugfire:20200204194712p:plain:w300
詳細画面(Member Items)

まとめ

基本は手動グルーピングで行い、 stacktrace が広範にわたる Middleware に起因するようなエラーや、特定用途に生成した例外を扱う場合などは Custom Fingerprinting を定義すると楽ができます。

3. Rollbar Item と Slack, Github Issue の連携

https://rollbar.comSettings/Project Settings/Notifications から

  • Slack で通知を行う
  • Github Issue と連携を行う

といったことができます。

Slack での通知

主題の Slack での通知ですが、以下のテンプレートが存在します、

f:id:bugfire:20200130192229p:plain:w300
Slack テンプレート選択

今回のエラー通知で関係するのは

  • 10^nth Occurrence → Post Message
  • High Occurrence Rate → Post Message
  • New Item → Post Message
  • Every Occurrence → Post Message

の四つです。それぞれ説明していきます。

通知ルール

10^nth Occurrence → Post Message

10n、つまり、10, 100, 1000, ... (1は除く) の回数で通知を行います。つまり間隔がどんどん10倍になっていくわけですから、繰り返すうちに通知されなくなります。あってもなくても良いような気がしますが、害はないです。忘れた頃に届くと思い出します。

High Occurrence Rate → Post Message

1分、5分、30分、1時間、1日あたりN件(N: 任意指定)のエラーが発生した場合に通知を行います。なんらかの理由で解決できないようなエラーで、エラー頻度が見積もれる場合はそれを閾値に指定します。恒久的に Mute or 見て見ぬ振りをするくらいなら、こちらを設定すべきだと考えています。

New Item → Post Message

新規エラー発生時に通知を行います。これは必須です。

Every Occurrence → Post Message

毎回エラー発生時に通知を行います。エラーの根本的修正はできないが、なんらかの対応のために発生を知りたい時に指定します。この場合は Github Issue は一つになるので対応記録は別の方法をとる必要があります。(例えば Slack での reaction、thread 等)

通知内容

メッセージは任意で設定ができ、template 変数 {{variable-name}}{{body.JSON Path}} を使用することができます。色々な変数があるので公式の記事を見ると良いです。

なお、注意点としてトップレベルは Occurrence の JSON Object ではないので、そちらを参照する場合の JSON Path は body. の prefix がつきます。つまり、 Extra データへのアクセスは、{{body.body.message.extra.XXX}} のように行います

定義の共有

上の設定は GUI で大量に設定したいようなものではないので、できるだけ少ない設定を使いまわしたいです。

Title に特定文字列を付加し、Tilte で contains を行う Filter を設定することで設定を共有することができます。

この Title への文字列の付加は、Rollbar Item を後から変更してもそれが有効になります。つまり、Rollbar Item Title の編集を用いて既存のエラーに属性を付与することができます。

  • 別チャネルで報告して欲しい
  • 一定の頻度以上での発生で通知が欲しい場合
    • High Occurrence Rate → Post Message で DAU に応じて閾値を変更する
  • 毎回通知して欲しい
    • Every Occurrences
    • (後に述べるエラーレベルで Critical にするなどの方法もあります)

Github Issue との連携

Rollbar 上の Item が作成されたとき、Resolved のものが Re-open された時などに、連動して Github Issue を作成・変更することができます。

f:id:bugfire:20200219144942p:plain:w300
Github 連携テンプレート

f:id:bugfire:20200219143153p:plain:w500
Github Issue の一覧

Github Issue の本文に、Rollbar Item へのリンクと stacktrace が自動的に記入されます。

f:id:bugfire:20200219143201p:plain:w500
Github Issue の詳細

Item Resolved → Resolve Issue のルールを設定があれば、Rollbar Item を Resolved に設定することで自動的に Github 側も Close することができます。

Rollbar Item と Github Issue の関連付けは作成時に行われるため、Rollbar 上は扱いたいが、Github 上では扱いたくない場合は、Rollbar 上で Unlink thig Github Issue で接続を切り、Github 上で Close します。

※ Reactivated と Reopen の違いは、Reactivated は新しい depoyment で再発生した場合、Reopen は手動で open しなおしたか、同じ depoyment で再発生した場合。詳しくは 公式サイト Rollbar Terminology

エラーレベル

エラーレベルを連携時のフィルタとして利用することで、簡単なグルーピングができます。

例えば、以下のようにすることで、通知と Github Issue の量をコントロールできます。

エラーレベル Slack Github Issue
debug 通知なし 連携なし
info 通知なし 連携なし
warning 通知あり #warning 連携なし
error 通知あり #error 連携あり
critical 発生都度通知あり #critical 連携あり

一度発生したエラーも後からエラーレベルを変更することが可能なため、状況をみてエラーレベルを変更し次回での通知を変更するのもよいでしょう。

手動グルーピング

手動グルーピングで生成された Rollbar Item は自動的に Github Issue に連携されないため、Create Github Issue メニューから手動で Github Issue も生成するか、Link existing Github Issue で既存の Github issue に割り当てる必要があります。

4. 最後に

Rollbar にはまだまだ書ききれないほどの機能があります!
今回ブログを書くにあたり、雰囲気で扱わずに公式ドキュメントを眺めてみると発見の宝庫でした。

グルーピングが適切に行われていないと、エラー件数の把握が曖昧になり、どのように対処していくかの方針が決めづらくなります。 ※ 全てのエラーをなくすのなら気にしなくて良いです!

通知は多すぎても少なすぎても問題があります。適切なエラーを適切な頻度で伝えられるように設定できると快適かつ安全に運用できますね!

We Are Hiring!

クラウドワークスでは DevOps が好きなエンジニアを募集しています!

www.wantedly.com

© 2016 CrowdWorks, Inc., All rights reserved.