Spatie Laravel Activitylog 默认不自动记录完整审计链,需显式调用causedBy()、performedOn()和withProperties()才能实现“谁对什么做了什么”的真实审计需求。

直接说结论:Spatie Laravel Activitylog 能自动记录模型的 created、updated、deleted 事件,也能手动记录任意操作;但默认不记录“谁在什么时候做了什么”这种完整审计链,必须显式配置 causedBy()、performedOn() 和 withProperties() 才能支撑真实审计需求。
模型自动记录只触发变更,不自动绑定用户或上下文
给模型加 LogsActivity trait 后,$model->save() 确实会写入 activity_log 表,但关键字段常为空:
-
causer_id为null—— 即使用户已登录,包不会自动填充,除非你全局注册了中间件或在每个操作里调用causedBy() -
subject_type和subject_id可能缺失 ——performedOn($model)不是自动的,必须显式调用 -
properties字段空着 —— IP、请求路径、参数等需手动传入withProperties()
常见错误现象:后台看到一堆 updated 日志,但点开全无操作人、无关联数据、无上下文,根本无法回溯。
手动记录必须显式指定 causedBy() 和 performedOn()
审计日志的核心是“谁对什么做了什么”,这三要素缺一不可。不能只写 activity()->log('导出报表')。
- 没调用
causedBy():即使当前用户已登录,causer_id仍为null;建议统一在控制器基类或中间件中兜底:causedBy(auth()->user() ?? null) - 没调用
performedOn($model):日志和模型无关联,查不到“这次更新影响了哪条记录”;注意$model必须是已保存的 Eloquent 实例(id存在),否则subject_id写入0 - 别依赖简写别名
by()或on():它们只是语法糖,该传参一个都不能少;且byAnonymous()仅适用于系统任务,不适用于用户操作
正确示例:
activity()
->causedBy(auth()->user())
->performedOn($order)
->withProperties([
'status_before' => $order->status,
'status_after' => 'shipped',
'ip' => request()->ip(),
])
->log('订单已发货');
logAttributes 配置错位会导致变更对比失效
想让日志显示“name 从 A 改为 B”,光有 logOnly(['name']) 不够,还必须确保模型实际发生了变更。
-
static $logAttributes = ['name']是旧版写法,Laravel 10+ 推荐改用getActivitylogOptions()返回LogOptions实例 - 如果字段被
$casts或访问器(accessor)修改过,原始值可能拿不准 ——logOnly()拿的是模型属性值,不是数据库原始值;必要时用logChanges()显式控制 -
$logAttributesToIgnore = ['updated_at']很必要,否则每次 save 都因时间戳微变而触发日志,产生噪音 - 别用
logOnly(['*'])在生产环境 —— 大字段(如 JSON、text)会拖慢写入,且properties字段有长度限制(默认 TEXT,约 64KB)
查询 Activity 时 subject 和 causer 关联容易 N+1
Activity::with('subject', 'causer')->get() 看似合理,但实际可能失效:
-
subject是多态关系,Eloquent 默认不支持with()预加载多态外键;必须用Activity::with(['subject' => fn ($q) => $q->withoutGlobalScopes()])或改用loadMorph() -
causer默认关联到User::class,但如果你用的是自定义用户模型(如Admin),需在配置里改'default_causer_class',否则causer查不到 - 批量查日志时,
getExtraProperty()是运行时解析 JSON,不能用于 where 查询;真要按自定义字段过滤,得用原生 SQL:where('properties->ip', '192.168.1.1')
最易忽略的一点:日志表增长极快,activity_log 建议加复合索引 (causer_id, created_at) 和 (subject_type, subject_id),否则分页查某用户所有操作会越来越慢。


















