审计触发器 91plus
以下是一个通用触发器函数的示例,用于将对表的更改记录到审计日志表中。它记录的信息比旧的 审计触发器 更加详细,并且以更结构化的方式记录。
行值记录为hstore字段,而不是扁平文本。这允许对审计历史进行更复杂的查询,并允许审计系统仅记录更新的更改字段。
审计可以在语句级别进行粗粒度操作,也可以在行级别进行细粒度操作。控制方式为每个被审计的表。
记录的信息包括:
- 更改类型 - **I**nsert(插入)、**U**pdate(更新)、**D**elete(删除)或 **T**runcate(截断)。
- 如果非 UNIX 套接字,则为客户端 IP/端口
- 会话用户名(“真实”用户名,而非来自SET ROLE或SECURITY DEFINER)
- 事务、语句和时钟时间戳
- 导致更改的顶级语句
- 更改前的行值(或在INSERT)
- 情况下为更改后的行值)UPDATE情况下,任何更改列的新值。可以使用以下方法重建新值:row_value || changed_fields
- 进行更改的事务 ID
- 应用程序名称application_name
- 目标模式和表,按 OID 和名称。
此触发器 *不能* 跟踪
- SELECTs
- 像ALTER TABLE
- 对系统目录的更改
跟踪表所有者和超级用户的更改,但可以轻松伪造。
如果你希望此审计日志可信,你的应用程序应该运行的角色最多具有对USAGE至audit模式和SELECT对audit.logged_actions的权限。最重要的是,*你的应用程序绝不能以超级用户角色连接,也不应拥有它使用的表*。使用与你的应用程序运行角色不同的用户创建你的应用程序模式,并GRANT你的应用程序所需的最小权限。
触发器
你可以在 GitHub 上获取 2ndQuadrant/audit-trigger 的最新版本。
基本用法
SELECT audit.audit_table('target_table_name');
现在,此表将为每次插入/更新/删除操作记录行级审计事件,并为截断操作记录语句级事件。查询文本将始终记录。
之后取消审计
DROP TRIGGER audit_trigger_row on target_table_name;
DROP TRIGGER audit_trigger_stm on target_table_name;
如果你需要更细粒度的控制,请使用audit.audit_table(target_table regclass, audit_rows boolean, audit_query_text boolean, excluded_cols text[])或CREATE TRIGGER自己创建审计触发器。例如
SELECT audit.audit_table('target_table_name', 'true', 'false', '{version_col, changed_by, changed_timestamp}'::text[]);
... 将在target_table_name上创建审计触发器,记录每个行更改,但省略查询文本('false' 参数)并省略version_col, changed_by和changed_timestamp列。一个UPDATE仅更改忽略列的操作将不会导致创建审计记录。
忽略某些更改
在 PostgreSQL 9.0 及更高版本中,可以添加一个可选的WHEN子句到触发器的调用中。这对于审计非常有用,因为它允许你排除某些更改,甚至不需要调用触发器带来的开销。
一个常见的案例是忽略一个经常更新且不值得审计的字段。不幸的是,你必须测试你感兴趣的所有字段的更改,没有简单的方法可以表示“如果除了 <x> 和 <y> 字段之外的任何字段在 OLD 和 NEW 之间发生了变化”。
CREATE TRIGGER tablename_audit_insert_delete
AFTER INSERT OR DELETE ON sometable FOR EACH ROW
EXECUTE PROCEDURE audit.if_modified_func();
CREATE TRIGGER tablename_audit_update_selective
AFTER UPDATE ON sometable FOR EACH ROW
WHEN ( (OLD.col1, OLD.col2, OLD.col3) IS DISTINCT FROM (NEW.col1, NEW.col2, NEW.col3) )
EXECUTE PROCEDURE audit.if_modified_func();
... 但当然,你还可以做更多事情。通常需要将INSERT, DELETE和UPDATE触发器定义分开,而不是将它们全部放在一个触发器定义中。
请注意使用IS DISTINCT FROM而不是=. 请考虑NULL.
的影响
TIMESTAMP WITH TIME ZONE字段始终以 UTC 存储,默认情况下以本地时间显示。你可以使用AT TIME ZONE在查询中控制显示,或者使用SET timezone = 'UTC'作为每个会话的 GUC。请参阅 Pg 文档。
松散地基于 bricklen 的 审计触发器,由 ringerc 完全重写,以提供更多审计细节、hstore 日志记录等功能。