149 lines
4.4 KiB
PHP
149 lines
4.4 KiB
PHP
<?php
|
||
|
||
namespace App\Exceptions;
|
||
|
||
use Exception;
|
||
use Illuminate\Support\Facades\Log;
|
||
|
||
/**
|
||
* 日志异常处理类
|
||
* 专门处理日志系统相关的异常,避免影响主业务流程
|
||
*/
|
||
class LogException extends Exception
|
||
{
|
||
/**
|
||
* 安全记录异常到系统日志
|
||
*
|
||
* @param string $message 错误消息
|
||
* @param \Exception|null $exception 原始异常
|
||
* @param array $context 上下文信息
|
||
*/
|
||
public static function safeLog(string $message, ?\Exception $exception = null, array $context = []): void
|
||
{
|
||
try {
|
||
// 构建完整的错误信息
|
||
$fullMessage = $message;
|
||
if ($exception) {
|
||
$fullMessage .= ' | 异常: ' . $exception->getMessage();
|
||
$fullMessage .= ' | 文件: ' . $exception->getFile() . ':' . $exception->getLine();
|
||
}
|
||
|
||
// 尝试多种日志记录方式
|
||
self::tryLogToChannels($fullMessage, $context);
|
||
|
||
} catch (\Exception $e) {
|
||
// 最后的兜底方案:系统错误日志
|
||
error_log("Laravel日志系统完全失效 - 原始消息: {$message} | 日志异常: {$e->getMessage()}");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 尝试多个日志通道记录
|
||
*/
|
||
private static function tryLogToChannels(string $message, array $context): void
|
||
{
|
||
$channels = ['single', 'daily', 'errorlog'];
|
||
|
||
foreach ($channels as $channel) {
|
||
try {
|
||
Log::channel($channel)->warning($message, $context);
|
||
return; // 成功记录后退出
|
||
} catch (\Exception $e) {
|
||
continue; // 继续尝试下一个通道
|
||
}
|
||
}
|
||
|
||
// 所有Laravel日志通道都失败,使用系统错误日志
|
||
error_log("Laravel日志记录失败: {$message}");
|
||
}
|
||
|
||
/**
|
||
* 检查日志目录权限并尝试修复
|
||
*
|
||
* @param string $logPath 日志路径
|
||
* @return bool 是否修复成功
|
||
*/
|
||
public static function checkAndFixLogPermissions(string $logPath): bool
|
||
{
|
||
try {
|
||
$logDir = dirname($logPath);
|
||
|
||
// 检查目录是否存在
|
||
if (!is_dir($logDir)) {
|
||
if (!mkdir($logDir, 0755, true)) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 检查目录权限
|
||
if (!is_writable($logDir)) {
|
||
// 尝试修改权限
|
||
if (!chmod($logDir, 0755)) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 如果日志文件存在,检查文件权限
|
||
if (file_exists($logPath) && !is_writable($logPath)) {
|
||
if (!chmod($logPath, 0644)) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
|
||
} catch (\Exception $e) {
|
||
self::safeLog("日志权限检查失败: " . $e->getMessage(), $e);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取所有配置的日志路径
|
||
*
|
||
* @return array
|
||
*/
|
||
public static function getAllLogPaths(): array
|
||
{
|
||
$paths = [];
|
||
|
||
try {
|
||
$channels = config('logging.channels', []);
|
||
|
||
foreach ($channels as $name => $config) {
|
||
if (isset($config['path'])) {
|
||
$paths[$name] = $config['path'];
|
||
}
|
||
}
|
||
|
||
} catch (\Exception $e) {
|
||
self::safeLog("获取日志路径配置失败: " . $e->getMessage(), $e);
|
||
}
|
||
|
||
return $paths;
|
||
}
|
||
|
||
/**
|
||
* 批量检查所有日志路径权限
|
||
*
|
||
* @return array 返回检查结果
|
||
*/
|
||
public static function checkAllLogPermissions(): array
|
||
{
|
||
$results = [];
|
||
$paths = self::getAllLogPaths();
|
||
|
||
foreach ($paths as $channel => $path) {
|
||
$results[$channel] = [
|
||
'path' => $path,
|
||
'writable' => self::checkAndFixLogPermissions($path),
|
||
'dir_exists' => is_dir(dirname($path)),
|
||
'dir_writable' => is_writable(dirname($path)),
|
||
'file_exists' => file_exists($path),
|
||
'file_writable' => file_exists($path) ? is_writable($path) : null
|
||
];
|
||
}
|
||
|
||
return $results;
|
||
}
|
||
}
|