【Haskell学習|初心者向け】Haskellで実現する!Sentry/Honeybadger向けのエラー構造化と可視化術

1. 導入:なぜ例外の「構造化」が必要なのか?

Webアプリケーションを運用していると、本番環境で「何が起きたのか分からないエラー」に直面することがあります。単にログに文字列を吐き出すだけでは、原因の切り分けに時間がかかり、対応が遅れてしまいます。
SentryやHoneybadgerのような監視サービスを活用し、Haskellの例外を「構造化(JSON形式)」して送信することで、スタックトレースやコンテキスト情報が一目で把握できるようになります。これは、モダンな開発現場において「見えないエラー」を可視化するための必須スキルです。

2. 基礎知識:Haskellの例外とJSON

Haskellでは、例外(Exception)は型クラスとして扱われます。エラー監視サービスに送信するためには、この例外を特定のJSONフォーマットに変換する必要があります。
ここで重要になるのが「型クラスのインスタンス化」と「Aesonライブラリ」です。AesonはHaskellでJSONを扱うための標準的なライブラリで、これを使って例外情報を機械が読み取りやすい形へとシリアライズします。

3. 実装・解決策:例外を構造化して送信する手順

実装の基本方針は以下の3ステップです。
1. 例外型を定義し、ToJSONインスタンスを実装する。
2. 例外発生時にスタックトレースを取得する(GHC.Stackを使用)。
3. HTTPクライアント(http-clientなど)を使用して、エラー監視サービスのAPIエンドポイントへPOSTリクエストを送る。

特に重要なのは「スタックトレースのキャプチャ」です。Haskellの関数呼び出し履歴をJSONに含めることで、コードのどの行で失敗したのかを特定しやすくなります。

4. サンプルプログラム

以下は、例外をJSONに変換して送信するイメージコードです。

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}

import GHC.Generics
import Data.Aeson
import GHC.Stack

— 1. エラー情報を保持するデータ型を定義
data AppError = AppError
{ message :: String
, callStack :: String
} deriving (Show, Generic)

— JSONに変換できるようにする
instance ToJSON AppError

— 2. 例外を投げる関数(スタックトレース付き)
throwError :: HasCallStack => String -> IO ()
throwError msg = do
let err = AppError msg (prettyCallStack callStack)
— ここで実際にはHTTPリクエストでSentry/Honeybadgerに送信する
putStrLn $ “外部サービスへ送信するJSONデータ: ” ++ show (encode err)

main :: IO ()
main = do
— エラー発生時のシミュレーション
throwError “データベース接続に失敗しました”

5. 応用・注意点:現場での運用Tips

・機密情報の除外
例外データにパスワードや個人情報が含まれていないか注意してください。構造化する際に、自動的に特定のフィールドを除外するフィルターを実装することをお勧めします。

・送信の非同期化
HTTPリクエストはブロッキング処理となるため、メインのアプリケーションスレッドで行うとパフォーマンスが低下します。必ず「非同期キュー」や「軽量スレッド(forkIO)」を利用して、エラー送信がメイン処理を遅延させないように設計してください。

・スタックトレースの精査
Haskellは遅延評価のため、スタックトレースが必ずしも期待通りの呼び出し元を指さないことがあります。必要に応じて `HasCallStack` 制約を関数に付与し、トレースの精度を高める工夫をしましょう。

この仕組みを導入するだけで、運用の安定性は劇的に向上します。ぜひ、次回のプロジェクトから取り入れてみてください。

コメント

タイトルとURLをコピーしました