82 lines
3.1 KiB
PHP
82 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace app\bootstrap;
|
|
|
|
use app\config\Config;
|
|
use Illuminate\Database\Events\QueryExecuted;
|
|
use support\Db;
|
|
use support\Log;
|
|
|
|
// 引入webman内置日志类
|
|
use Webman\Bootstrap;
|
|
|
|
/**
|
|
* 在控制台/日志文件打印执行的SQL语句
|
|
*/
|
|
class SqlDebug implements Bootstrap
|
|
{
|
|
public static function start($worker)
|
|
{
|
|
// 判断是否为控制台环境
|
|
$is_console = !$worker;
|
|
if ($is_console) {
|
|
return;
|
|
}
|
|
|
|
// 仅在调试模式下开启
|
|
$debug = config("app.debug");
|
|
if (!$debug || $debug === 'false') {
|
|
return;
|
|
}
|
|
|
|
$appPath = app_path();
|
|
|
|
if (Config::getInstance()->dbDebug) Db::connection()->listen(function (QueryExecuted $queryExecuted) use ($appPath) {
|
|
// 过滤掉 "select 1" 这类心跳检测SQL
|
|
if (isset($queryExecuted->sql) && $queryExecuted->sql !== "select 1") {
|
|
$bindings = $queryExecuted->bindings;
|
|
// 替换SQL中的?为实际绑定参数
|
|
$sql = array_reduce(
|
|
$bindings,
|
|
function ($sql, $binding) {
|
|
// 处理参数类型:字符串加引号,数值/布尔直接使用,null显示为NULL
|
|
$value = match (true) {
|
|
is_string($binding) => "'{$binding}'",
|
|
is_null($binding) => 'NULL',
|
|
is_bool($binding) => $binding ? 1 : 0,
|
|
default => $binding
|
|
};
|
|
return preg_replace('/\?/', $value, $sql, 1);
|
|
},
|
|
$queryExecuted->sql
|
|
);
|
|
|
|
// 构造基础SQL日志信息
|
|
$sqlLog = sprintf(
|
|
"%s",
|
|
$sql
|
|
);
|
|
|
|
// 定位产生SQL的业务文件/行号/方法
|
|
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
|
foreach ($traces as $trace) {
|
|
if (isset($trace['file'], $trace['function']) && str_contains($trace['file'], $appPath)) {
|
|
// 格式化文件路径(去掉项目根目录,只保留相对路径)
|
|
$file = str_replace(base_path(), '', $trace['file']);
|
|
$file = ltrim($file, '/\\');
|
|
$file = str_replace(".php", '', $file);
|
|
$file = str_replace("\\", '.', $file);
|
|
$file = str_replace("/", '.', $file);
|
|
// $file = basename($file);
|
|
|
|
// 使用Logger::debug输出日志(会同时输出到控制台和日志文件)
|
|
Log::debug(
|
|
'<SQL_LOG_F>' . $file . "</SQL_LOG_F><SQL_LOG_L>{$trace['line']}</SQL_LOG_L><SQL_LOG_M>{$trace['function']}</SQL_LOG_M>[$queryExecuted->time ms] " . $sqlLog
|
|
);
|
|
break; // 只打印第一个匹配的业务文件信息,避免重复输出
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
} |