审计日志聚焦关键操作与数据变更,确保可追溯与合规,操作日志涵盖系统运行全貌,用于监控与诊断;二者均通过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 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号