如何让Laravel 6.x的Monolog输出异常链所有异常的栈追踪?
Laravel 异常链栈追踪输出解决方案
方案1:合并输出异常链中所有异常的完整栈追踪
通过自定义Monolog格式化器实现,无需修改核心异常逻辑,配置即可生效:
- 创建自定义格式化器类
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); } }
- 配置日志通道使用自定义格式化器
修改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:仅输出根因异常的栈追踪
如果不需要完整异常链,只需要最底层的根因异常栈,可通过重写异常处理器的报告逻辑实现:
- 打开
app/Exceptions/Handler.php,新增获取根因异常的辅助方法:
protected function getRootException(Throwable $e): Throwable { while ($e->getPrevious()) { $e = $e->getPrevious(); } return $e; }
- 重写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
相关产品推荐
相关产品推荐

