CodeGym /コース /SQL SELF /関数による自動ログ記録

関数による自動ログ記録

SQL SELF
レベル 52 , レッスン 3
使用可能

関数による自動ログ記録

例えば、自分のbotをデータベースで自由に動かして、複雑な操作をさせてみたとしよう。いつかはbotがつまずいたり、ミスしたり、予想外の状況に遭遇したりするよね。ログがなければ、botは黙り込んで、何が起きたのか全然分からなくなっちゃう。自動ログ記録があれば:

  • エラーや警告が発生したタイミングを追跡できる。
  • トラブルの原因や内容を理解できる。
  • コードの診断やパフォーマンス改善がしやすくなる。

自動ログ記録を使えば、データベースの「ブラックボックス」を作れて、イベントを記録しながら、まるで一流の探偵みたいにバグを見つけられるんだ。

関数で自動ログ記録を作る方法

  1. ログ用テーブルを定義する

エラーを記録するには、保存場所が必要だよね。前のレクチャーでerror_logテーブルを作ったよ:

CREATE TABLE error_log (
    id SERIAL PRIMARY KEY,                 -- レコードのユニークID
    error_message TEXT NOT NULL,          -- エラーメッセージ
    error_time TIMESTAMP DEFAULT NOW(),   -- エラー発生時刻
    function_name TEXT                    -- エラーを出した関数名
);

このテーブルにはエラー記録に必要なものが全部入ってる:エラーテキスト、発生時刻、どの関数から出たか。

  1. ログを書き込む関数を作る

次のステップは、エラーをerror_logテーブルに書き込む汎用関数を作ること。この関数は、エラーを記録したい時にいつでも呼び出せるよ。

CREATE OR REPLACE FUNCTION log_error(p_error_message TEXT, p_function_name TEXT)
RETURNS VOID AS $$
BEGIN
    INSERT INTO error_log (error_message, function_name)
    VALUES (p_error_message, p_function_name);
    -- ログ記録成功メッセージ
    RAISE NOTICE 'エラーが記録された: %', p_error_message;
END;
$$ LANGUAGE plpgsql;

このコードを解説するね:

  1. p_error_messagep_function_nameは、エラーメッセージと呼び出し元関数名を受け取るパラメータ。
  2. INSERT INTO error_logでテーブルにレコードを追加。
  3. RAISE NOTICEで、ログ記録の進行状況を開発者にコンソールで知らせる。

これで最初の課題はクリア!最小限の手間でエラーをテーブルに記録できるようになった。

実際のタスクでlog_error関数を使う

例1: 0で割った時のエラーをログに記録

簡単な割り算をする関数を作ってみよう。ただし、もし分母が0ならエラーをログに記録するよ。

CREATE OR REPLACE FUNCTION divide_numbers(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
    result NUMERIC;
BEGIN
    IF b = 0 THEN
        -- ログ記録関数を呼び出す
        PERFORM log_error('0で割ろうとした!', 'divide_numbers');
        -- 例外を発生させる
        RAISE EXCEPTION '0で割るのは禁止だよ。';
    END IF;

    -- 割り算を実行
    result := a / b;
    RETURN result;
END;
$$ LANGUAGE plpgsql;
  • 分母が0なら、log_error関数が呼ばれてエラーがテーブルに記録される。
  • エラー記録の後、RAISE EXCEPTIONでユーザーに例外を通知。

呼び出し例:

SELECT divide_numbers(10, 0);

結果:

  • この関数を0で割る引数で呼ぶと、error_logテーブルにエラーが記録される。
  • ユーザーはコンソールでエラーメッセージを見ることができる。

例2: 無効なデータ挿入時のログ記録

studentsテーブルに新しい学生を追加する関数の例を見てみよう。もし学生名が空なら、イベントをログに記録して処理を中断するよ。

CREATE OR REPLACE FUNCTION add_student(p_name TEXT)
RETURNS VOID AS $$
BEGIN
    IF p_name IS NULL OR p_name = '' THEN
        PERFORM log_error('学生名は必須だよ!', 'add_student');
        RAISE EXCEPTION '学生名は空にできないよ。';
    END IF;

    INSERT INTO students (name) VALUES (p_name);
END;
$$ LANGUAGE plpgsql;

呼び出し例:

SELECT add_student('');

名前なしで学生を追加しようとすると、関数はerror_logに対応するメッセージでレコードを作るよ。

例3: 警告のログ記録

ユーザーに例外を投げる必要がない場合もある。そんな時は警告だけ記録すればOK。学生の年齢チェック関数を作ってみよう:

CREATE OR REPLACE FUNCTION check_age(p_age INT)
RETURNS VOID AS $$
BEGIN
    IF p_age < 18 THEN
        -- 警告をログに記録、処理は中断しない
        PERFORM log_error('学生の年齢が18未満だよ。', 'check_age');
        RAISE NOTICE '警告: 学生の年齢が18未満だよ。';
    END IF;

    RAISE NOTICE '年齢チェックOK。';
END;
$$ LANGUAGE plpgsql;

呼び出し例:

SELECT check_age(16);

結果:

  • error_logテーブルに警告が記録される。
  • 学生の年齢が18未満だとコンソールで通知される。

ログ記録と例外処理

エラー記録と例外処理を組み合わせた、ちょっと複雑な関数も作ってみよう。例えば、gradesテーブルで学生の成績を再計算するタスクがあるとする。もし1人の学生で処理が失敗しても、エラーをログに記録して、他のデータの処理は続けるよ。

CREATE OR REPLACE FUNCTION recalculate_grades()
RETURNS VOID AS $$
DECLARE
    student RECORD;
BEGIN
    FOR student IN SELECT * FROM students LOOP
        BEGIN
            -- 例: 学生の成績を更新
            UPDATE grades SET final_grade = final_grade + 1
            WHERE student_id = student.id;

            RAISE NOTICE '学生%の成績を更新したよ', student.name;
        EXCEPTION WHEN OTHERS THEN
            -- エラーをログに記録して処理を続行
            PERFORM log_error('学生' || student.name || 'の成績更新に失敗した', 'recalculate_grades');
        END;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

呼び出し例:

SELECT recalculate_grades();

このやり方なら、関数がもっとタフになって、エラーは個別にログに残しつつ、全データの処理を止めずに済むよ。

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION