CodeGym /Các khóa học /SQL SELF /Ghi log tự động qua function

Ghi log tự động qua function

SQL SELF
Mức độ, Bài học
Có sẵn

Hãy tưởng tượng bạn thả con bot của mình đi lang thang trong database để nó làm mấy thao tác phức tạp. Sớm hay muộn nó cũng sẽ vấp, bị lỗi hoặc gặp tình huống bất ngờ. Nếu không có log, nó sẽ im re luôn, còn bạn thì ngồi đoán không biết chuyện gì vừa xảy ra. Ghi log tự động giúp bạn:

  • Theo dõi khi nào có lỗi hoặc cảnh báo xuất hiện.
  • Hiểu được bản chất và lý do của lỗi.
  • Cải thiện việc chẩn đoán và hiệu năng code.

Với ghi log tự động, bạn tạo ra một "hộp đen" ghi lại mọi sự kiện trong database, giúp bạn tìm lỗi như một thám tử xịn sò.

Tạo ghi log tự động bằng function

  1. Định nghĩa bảng log

Để ghi log lỗi, mình cần chỗ để lưu lại. Mình đã tạo bảng error_log ở bài trước rồi nè:

CREATE TABLE error_log (
    id SERIAL PRIMARY KEY,                 -- Định danh duy nhất cho bản ghi
    error_message TEXT NOT NULL,          -- Thông báo lỗi
    error_time TIMESTAMP DEFAULT NOW(),   -- Thời điểm lỗi xảy ra
    function_name TEXT                    -- Tên function gây ra lỗi
);

Bảng này có đủ thứ cần thiết để ghi lỗi: nội dung lỗi, thời gian và tên function phát sinh lỗi.

  1. Tạo function để ghi log

Bước tiếp theo — tạo một function đa năng để ghi lỗi vào bảng error_log. Function này sẽ được gọi bất cứ khi nào bạn muốn lưu lại lỗi.

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);
    -- Thông báo ghi log thành công
    RAISE NOTICE 'Lỗi đã được ghi log: %', p_error_message;
END;
$$ LANGUAGE plpgsql;

Giải thích đoạn code này:

  1. p_error_message và p_function_name — tham số truyền vào function, nhận thông báo lỗi và tên function gọi lỗi.
  2. INSERT INTO error_log thêm bản ghi vào bảng.
  3. RAISE NOTICE in ra thông báo trên console để dev biết quá trình ghi log đang diễn ra.

Giờ mình đã giải quyết xong bài toán đầu tiên: có thể ghi lỗi vào bảng log cực kỳ dễ dàng.

Dùng function log_error trong các bài toán thực tế

Ví dụ 1: Ghi log lỗi khi chia cho 0

Tạo function thực hiện phép chia đơn giản, nhưng sẽ ghi log nếu mẫu số bằng 0.

CREATE OR REPLACE FUNCTION divide_numbers(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
    result NUMERIC;
BEGIN
    IF b = 0 THEN
        -- Gọi function ghi log
        PERFORM log_error('Đã thử chia cho 0!', 'divide_numbers');
        -- Sinh exception
        RAISE EXCEPTION 'Không được phép chia cho 0.';
    END IF;

    -- Thực hiện phép chia
    result := a / b;
    RETURN result;
END;
$$ LANGUAGE plpgsql;
  • Nếu mẫu số là 0, function log_error sẽ được gọi để ghi lỗi vào bảng.
  • Sau khi ghi log, sẽ sinh ra exception RAISE EXCEPTION để báo cho user.

Ví dụ gọi hàm:

SELECT divide_numbers(10, 0);

Kết quả:

  • Gọi function này với phép chia cho 0 sẽ ghi lỗi vào bảng error_log.
  • User sẽ thấy thông báo lỗi trên console.

Ví dụ 2: ghi log khi chèn dữ liệu không hợp lệ

Xem thử function thêm sinh viên mới vào bảng students. Nếu tên sinh viên bị trống, mình sẽ ghi log và dừng luôn.

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('Phải nhập tên sinh viên!', 'add_student');
        RAISE EXCEPTION 'Tên sinh viên không được để trống.';
    END IF;

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

Ví dụ gọi hàm:

SELECT add_student('');

Nếu thử thêm sinh viên mà không có tên, function sẽ tạo bản ghi trong error_log với thông báo tương ứng.

Ví dụ 3: ghi log cảnh báo

Không phải lúc nào cũng cần sinh exception cho user. Đôi khi chỉ cần ghi lại cảnh báo là đủ. Làm thử function kiểm tra tuổi sinh viên nhé:

CREATE OR REPLACE FUNCTION check_age(p_age INT)
RETURNS VOID AS $$
BEGIN
    IF p_age < 18 THEN
        -- Ghi log cảnh báo, không dừng chương trình
        PERFORM log_error('Tuổi sinh viên nhỏ hơn 18.', 'check_age');
        RAISE NOTICE 'Cảnh báo: Tuổi sinh viên nhỏ hơn 18.';
    END IF;

    RAISE NOTICE 'Kiểm tra tuổi ok.';
END;
$$ LANGUAGE plpgsql;

Ví dụ gọi hàm:

SELECT check_age(16);

Kết quả:

  • Ghi cảnh báo vào bảng error_log.
  • Thông báo trên console rằng tuổi sinh viên nhỏ hơn 18.

Ghi log và xử lý exception

Giờ mình sẽ kết hợp ghi log lỗi và xử lý exception trong một function phức tạp hơn. Giả sử bạn cần tính lại điểm cho sinh viên trong bảng grades. Nếu có lỗi với một sinh viên nào đó, lỗi sẽ được ghi log, nhưng chương trình vẫn tiếp tục với các sinh viên khác.

CREATE OR REPLACE FUNCTION recalculate_grades()
RETURNS VOID AS $$
DECLARE
    student RECORD;
BEGIN
    FOR student IN SELECT * FROM students LOOP
        BEGIN
            -- Ví dụ: cập nhật điểm cho sinh viên
            UPDATE grades SET final_grade = final_grade + 1
            WHERE student_id = student.id;

            RAISE NOTICE 'Đã cập nhật điểm cho sinh viên %', student.name;
        EXCEPTION WHEN OTHERS THEN
            -- Ghi log lỗi và tiếp tục
            PERFORM log_error('Không cập nhật được điểm cho sinh viên ' || student.name, 'recalculate_grades');
        END;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Ví dụ gọi hàm:

SELECT recalculate_grades();

Cách này giúp function của bạn "trâu bò" hơn, vì lỗi sẽ được ghi log riêng mà không làm dừng toàn bộ quá trình xử lý dữ liệu.

2
Nhiệm vụ
SQL SELF, mức độ, bài học
Đã khóa
Ghi log lỗi khi tính toán
Ghi log lỗi khi tính toán
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION