feat(webman): 初始化webman框架基础配置与核心代码
- 添加基础配置文件,包括app、autoload、bootstrap、container、database、dependence、exception、log、middleware - 新增完整Dockerfile和docker-compose.yml,支持容器化运行 - 增加webman控制台插件配置及依赖管理文件composer.json - 创建app目录下核心控制器IndexController及进程Http和Monitor - 实现日志工具类Logger,支持多级别及异常格式化 - 配置.gitignore优化忽略无关文件和目录 - 初始化.idea项目配置文件,支持开发环境集成 - 完善启动流程,支持自动加载配置、路由及中间件 - 增加文件变更监控和内存监控机制,提升开发体验 - 设定默认时区为Asia/Shanghai,开启调试模式 - 配置日志输出格式,支持多种日志处理器与颜色高亮 - 提供公共函数文件框架,便于扩展自定义功能
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\RotatingFileHandler;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\FilterHandler;
|
||||
use Monolog\Processor\ProcessIdProcessor;
|
||||
|
||||
return [
|
||||
'default' => [
|
||||
'handlers' => [
|
||||
// 控制台输出处理器
|
||||
[
|
||||
'class' => StreamHandler::class,
|
||||
'constructor' => [
|
||||
'php://stdout',
|
||||
Logger::DEBUG,
|
||||
],
|
||||
'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',
|
||||
7,
|
||||
Logger::DEBUG,
|
||||
],
|
||||
'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',
|
||||
7,
|
||||
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
|
||||
) {
|
||||
// 获取文件路径(简化为项目内相对路径)
|
||||
$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'];
|
||||
|
||||
$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);
|
||||
}else{
|
||||
$record['logger'] = $file;
|
||||
$record['message'] = $message;
|
||||
}
|
||||
|
||||
$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']), 7);
|
||||
return $record;
|
||||
}
|
||||
]
|
||||
],
|
||||
];
|
||||
Reference in New Issue
Block a user