持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情
在很多系统上都会遇到日志类的需求,如记录用户的行为日志,记录浏览记录、操作记录等。审计日志就是日志需求中的一种,也成为审计跟踪,是对事件和更改的记录。通常都是将一系列的动作或特定的活动相关的事件进行记录。
数据模型
对于审计日志的数据,最重要的是需要记录行为操作,行为分类等重要的数据,希望便于数据回溯或者行为回溯:
- 事件 ID
- 事件名称
- 事件来源
- 事件类型
- 事件所在的地域
- 事件发生结果
- 事件结果原因
- 事件操作者
- 事件操作时间
设计方案
触发器方案
第一次遇到日志记录是使用 oralce 数据库,通过建立数据库表触发器来记录数据的变化。主要是对数据的增删改三个动作分别建立三个触发器,对需要关注的数据表建立触发器,一旦数据发生变更时都会将变更前后的数据都记录到另外 history_record 记录表。
这种方式虽然简单,但也存在很多局限性:
- 如果是遇到不同的数据库如 pg 、mysql 等都需要重新编写触发器
- 仅能记录数据的变更,一些其他操作 IP,来源等就无法记录
- 也会产生有影响性能的可能性
-- user
create table user {
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(20),
createtime date
};
-- user_log
create table user_log(
id int PRIMARY key AUTO_INCREMENT,
extValue varchar(200)
newValue varchar(200)
);
-- insert trigger
create trigger inser_user_trigger after insert on user
for EACH row
begin
insert into user_log(extValue,newValue) value(ext, NEW);
end;
嵌入业务内记录变更
和业务代码结合,然后在最后 return 响应结果之前将整个记录都记录到日志中
该方案流程清晰,环环相扣:先查询原值,完成核心业务,如新增/更新/删除操作后之后,再去diff 新老值,将变更的数据都查出然后转换成操作的文本,记录到日志中。但该方案也存在很多问题:
- 与业务代码耦合性太强,对业务流程入侵太大
- 如果复杂的业务或者需要更详细的审计数据,可能部分数据还需要进行反查。
publict class UserController {
createUser(@Body() data: User){
// 业务处理...
// 创建加入 db
this.userService.createUser(data);
// 加入日志
addLog(data);
return {code:200, message: '创建成功'}
}
updateUser(@Body() updates: User){
// 业务处理...
// 获取原始值
let originValue = this.userService.getUserById(user.id)
// 更新到 db
this.userService.updateUser(data);
// diff 差异
let diffFields = this.logService.getDiffField(originValue, updates)
// 加入日志
addLog(diffFields);
return {code:200, message: '更新成功'}
}
}
AOP 设计
基于以上的设计,可进一步优化,如在支持注解的方式可通过 AOP 设计思想,使用注入的方式进行拦截然后近路用户行为。
比如 java 中的通过注入日志拦截器。调用某一方法结束后进行拦截,然后进行日志的写入。
@UseLoggerFilter()
publict class UserController {
@AddLogger(params) // 注入日志拦截
createUser(@Body() data: User){
// 业务处理...
// 创建加入 db
this.userService.createUser(data);
return {code:200, message: '创建成功'}
}
}
其他方式
- 通过前端记录日志
通过埋点的方式,前端监控数据的变更,然后将记录传递给后端服务,由后端服务记录,但是前端记录采集事件行为数据。
- 基于其他第三方工具
现有市场上有很多第三方提供软件进行统一管理。
- ORM 的拦截
现有的服务基本都是使用 ORM,利用其提供的功能,使用拦截器方式,比如 mybatis 的拦截器。
总之,还是需要根据自己的场景去确定使用的技术方案,大部分可能还是使用嵌入业务方式去拦截然后记录日志。比如 Java 通过注解注入日志拦截,方法执行完之后进入日志拦截器,然后将需要的日志行为和事件记录在日志中。