043306819b
- 添加基础配置文件,包括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,开启调试模式 - 配置日志输出格式,支持多种日志处理器与颜色高亮 - 提供公共函数文件框架,便于扩展自定义功能
264 lines
8.8 KiB
PHP
264 lines
8.8 KiB
PHP
<?php
|
|
|
|
namespace app\utils;
|
|
|
|
use support\Log;
|
|
use Throwable;
|
|
|
|
/**
|
|
* 日志工具类(仅提供静态方法)
|
|
*/
|
|
class Logger
|
|
{
|
|
/**
|
|
* 获取日志实例(核心入口)
|
|
* @param string $name 日志器名称,默认 '__default'
|
|
* @return LoggerIns
|
|
*/
|
|
public static function new(string $name = '__default'): LoggerIns
|
|
{
|
|
return new LoggerIns($name);
|
|
}
|
|
|
|
/**
|
|
* 静态信息级别日志
|
|
* @param string $message 日志消息
|
|
* @param array|Throwable $context 占位符参数或异常对象
|
|
* @param string $name 日志器名称
|
|
*/
|
|
public static function InfoMsg(string $message, array|Throwable $context = [], string $name = '__default'): void
|
|
{
|
|
self::new($name)->info($message, $context);
|
|
}
|
|
|
|
/**
|
|
* 静态调试级别日志
|
|
* @param string $message 日志消息
|
|
* @param array|Throwable $context 占位符参数或异常对象
|
|
* @param string $name 日志器名称
|
|
*/
|
|
public static function debug(string $message, array|Throwable $context = [], string $name = '__default'): void
|
|
{
|
|
self::new($name)->debug($message, $context);
|
|
}
|
|
|
|
/**
|
|
* 静态warn方法(warning别名)
|
|
* @param string $message 日志消息
|
|
* @param array|Throwable $context 占位符参数或异常对象
|
|
* @param string $name 日志器名称
|
|
*/
|
|
public static function warn(string $message, array|Throwable $context = [], string $name = '__default'): void
|
|
{
|
|
self::new($name)->warn($message, $context);
|
|
}
|
|
|
|
/**
|
|
* 静态warn方法(warning别名)
|
|
* @param string $message 日志消息
|
|
* @param array|Throwable $context 占位符参数或异常对象
|
|
* @param string $name 日志器名称
|
|
*/
|
|
public static function warning(string $message, array|Throwable $context = [], string $name = '__default'): void
|
|
{
|
|
self::new($name)->warn($message, $context);
|
|
}
|
|
|
|
/**
|
|
* 静态错误级别日志
|
|
* @param string $message 日志消息
|
|
* @param array|Throwable $context 占位符参数或异常对象
|
|
* @param string $name 日志器名称
|
|
*/
|
|
public static function error(string $message, array|Throwable $context = [], string $name = '__default'): void
|
|
{
|
|
self::new($name)->error($message, $context);
|
|
}
|
|
|
|
/**
|
|
* 静态通用日志方法
|
|
* @param string $level 日志级别
|
|
* @param string $message 日志消息
|
|
* @param array|Throwable $context 占位符参数或异常对象
|
|
* @param string $name 日志器名称
|
|
*/
|
|
public static function log(string $level, string $message, array|Throwable $context = [], string $name = '__default'): void
|
|
{
|
|
self::new($name)->log($level, $message, $context);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 日志实例类(仅提供实例方法)
|
|
*/
|
|
class LoggerIns
|
|
{
|
|
public $name = '';
|
|
|
|
/**
|
|
* 构造函数:初始化日志器名称
|
|
* @param string $name 日志器名称,默认 '__default'
|
|
*/
|
|
public function __construct(string $name = '__default')
|
|
{
|
|
$this->name = $name;
|
|
}
|
|
|
|
/**
|
|
* 信息级别日志
|
|
* @param string $message 日志消息(支持 {} 占位符)
|
|
* @param array|Throwable $context 占位符替换参数或异常对象
|
|
*/
|
|
public function info(string $message, array|Throwable $context = []): void
|
|
{
|
|
$processedMessage = $this->buildMessage($message, $context);
|
|
Log::info($processedMessage);
|
|
}
|
|
|
|
/**
|
|
* 调试级别日志
|
|
* @param string $message 日志消息(支持 {} 占位符)
|
|
* @param array|Throwable $context 占位符替换参数或异常对象
|
|
*/
|
|
public function debug(string $message, array|Throwable $context = []): void
|
|
{
|
|
$processedMessage = $this->buildMessage($message, $context);
|
|
Log::debug($processedMessage);
|
|
}
|
|
|
|
/**
|
|
* 警告级别日志
|
|
* @param string $message 日志消息(支持 {} 占位符)
|
|
* @param array|Throwable $context 占位符替换参数或异常对象
|
|
*/
|
|
public function warning(string $message, array|Throwable $context = []): void
|
|
{
|
|
$processedMessage = $this->buildMessage($message, $context);
|
|
Log::warning($processedMessage);
|
|
}
|
|
|
|
/**
|
|
* warn 方法 - warning 的别名
|
|
* @param string $message 日志消息(支持 {} 占位符)
|
|
* @param array|Throwable $context 占位符替换参数或异常对象
|
|
*/
|
|
public function warn(string $message, array|Throwable $context = []): void
|
|
{
|
|
$this->warning($message, $context);
|
|
}
|
|
|
|
/**
|
|
* 错误级别日志
|
|
* @param string $message 日志消息(支持 {} 占位符)
|
|
* @param array|Throwable $context 占位符替换参数或异常对象
|
|
*/
|
|
public function error(string $message, array|Throwable $context = []): void
|
|
{
|
|
$processedMessage = $this->buildMessage($message, $context);
|
|
Log::error($processedMessage);
|
|
}
|
|
|
|
/**
|
|
* 通用日志方法
|
|
* @param string $level 日志级别 (info/debug/warning/warn/error/fatal)
|
|
* @param string $message 日志消息(支持 {} 占位符)
|
|
* @param array|Throwable $context 占位符替换参数或异常对象
|
|
*/
|
|
public function log(string $level, string $message, array|Throwable $context = []): void
|
|
{
|
|
// 验证并处理日志级别(兼容warn别名)
|
|
$validLevels = ['info', 'debug', 'warning', 'warn', 'error', 'fatal'];
|
|
$level = strtolower($level);
|
|
|
|
// 将warn映射为warning
|
|
if ($level === 'warn') {
|
|
$level = 'warning';
|
|
}
|
|
|
|
if (!in_array($level, $validLevels)) {
|
|
$level = 'info'; // 默认使用info级别
|
|
}
|
|
|
|
$processedMessage = $this->buildMessage($message, $context);
|
|
Log::{$level}($processedMessage);
|
|
}
|
|
|
|
/**
|
|
* 处理日志消息:替换占位符、处理异常、添加名称前缀
|
|
* @param string $message 原始日志消息
|
|
* @param array|Throwable $context 占位符参数或异常对象
|
|
* @return string 处理后的日志消息
|
|
*/
|
|
private function buildMessage(string $message, array|Throwable $context = []): string
|
|
{
|
|
// 1. 先处理占位符替换(无论是否有异常,先处理消息本身)
|
|
$processedMessage = $this->replacePlaceholders($message, is_array($context) ? $context : []);
|
|
|
|
// 2. 处理异常对象:换行输出完整异常内容,优化堆栈缩进
|
|
if ($context instanceof Throwable) {
|
|
// 转换异常为字符串并优化堆栈缩进(制表符)
|
|
$exceptionStr = $this->formatExceptionStackTrace((string)$context);
|
|
// 使用 PHP_EOL 保证跨系统换行
|
|
$processedMessage .= PHP_EOL . $exceptionStr;
|
|
}
|
|
|
|
// 3. 添加名称前缀 [name]
|
|
$namePrefix = "<RP_NAME:{$this->name}>";
|
|
return $namePrefix . $processedMessage;
|
|
}
|
|
|
|
/**
|
|
* 格式化异常堆栈:让Stack trace下的每一行添加制表符缩进
|
|
* @param string $exceptionStr 原始异常字符串
|
|
* @return string 格式化后的异常字符串
|
|
*/
|
|
private function formatExceptionStackTrace(string $exceptionStr): string
|
|
{
|
|
// 正则匹配 Stack trace: 后的所有行,并在每行前添加制表符
|
|
$pattern = '/(Stack trace:\s*)(.*)$/s';
|
|
return preg_replace_callback($pattern, function ($matches) {
|
|
// $matches[1] 是 "Stack trace: "
|
|
// $matches[2] 是堆栈内容
|
|
$stackTrace = $matches[2];
|
|
// 将堆栈的每一行(#开头)前添加 制表符(\t)
|
|
$formattedStack = preg_replace('/(#\d+)/', "\t$1", $stackTrace);
|
|
return $matches[1] . $formattedStack;
|
|
}, $exceptionStr);
|
|
}
|
|
|
|
/**
|
|
* 内部方法:替换 {} 占位符
|
|
* @param string $message 原始消息
|
|
* @param array $context 替换参数
|
|
* @return string 替换后的消息
|
|
*/
|
|
private function replacePlaceholders(string $message, array $context = []): string
|
|
{
|
|
if (empty($context)) {
|
|
return $message;
|
|
}
|
|
|
|
// 将上下文参数转换为安全的字符串
|
|
$replacements = array_map(function ($value) {
|
|
if ($value === null) {
|
|
return 'null';
|
|
}
|
|
if (is_bool($value)) {
|
|
return $value ? 'true' : 'false';
|
|
}
|
|
if (is_array($value) || is_object($value)) {
|
|
return json_encode($value, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR);
|
|
}
|
|
return (string)$value;
|
|
}, $context);
|
|
|
|
// 按顺序替换 {} 占位符
|
|
$index = 0;
|
|
$result = preg_replace_callback('/\{\}/', function () use (&$index, $replacements) {
|
|
return isset($replacements[$index]) ? $replacements[$index++] : '{}';
|
|
}, $message);
|
|
|
|
// 替换失败时返回原始消息
|
|
return $result ?: $message;
|
|
}
|
|
} |