You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Laravel 6.x的Monolog输出异常链所有异常的栈追踪?

Laravel 异常链栈追踪输出解决方案

方案1:合并输出异常链中所有异常的完整栈追踪

通过自定义Monolog格式化器实现,无需修改核心异常逻辑,配置即可生效:

  1. 创建自定义格式化器类 app/Logging/ExceptionChainFormatter.php
<?php
namespace App\Logging;
use Monolog\Formatter\LineFormatter;
use Throwable;

class ExceptionChainFormatter extends LineFormatter
{
    // 自定义输出格式,可根据需要调整
    public function __construct(
        ?string $format = null,
        ?string $dateFormat = null,
        bool $allowInlineLineBreaks = true,
        bool $ignoreEmptyContextAndExtra = false
    ) {
        parent::__construct($format, $dateFormat, $allowInlineLineBreaks, $ignoreEmptyContextAndExtra);
    }

    public function format(array $record): string
    {
        // 存在异常上下文时递归遍历异常链
        if (isset($record['context']['exception']) && $record['context']['exception'] instanceof Throwable) {
            $currentException = $record['context']['exception'];
            $chainContent = "\n--- 异常链完整信息 ---\n";
            $index = 1;
            while ($currentException) {
                $chainContent .= sprintf(
                    "[异常%d] 消息: %s | 文件: %s | 行号: %d\n栈追踪:\n%s\n\n",
                    $index,
                    $currentException->getMessage(),
                    $currentException->getFile(),
                    $currentException->getLine(),
                    $currentException->getTraceAsString()
                );
                $currentException = $currentException->getPrevious();
                $index++;
            }
            // 将异常链内容追加到日志末尾
            $record['message'] .= $chainContent;
            // 移除默认exception上下文,避免重复输出外层异常栈
            unset($record['context']['exception']);
        }
        return parent::format($record);
    }
}
  1. 配置日志通道使用自定义格式化器
    修改config/logging.php,在你常用的日志通道(比如daily、single)中加入formatter配置:
'channels' => [
    'daily' => [
        'driver' => 'daily',
        'path' => storage_path('logs/laravel.log'),
        'level' => env('LOG_LEVEL', 'debug'),
        'days' => 14,
        // 加入以下配置
        'formatter' => App\Logging\ExceptionChainFormatter::class,
    ],
    // 其他通道配置...
],

配置完成后日志会自动输出所有链式异常的完整栈信息,包含你示例代码中method3抛出的根因异常栈。

方案2:仅输出根因异常的栈追踪

如果不需要完整异常链,只需要最底层的根因异常栈,可通过重写异常处理器的报告逻辑实现:

  1. 打开app/Exceptions/Handler.php,新增获取根因异常的辅助方法:
protected function getRootException(Throwable $e): Throwable
{
    while ($e->getPrevious()) {
        $e = $e->getPrevious();
    }
    return $e;
}
  1. 重写report方法,将根因异常作为日志上报的异常对象:
public function report(Throwable $exception)
{
    if ($this->shouldReport($exception)) {
        $rootException = $this->getRootException($exception);
        // 替换上报的异常为根因异常
        parent::report($rootException);
        return;
    }
    parent::report($exception);
}

该方案下日志只会输出最开始抛出的根因异常的栈信息,完全符合你示例中需要输出method3抛出异常栈的需求。

内容的提问来源于stack exchange,提问作者Leigh Bicknell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 09:06:06