diff --git a/.example.env b/.example.env index ed862f9..2ff9e6d 100644 --- a/.example.env +++ b/.example.env @@ -19,6 +19,7 @@ PREFIX=ul_ FIELDS_CACHE=false [LOG] +# 日志通道三选一:file(本地文件)/ debug_mysql(直写数据库)/ debug_mysql_async(异步:本地 JSONL + 定时导入,写日志零 DB 依赖) CHANNEL=file [TIMER] diff --git a/config/log.php b/config/log.php index f236c61..c69cb66 100644 --- a/config/log.php +++ b/config/log.php @@ -72,7 +72,11 @@ return [ 'charset' => Env::get('database.charset', 'utf8'), // 数据库表前缀 'prefix' => Env::get('database.prefix', 'ul_'), - ] + ], + // 异步模式:本地 JSONL + 定时导入,写日志零 DB 依赖 + 'debug_mysql_async' => [ + 'type' => 'DebugMysqlAsync', + ], ], ]; \ No newline at end of file diff --git a/extend/think/log/driver/DebugMysqlAsync.php b/extend/think/log/driver/DebugMysqlAsync.php new file mode 100644 index 0000000..186a080 --- /dev/null +++ b/extend/think/log/driver/DebugMysqlAsync.php @@ -0,0 +1,86 @@ +config = array_merge($this->config, $config); + } + } + + /** + * 落盘一批日志(扁平 array). + * + * 镜像 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; + } +}