Files
tcpserver-flow/config/log.php
T
zimoyin defe163190 test
2026-03-18 13:27:48 +08:00

184 lines
7.8 KiB
PHP

<?php
use Monolog\Logger;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FilterHandler;
use Monolog\Processor\ProcessIdProcessor;
use app\config\Config;
return [
'default' => [
'handlers' => [
// 控制台输出处理器
[
'class' => StreamHandler::class,
'constructor' => [
'php://stdout',
Config::getInstance()->logLevel,
],
'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class,
/**
* 格式化日志输出
* %start%: 标记日志颜色
* %end%: 结束标记颜色
* %logger%: 日志记录器名称
* %L: 行号
* %M: 方法名
* %P: 进程ID
* %thread%: 线程ID
* %Level%: 日志级别(带有占位符)
* %level_name%: 日志级别名称
* %level%: 日志等级数字
* %message%: 日志内容
* %datetime%: 时间
*/
'constructor' => [
"%start%%datetime% [%thread%] %Level% %logger%:%L% - %message%%end%\n",
'Y-m-d H:i:s',
true
],
],
],
// 默认文件输出处理器
[
'class' => RotatingFileHandler::class,
'constructor' => [
runtime_path() . '/logs/webman.log',
Config::getInstance()->logRotationTimeByDay,
Config::getInstance()->logLevel,
],
'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class,
'constructor' => [
"%datetime% [%thread%] %Level% %logger%:%L% - %message%\n",
'Y-m-d H:i:s',
true
],
],
],
// Error级别单独文件处理器
[
'class' => FilterHandler::class,
'constructor' => [
new RotatingFileHandler(
runtime_path() . '/logs/error.log',
Config::getInstance()->errorLogRotationTimeByDay,
Logger::DEBUG
),
Logger::ERROR,
Logger::EMERGENCY
],
'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class,
'constructor' => [
"%datetime% [%thread%] %Level% %logger%:%L% - %message%\n",
'Y-m-d H:i:s',
true
],
],
],
],
// 全局处理器:手动解析调用栈,精准定位业务代码
'processors' => [
// 1. 注入进程ID(生成线程名)
new ProcessIdProcessor(),
// 2. 手动解析调用栈,获取实际业务代码位置 + 日志过滤
function ($record) {
$message = $record['message'];
// 线程名
$processId = $record['extra']['process'] ?? 0;
$record['thread'] = "thread-{$processId}";
// 手动解析调用栈,定位实际业务代码
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10); // 获取调用栈(前10层)
$file = $record['channel'];
$function = '';
$line = '0';
// 遍历调用栈,跳过日志类相关的层,找到业务代码层
foreach ($trace as $step) {
// 跳过 webman 日志类、monolog 相关的调用层
if (isset($step['file'])
&& str_contains($step['file'], 'support') === false
&& str_contains($step['file'], 'monolog') === false
&& str_contains($step['file'], 'Logger') === false
) {
// 获取文件路径(简化为项目内相对路径)
$file = $step['file'];
$projectRoot = base_path();
if (str_starts_with($file, $projectRoot)) {
$file = substr($file, strlen($projectRoot) + 1);
}
$file = str_replace('.php', '', $file);
$file = str_replace('\\', '.', $file);
// 获取方法名
$function = $step['function'];
// 获取行
$line = $step['line'] ?? '0';
break; // 找到第一个业务代码层就停止
}
}
$record['M'] = $function;
$record['L'] = $line;
$record['P'] = $record['extra']['process_id'];
// 解析 <RP_NAME:xxx> 标签
$pattern = '/<RP_NAME:(.*?)>/si';
if (preg_match_all($pattern, $message, $matches) && !empty($matches[1])) {
$record['logger'] = $matches[1][0];
$record['message'] = preg_replace($pattern, '', $message);
if ($matches[1][0] == '__default') $record['logger'] = $file;
} else {
$record['logger'] = $file;
$record['message'] = $message;
}
// 解析 SQL_LOG 相关标签
$tagPatterns = [
'logger' => '/<SQL_LOG_F>(.*?)<\/SQL_LOG_F>/s', // 文件路径
'L' => '/<SQL_LOG_L>(.*?)<\/SQL_LOG_L>/s', // 行号
'M' => '/<SQL_LOG_M>(.*?)<\/SQL_LOG_M>/s' // 方法名
];
$tempMessage = $record['message']; // 基于处理后的message继续解析
foreach ($tagPatterns as $key => $pattern) {
if (preg_match($pattern, $tempMessage, $matches)) {
$record[$key] = $matches[1];
$tempMessage = preg_replace($pattern, '', $tempMessage); // 移除当前标签
$record['message'] = trim($tempMessage);
}
}
// 日志级别颜色映射
$levelColorMap = [
Logger::EMERGENCY => "\033[41m\033[37m", // 最高级别:红色底色+白色字体
Logger::ALERT => "\033[41m\033[37m", // 警报:红色底色+白色字体
Logger::CRITICAL => "\033[41m\033[37m", // 严重:红色底色+白色字体
Logger::ERROR => "\033[31m", // 错误:红色字体(无底色)
Logger::WARNING => "\033[33m", // 警告:深黄色字体
Logger::INFO => "\033[32m", // 信息:绿色字体
Logger::DEBUG => "\033[34m", // 调试:蓝色字体
];
$record['start'] = "\033[0m";
$record['end'] = "\033[0m";
foreach ($levelColorMap as $level => $color) {
if ($record['level'] >= $level) {
$record['start'] = $color;
$record['end'] = "\033[0m";
break;
}
}
$record['Level'] = str_pad(strtoupper($record['level_name']), 5);
return $record;
}
],
'ignore' => [
app_path() . '/flow/config/AbstractConfig.php'
],
],
];