mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-08-30 04:35:33 +08:00
feat(log): 新增 DebugMysqlAsync 异步日志驱动与 debug_mysql_async 通道
This commit is contained in:
@@ -19,6 +19,7 @@ PREFIX=ul_
|
||||
FIELDS_CACHE=false
|
||||
|
||||
[LOG]
|
||||
# 日志通道三选一:file(本地文件)/ debug_mysql(直写数据库)/ debug_mysql_async(异步:本地 JSONL + 定时导入,写日志零 DB 依赖)
|
||||
CHANNEL=file
|
||||
|
||||
[TIMER]
|
||||
|
||||
@@ -72,7 +72,11 @@ return [
|
||||
'charset' => Env::get('database.charset', 'utf8'),
|
||||
// 数据库表前缀
|
||||
'prefix' => Env::get('database.prefix', 'ul_'),
|
||||
]
|
||||
],
|
||||
// 异步模式:本地 JSONL + 定时导入,写日志零 DB 依赖
|
||||
'debug_mysql_async' => [
|
||||
'type' => 'DebugMysqlAsync',
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
86
extend/think/log/driver/DebugMysqlAsync.php
Normal file
86
extend/think/log/driver/DebugMysqlAsync.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace think\log\driver;
|
||||
|
||||
use think\App;
|
||||
use think\contract\LogHandlerInterface;
|
||||
use think\log\DebugLogToolkit;
|
||||
|
||||
/**
|
||||
* 异步调试日志驱动:本地 JSONL 落盘 + 定时导入,写日志零 DB 依赖.
|
||||
*
|
||||
* 与 DebugMysql 的分工:DebugMysql 写日志时直连 DB(含重连/CSV 文件降级逻辑);
|
||||
* 本驱动根本不连 DB——save() 只把行追加进 {runtimePath}log/{Ymd}.jsonl,
|
||||
* DB 导入由定时任务异步完成。写日志的动作从物理上不可能成为业务故障点:
|
||||
* 零 DB 依赖、绝不抛异常、绝不返回 false。
|
||||
*
|
||||
* 三条铁律:
|
||||
* 1. 禁止缓存文件句柄或日期——DebugLogToolkit 每次现算(长驻 CLI 跨天滚动);
|
||||
* 2. 禁止跨 save() 静态攒批——每次调用独立落盘;
|
||||
* 3. 禁止任何 DB 访问/重连/降级逻辑——本驱动根本不连 DB。
|
||||
*
|
||||
* 行格式契约:DebugLogToolkit::FIELDS(与 ul_debug_log 列一一对应)。
|
||||
*/
|
||||
class DebugMysqlAsync implements LogHandlerInterface
|
||||
{
|
||||
/**
|
||||
* 驱动配置(当前无可用项,保留以兼容通道配置注入).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [];
|
||||
|
||||
/**
|
||||
* 构造器签名与 DebugMysql 一致(框架 Log Manager 经容器 invokeClass 注入 App 实例与通道配置).
|
||||
*/
|
||||
public function __construct(App $app, $config = [])
|
||||
{
|
||||
if (is_array($config)) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 落盘一批日志(扁平 array<LogRecord>).
|
||||
*
|
||||
* 镜像 DebugMysql.save 的遍历方式(type 作 level、message 作 content、
|
||||
* 非字符串 message 转 print_r),但落盘动作换为 DebugLogToolkit:
|
||||
* 全部行拼接成一个多行字符串后只调一次 appendLine(单次 flock 批量写入);
|
||||
* 行间以 \n 连接、行尾 \n 由 appendLine 统一补齐,避免双换行。
|
||||
* 整体 catch \Throwable 后仍返回 true——日志失败绝不反噬业务。
|
||||
*
|
||||
* @param array $log Channel save() 传入的扁平 LogRecord 数组
|
||||
*/
|
||||
public function save(array $log): bool
|
||||
{
|
||||
try {
|
||||
$lines = [];
|
||||
|
||||
foreach ($log as $log_item) {
|
||||
if (!is_object($log_item) || !isset($log_item->type) || !is_string($log_item->type) || !isset($log_item->message)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = $log_item->message;
|
||||
|
||||
if (!is_string($content)) {
|
||||
$content = print_r($content, true);
|
||||
}
|
||||
|
||||
$row = DebugLogToolkit::buildRow($log_item->type, $content);
|
||||
|
||||
$lines[] = DebugLogToolkit::encodeRow($row);
|
||||
}
|
||||
|
||||
if (!empty($lines)) {
|
||||
DebugLogToolkit::appendLine(implode("\n", $lines));
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
// 铁律:绝不抛异常、绝不返回 false(失败即静默丢弃本批日志)
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user