通过函数实现自动日志记录
想象一下,你让你的bot在数据库里自由发挥,执行各种复杂操作。迟早它会出错、犯傻,或者遇到意外情况。如果没有日志记录,它可能直接沉默,你就会一脸懵逼,不知道哪里出问题了。自动日志记录能帮你:
- 追踪错误和警告的发生。
- 搞清楚故障的本质和原因。
- 让代码更好调试和优化。
用自动日志记录,你就有了一个“黑匣子”,能把数据库里的事件都记下来,帮你像侦探一样找bug。
用函数实现自动日志记录
- 定义日志表
要记录错误,得有地方存。我们在上一节已经建过error_log表:
CREATE TABLE error_log (
id SERIAL PRIMARY KEY, -- 唯一记录ID
error_message TEXT NOT NULL, -- 错误信息
error_time TIMESTAMP DEFAULT NOW(), -- 错误发生时间
function_name TEXT -- 抛出错误的函数名
);
这个表有记录错误需要的所有东西:错误文本、时间和出错的函数。
- 写一个日志记录函数
下一步——写一个通用函数,把错误写进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 'Error logged: %', p_error_message;
END;
$$ LANGUAGE plpgsql;
来拆解下这段代码:
p_error_message和p_function_name是函数参数,分别接收错误信息和出错函数名。INSERT INTO error_log把记录插进表里。RAISE NOTICE会在控制台输出提示,让开发者知道日志已经写入。
现在我们搞定了第一步:可以很方便地把错误写进表里了。
在实际任务中用log_error函数
例子1:除零错误日志
写个函数做简单的除法,如果分母是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('尝试除以零!', 'divide_numbers');
-- 抛出异常
RAISE EXCEPTION '不允许除以零。';
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:记录警告日志
有时候不用抛异常,只要记个警告就行。比如写个函数检查学生年龄:
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 '年龄检查通过。';
END;
$$ LANGUAGE plpgsql;
调用例子:
SELECT check_age(16);
结果:
- 在
error_log表里写一条警告。 - 控制台会提示学生年龄小于18。
日志记录和异常处理
我们来把错误记录和异常处理结合起来,写个复杂点的函数。比如要给grades表里的学生重新算分。如果某个学生失败了,记录错误但继续处理其他人。
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();
这样你的函数就更健壮了,错误会单独记录,不会让所有数据都停下来。
GO TO FULL VERSION