例えば、DBで大量のトランザクションを処理してる時に、何かトラブルが発生したとしよう。ユーザーは文句言うし、ビジネス側も大騒ぎ。でも何が起きたのか全然見えない。そんな時に役立つのがちゃんとしたエラーログだよ。エラーログがあると:
- エラーをDBに保存して後で分析できる。
- エラーの詳細(発生時刻、メッセージ、関連データ)を簡単に復元できる。
- ログを分析してよくあるエラーを直すことで、コードの質も上げられる。
要するに、エラーログはDBの監視カメラみたいなもん。何がいつ起きたか全部見えるようになる。
error_log テーブルを作ろう
まずは基礎から始めよう。エラー情報を保存するテーブルを作るよ。テーブルのカラムはこんな感じ:
id— エラーのユニークID。error_message— エラーメッセージのテキスト。error_time— エラーが発生した時刻。- (オプション)
context— 詳細を保存したい時のエラーのコンテキスト。
CREATE TABLE error_log (
id SERIAL PRIMARY KEY, -- エラーのユニークID
error_message TEXT NOT NULL, -- エラーメッセージのテキスト
error_time TIMESTAMP NOT NULL DEFAULT NOW(), -- エラー発生時刻
context JSONB -- エラーの追加データ
);
これ何してるの?
id SERIAL PRIMARY KEY— 各レコードに自動でユニークIDを付ける。error_message TEXT NOT NULL— エラーメッセージを保存。必須項目。error_time TIMESTAMP NOT NULL DEFAULT NOW()— イベント発生時刻を記録。値を指定しなければDEFAULT NOW()で現在時刻が自動で入る。context JSONB— オプションで、例えばどんな操作中にエラーが起きたかなど追加情報を保存できる。
CREATE TABLE コマンドを実行すると、DBにログ保存用の構造ができるよ。
エラーをテーブルに記録する例
テーブルができたら、実際にエラー情報を保存してみよう。エラーメッセージと時刻を error_log に記録する関数を作るよ。
エラー記録用関数の例
CREATE OR REPLACE FUNCTION log_error(p_error_message TEXT, p_context JSONB DEFAULT NULL)
RETURNS VOID AS $$
BEGIN
INSERT INTO error_log (error_message, context)
VALUES (p_error_message, p_context);
END;
$$ LANGUAGE plpgsql;
p_error_message— エラーメッセージを受け取る引数。p_context— 追加データを渡すオプション引数。デフォルトはNULL。INSERT INTO error_log (error_message, context)—error_logテーブルに新しいレコードを追加。DEFAULT NULL— contextが指定されなければNULLになる。
エラーメッセージを記録したい時は、こんな感じで関数を呼び出せる:
SELECT log_error('クエリ実行中にエラー発生', '{"query": "SELECT * FROM data"}');
これで error_log テーブルに新しいレコードが追加される。
エラーの自動ログ化
毎回 SELECT log_error(...) を手で書くのは面倒だよね。例外処理を使ってこの作業を自動化しよう。
例外処理付き関数の例。
CREATE OR REPLACE FUNCTION divide_numbers(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
result NUMERIC;
BEGIN
-- 割り算を試す
result := a / b;
-- 結果を返す
RETURN result;
EXCEPTION
WHEN division_by_zero THEN
-- エラーをログしてcontextも渡す
PERFORM log_error('ゼロで割り算', jsonb_build_object('a', a, 'b', b));
-- ユーザー向けに例外を投げる
RAISE EXCEPTION '値 % を % で割るのは無理 — 割る数がゼロだよ', a, b;
END;
$$ LANGUAGE plpgsql;
- 割り算チェック:
result := a / bを実行。b = 0ならPostgreSQLがdivision_by_zero例外を投げる。 - 例外ハンドラ(
EXCEPTION)がエラーをキャッチ。 - ハンドラ内で
log_errorを呼び出して、エラーとパラメータをテーブルに記録。 RAISE EXCEPTIONでユーザーにもエラーメッセージを返す。
呼び出し例:
SELECT divide_numbers(10, 0);
結果:
- ユーザーには
値 10 を 0 で割るのは無理 — 割る数がゼロだよというエラーが表示される。 error_logテーブルにはゼロ割りの記録が残る。
GO TO FULL VERSION