审计日志聚焦关键操作与数据变更,确保可追溯与合规,操作日志涵盖系统运行全貌,用于监控与诊断;二者均通过Yii日志组件实现,利用Yii::info()等方法记录,配置FileTarget或DbTarget指定存储位置与级别,并通过categories区分日志类型;为保障审计日志完整性与安全性,需将日志存于非Web可访问目录或专用日志表,数据库写入权限应限制为仅INSERT,敏感信息需脱敏,推荐设置exportInterval=1实现即时写入,结合消息队列解耦日志系统;高价值操作日志应包含用户ID、IP、操作类型、目标对象、前后数据、结果状态及上下文信息,结构化存储于数据库并支持JSON字段灵活查询;为满足定制需求,可自定义Log Target继承yii\log\Target并重写export()方法,实现写入专用表或对接ELK、Kafka等外部系统,亦可通过Behavior绑定ActiveRecord事件(如AFTER_INSERT、AFTER_UPDATE)自动记录变更,实现业务无侵扰的审计追踪。
在Yii框架里,审计日志和操作日志其实是两个紧密相关但又略有侧重的概念。简单来说,审计日志更偏向于追踪关键业务操作、数据变更,确保可追溯性和合规性,它通常记录“谁在何时做了什么,对哪个数据产生了什么影响”。而操作日志则是一个更宽泛的范畴,涵盖了应用运行时各种信息,从错误、警告到普通的调试信息,目的是为了系统监控、问题诊断和性能分析。核心目的都指向一个:让系统行为变得透明可查,无论是为了安全审计还是日常运维。
要让Yii框架有效地记录操作日志,乃至更细致的审计日志,我们通常会利用其强大的日志组件。这玩意儿就像是系统内部的“黑匣子”,能把我们想记录的一切都妥善地保存下来。
最直接的方式,就是使用
Yii::info()
Yii::warning()
Yii::error()
// config/web.php 或 config/main.php 'components' => [ 'log' => [ 'traceLevel' => YII_DEBUG ? 3 : 0, // 调试模式下追踪调用栈 'targets' => [ [ 'class' => 'yii\log\FileTarget', // 文件日志 'levels' => ['error', 'warning'], // 只记录错误和警告 'logFile' => '@runtime/logs/app.log', 'except' => ['yii\web\HttpException:404'], // 排除404错误 ], [ 'class' => 'yii\log\DbTarget', // 数据库日志,用于更结构化的记录 'levels' => ['info'], // 记录info级别,适合操作日志 'logTable' => '{{%audit_log}}', // 专门的审计日志表 'categories' => ['application', 'user_action'], // 区分不同类别的日志 'prefix' => function ($message) { // 添加额外上下文信息,如用户ID、IP $userId = Yii::$app->user->isGuest ? 0 : Yii::$app->user->id; $ip = Yii::$app->request->userIP; return "User: {$userId}, IP: {$ip} | "; }, 'exportInterval' => 1, // 每条日志都立即写入 ], ], ], ],
在控制器或模型中,要记录操作日志,就像这样:
// 记录普通信息 Yii::info('用户ID: ' . Yii::$app->user->id . ' 访问了文章列表。', 'user_action'); // 记录数据变更(审计日志的核心) class Post extends \yii\db\ActiveRecord { public function afterSave($insert, $changedAttributes) { parent::afterSave($insert, $changedAttributes); $logData = [ 'user_id' => Yii::$app->user->id, 'action' => $insert ? '创建文章' : '更新文章', 'model_id' => $this->id, 'model_name' => self::class, 'old_attributes' => json_encode($changedAttributes), // 记录旧值 'new_attributes' => json_encode($this->getAttributes()), // 记录新值 'ip_address' => Yii::$app->request->userIP, ]; Yii::info(json_encode($logData), 'audit_trail'); // 使用特定分类方便过滤 } public function afterDelete() { parent::afterDelete(); $logData = [ 'user_id' => Yii::$app->user->id, 'action' => '删除文章', 'model_id' => $this->id, 'model_name' => self::class, 'ip_address' => Yii::$app->request->userIP, ]; Yii::info(json_encode($logData), 'audit_trail'); } }
通过配置不同的
targets
categories
谈到审计日志,完整性和安全性可不是小事。毕竟,这些日志是未来追溯问题、甚至法律合规的依据,如果它们能被轻易篡改或丢失,那记录的意义就大打折扣了。在我看来,Yii本身提供了良好的基础,但要做到极致,还得我们开发者多费点心思。
首先,存储位置的选择至关重要。如果选择文件日志(
FileTarget
@runtime/logs
其次,数据库日志(DbTarget
audit_log
INSERT
UPDATE
DELETE
TRUNCATE
再来,日志的实时性和不可抵赖性。虽然Yii的
DbTarget
exportInterval
最后,别忘了日志查看和管理的安全。审计日志本身也是敏感信息,只有授权人员才能查看。在Yii应用中,这通常通过RBAC(基于角色的访问控制)来实现,只有具备特定“查看审计日志”权限的角色才能访问相应的管理界面。
要让操作日志真正有价值,不仅仅是记录“发生了什么”,更重要的是记录“谁、何时、何地、如何、对什么做了什么,以及结果如何”。这就像是给每个操作都拍了一张带有详细信息的“快照”。
操作主体信息:
操作行为信息:
操作对象信息:
Post
User
Order
post_id=123
ActiveRecord
getDirtyAttributes()
getOldAttributes()
操作结果信息:
上下文信息:
在我处理过的一些复杂业务系统中,我们会把这些信息结构化地存储在数据库中,并配合
JSON
old_attributes
new_attributes
Yii的日志组件设计得非常灵活,当内置的
FileTarget
DbTarget
1. 创建自定义Log Target
核心思路是继承
yii\log\Target
export()
export()
exportInterval
// app/components/AuditLogTarget.php namespace app\components; use yii\log\Target; use Yii; class AuditLogTarget extends Target { public $auditTableName = '{{%my_custom_audit_log}}'; // 自定义审计表名 public function export() { // 遍历所有待处理的日志消息 foreach ($this->messages as $message) { list($text, $level, $category, $timestamp) = $message; // 假设我们只关心 'audit_trail' 类别且内容是JSON字符串 if ($category === 'audit_trail' && is_string($text)) { $logData = json_decode($text, true); if (json_last_error() !== JSON_ERROR_NONE) { // 如果不是有效的JSON,记录为普通错误或跳过 Yii::error('Invalid JSON in audit_trail log: ' . $text, 'application'); continue; } // 准备插入数据库的数据 $insertData = [ 'user_id' => $logData['user_id'] ?? 0, 'action' => $logData['action'] ?? '未知操作', 'model_name' => $logData['model_name'] ?? '', 'model_id' => $logData['model_id'] ?? 0, 'old_attributes' => $logData['old_attributes'] ?? null, 'new_attributes' => $logData['new_attributes'] ?? null, 'ip_address' => $logData['ip_address'] ?? null, 'created_at' => date('Y-m-d H:i:s', $timestamp), // 还可以添加更多自定义字段 ]; // 插入数据库 Yii::$app->db->createCommand()->insert($this->auditTableName, $insertData)->execute(); } } } }
然后在配置中引用它:
'components' => [ 'log' => [ 'targets' => [ // ... 其他日志目标 [ 'class' => 'app\components\AuditLogTarget', 'levels' => ['info'], // 只处理info级别的日志 'categories' => ['audit_trail'], // 只处理 'audit_trail' 类别的日志 'exportInterval' => 1, // 确保实时写入 ], ], ], ],
这种方式的优势在于,它将日志的格式化和存储逻辑完全封装起来,业务代码只需要
Yii::info(json_encode($data), 'audit_trail');
2. 集成外部日志服务
如果你的审计需求涉及到大数据量、实时分析或跨服务追踪,可以考虑将日志发送到专门的日志管理系统,比如:
AuditLogTarget
export()
3. 行为(Behavior)与事件(Event)结合
对于更细粒度的模型数据变更审计,除了在
afterSave
AuditBehavior
// app/behaviors/AuditBehavior.php namespace app\behaviors; use yii\base\Behavior; use yii\db\ActiveRecord; use Yii; class AuditBehavior extends Behavior { public function events() { return [ ActiveRecord::EVENT_AFTER_INSERT => 'logAudit', ActiveRecord::EVENT_AFTER_UPDATE => 'logAudit', ActiveRecord::EVENT_AFTER_DELETE => 'logAudit', ]; } public function logAudit($event) { /** @var ActiveRecord $model */ $model = $this->owner; $action = ''; $oldAttributes = null; $newAttributes = $model->getAttributes(); if ($event->name === ActiveRecord::EVENT_AFTER_INSERT) { $action = '创建'; } elseif ($event->name === ActiveRecord::EVENT_AFTER_UPDATE) { $action = '更新'; // 记录变更前的数据 $oldAttributes = $event->changedAttributes; // 只有更新事件才有 } elseif ($event->name === ActiveRecord::EVENT_AFTER_DELETE) { $action = '删除'; $newAttributes = null; // 删除后没有新属性 } $logData = [ 'user_id' => Yii::$app->user->isGuest ? 0 : Yii::$app->user->id, 'action' => $action . $model->formName(), 'model_id' => $model->getPrimaryKey(), 'model_name' => $model->formName(), 'old_attributes' => $oldAttributes ? json_encode($oldAttributes) : null, 'new_attributes' => $newAttributes ? json_encode($newAttributes) : null, 'ip_address' => Yii::$app->request->userIP, ]; Yii::info(json_encode($logData), 'audit_trail'); } }
然后在模型中附加这个行为:
class Product extends \yii\db\ActiveRecord { public function behaviors() { return [ \app\behaviors\AuditBehavior::class, ]; } // ... }
这种方式让审计逻辑与业务逻辑分离,更易于维护和复用。对于大型项目,我个人非常推崇这种结合行为模式的审计方案。它能让你在不侵入业务代码的情况下,优雅地实现全面的审计追踪。
以上就是YII框架的审计日志是什么?YII框架如何记录操作日志?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 //m.sbmmt.com/ All Rights Reserved | php.cn | 湘ICP备2023035733号