DoctrineExtensions 实现全局日志记录与选择性忽略的实践
2025-06-16 14:20:26作者:柏廷章Berta
背景介绍
在基于Symfony框架和Doctrine ORM的开发中,Gedmo的DoctrineExtensions提供了Loggable行为,能够自动记录实体对象的变更历史。标准的Loggable实现需要显式地为每个需要记录的实体添加注解或属性标记。但在实际业务场景中,我们往往希望记录所有实体的变更,只排除少数不需要记录的实体或字段。
解决方案设计
通过继承LoggableListener并重写关键方法,我们可以实现以下功能:
- 默认记录所有实体变更
- 通过NotLoggable属性标记排除特定实体或字段
- 增强日志记录功能,包括对象标题、变更前后数据等
核心实现代码
配置扩展
首先需要在Symfony的配置文件中替换默认的LoggableListener:
services:
Gedmo\Loggable\LoggableListener:
class: App\EventSubscriber\Loggable
calls:
- [ setSecurity, ['@security.helper'] ]
tags:
- { name: doctrine.event_listener, event: 'onFlush' }
- { name: doctrine.event_listener, event: 'loadClassMetadata' }
- { name: doctrine.event_listener, event: 'postPersist' }
自定义Loggable监听器
创建自定义的Loggable监听器类,继承并扩展原始功能:
class Loggable extends LoggableListener
{
private Security $security;
private string $lastAction;
private array $lastChanges;
public function setSecurity(Security $security)
{
$this->security = $security;
}
// 关键方法:获取实体配置
public function getConfiguration(ObjectManager $objectManager, $class): array
{
$config = parent::getConfiguration($objectManager, $class);
$meta = $objectManager->getClassMetadata($class);
// 检查类级别NotLoggable属性
if ($meta->reflClass->getAttributes(NotLoggable::class)) {
return $config;
}
// 过滤掉带有NotLoggable属性的字段
$versioned = array_filter(
array_merge($meta->getFieldNames(), $meta->getAssociationNames()),
fn ($field) => !$meta->reflFields[$field]->getAttributes(NotLoggable::class)
);
// 设置默认记录配置
$config = array_merge($config, [
'loggable' => true,
'logEntryClass' => AuditLogEntry::class,
'useObjectClass' => $class,
'versioned' => $versioned,
]);
self::$configurations[$this->name][$meta->getName()] = $config;
return $config;
}
// 日志条目预处理
protected function prePersistLogEntry($logEntry, $object): void
{
if (method_exists($object, '__toString')) {
$logEntry->setObjectTitle((string)$object);
}
if (LogEntryInterface::ACTION_UPDATE !== $this->lastAction) {
return;
}
// 记录变更前数据
$prevData = [];
foreach ($this->lastChanges as $field => $changes) {
$value = $changes[0];
if (is_object($value) && method_exists($value, 'getId')) {
$value = ['id' => $value->getId()];
}
$prevData[$field] = $value;
}
$logEntry->setPrevData($prevData);
}
// 创建日志条目
protected function createLogEntry($action, $object, LoggableAdapter $ea): ?LogEntryInterface
{
$user = $this->security->getUser();
if ($user) {
$this->setUsername($user->getFullNameShort());
}
$this->lastAction = $action;
$om = $ea->getObjectManager();
$this->lastChanges = $ea->getObjectChangeSet($om->getUnitOfWork(), $object);
return parent::createLogEntry($action, $object, $ea);
}
}
使用示例
排除整个实体
#[\NotLoggable]
#[ORM\Entity(repositoryClass: RepairStatusLogRepository::class)]
class RepairStatusLog
{
// 实体定义
}
排除特定字段
#[ORM\Entity]
class User
{
#[ORM\Column]
private string $name;
#[\NotLoggable]
#[ORM\Column]
private string $password;
}
技术要点解析
-
配置覆盖机制:通过重写getConfiguration方法,实现了默认记录所有实体的逻辑,同时保留通过NotLoggable属性排除特定实体或字段的能力。
-
变更数据捕获:在createLogEntry方法中捕获变更数据集,并在prePersistLogEntry中将变更前数据格式化后存入日志条目。
-
用户上下文集成:通过Security组件自动获取当前用户信息并记录到日志中。
-
对象标识处理:对于关联对象,自动记录其ID而非整个对象,避免数据冗余。
实际应用价值
这种实现方式特别适合以下场景:
- 需要全面审计的系统,如金融、医疗等合规要求高的领域
- 开发初期阶段,尚未完全确定哪些实体需要记录
- 需要细粒度控制记录字段的系统
相比标准的Loggable实现,这种"记录所有,排除例外"的模式可以显著减少配置工作量,同时保证系统的审计完整性。
注意事项
- 性能考虑:全量记录可能对高并发系统产生性能影响,需合理设计日志存储方案
- 存储规划:日志数据可能快速增长,需要考虑归档策略
- 敏感数据处理:确保排除密码等敏感字段的记录
- 关联对象处理:对于复杂对象图,可能需要定制更精细的记录策略
通过这种定制化的Loggable实现,开发者可以在保证系统可审计性的同时,保持代码的简洁性和可维护性。
登录后查看全文
热门项目推荐
相关项目推荐
Kimi-K2.5Kimi K2.5 是一款开源的原生多模态智能体模型,它在 Kimi-K2-Base 的基础上,通过对约 15 万亿混合视觉和文本 tokens 进行持续预训练构建而成。该模型将视觉与语言理解、高级智能体能力、即时模式与思考模式,以及对话式与智能体范式无缝融合。Python00- QQwen3-Coder-Next2026年2月4日,正式发布的Qwen3-Coder-Next,一款专为编码智能体和本地开发场景设计的开源语言模型。Python00
xw-cli实现国产算力大模型零门槛部署,一键跑通 Qwen、GLM-4.7、Minimax-2.1、DeepSeek-OCR 等模型Go06
PaddleOCR-VL-1.5PaddleOCR-VL-1.5 是 PaddleOCR-VL 的新一代进阶模型,在 OmniDocBench v1.5 上实现了 94.5% 的全新 state-of-the-art 准确率。 为了严格评估模型在真实物理畸变下的鲁棒性——包括扫描伪影、倾斜、扭曲、屏幕拍摄和光照变化——我们提出了 Real5-OmniDocBench 基准测试集。实验结果表明,该增强模型在新构建的基准测试集上达到了 SOTA 性能。此外,我们通过整合印章识别和文本检测识别(text spotting)任务扩展了模型的能力,同时保持 0.9B 的超紧凑 VLM 规模,具备高效率特性。Python00
Baichuan-M3-235BBaichuan-M3 是百川智能推出的新一代医疗增强型大型语言模型,是继 Baichuan-M2 之后的又一重要里程碑。Python00
VLOOKVLOOK™ 是优雅好用的 Typora/Markdown 主题包和增强插件。 VLOOK™ is an elegant and practical THEME PACKAGE × ENHANCEMENT PLUGIN for Typora/Markdown.Less00
热门内容推荐
项目优选
收起
OpenHarmony documentation | OpenHarmony开发者文档
Dockerfile
539
3.77 K
Ascend Extension for PyTorch
Python
347
413
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
889
607
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
337
184
暂无简介
Dart
778
192
deepin linux kernel
C
27
11
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
1.34 K
758
React Native鸿蒙化仓库
JavaScript
303
356
openJiuwen agent-studio提供零码、低码可视化开发和工作流编排,模型、知识库、插件等各资源管理能力
TSX
986
252
仓颉编译器源码及 cjdb 调试工具。
C++
154
896