使用 Monolog 记录完整的堆栈跟踪
Posted
技术标签:
【中文标题】使用 Monolog 记录完整的堆栈跟踪【英文标题】:Logging full stack trace with Monolog 【发布时间】:2014-01-06 13:58:04 【问题描述】:我在我的应用程序中使用Monolog 作为独立库,最近我遇到了一个问题。比方说,在我的应用程序的某个时刻,我捕获了一个异常,我想记录它:
$mylogger->error('Exception caught', array('exception' => $exception));
除了一件小事之外,这一切都很好 - 它不会记录整个堆栈跟踪。是否可以使用 monolog 内置格式化程序记录异常的完整堆栈跟踪?
【问题讨论】:
【参考方案1】:实际上,从1.12.0
版本开始,可以在日志文件中包含堆栈跟踪:LineFormatter
的新方法称为includeStacktraces
。
要使用这个,你需要覆盖独白格式化程序的默认行为:
config.yml
monolog:
handlers:
main:
formatter: your.monolog.service.id
(rest of config is as usual)
services.yml
services:
your.monolog.service.id:
class: Monolog\Formatter\LineFormatter
calls:
- [includeStacktraces]
查看 github 了解更多信息: Pull request
【讨论】:
JsonFormatter中也存在 我添加了一个separate answer,其中包含在没有配置文件的情况下使用所述方法所需的代码。不允许用户对其他人的答案进行大量编辑,但如果您想在其中进行编辑,我会删除我的。【参考方案2】:我有一个非常简单的解决方案!!!
$mylogger->error((string) $exception);
【讨论】:
你甚至可以省略(字符串)调用。至少如果你使用 Monolog。【参考方案3】:不,您不能使用内置格式化程序记录堆栈跟踪。请参阅我的问题here。
如果您查看LineFormatter.php
,您会看到normalizeException
方法负责获取异常数据。因此,我必须创建一个扩展 LineFormatter
的新格式化程序。代码如下:
<?php
namespace Monolog\Formatter;
use Exception;
class ExceptionLineFormatter extends LineFormatter
protected function normalizeException(Exception $e)
return 'Message: ' . $e->getMessage() .
'Stack Trace: '. $e->getTraceAsString();
我像这样初始化了我的记录器:
$logFile = 'MyLogFile.txt';
$handler = new StreamHandler($logFile);
$handler->setFormatter(new ExceptionLineFormatter);
$log = new Logger('MyLogger');
$handler = self::getStreamHander();
$log->pushHandler($handler);
这将打印出您的堆栈跟踪。
【讨论】:
这个答案已经过时了;-)【参考方案4】:添加到Tomasz Madeyski's answer,这就是您可以仅通过代码使用它的方式:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\ErrorHandler;
use Monolog\Formatter\LineFormatter;
$formatter = new LineFormatter(LineFormatter::SIMPLE_FORMAT, LineFormatter::SIMPLE_DATE);
$formatter->includeStacktraces(true); // <--
$stream = new StreamHandler('error.log');
$stream->setFormatter($formatter);
$logger = new Logger('logger');
$logger->pushHandler($stream);
【讨论】:
【参考方案5】:您可以简单地使用带有“include_stacktraces”参数的配置文件(Symfony Bundle):
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: info
channels: ["!event"]
max_files: 10
include_stacktraces: true <--- SET TO TRUE
@see this commit
@see the full schema (configuration)
【讨论】:
但它也适合logstash格式吗?【参考方案6】:这就是我的做法,是的,多年后...
$mylogger->error('Exception caught', $exception->getTrace());
因为 getTrace() 返回一个数组,这正是 Monolog 想要的。
【讨论】:
对于像我这样使用它的任何人,请注意,如果您使用 Gelf 处理程序,这将引发异常。由于 getTrace 数组从 0 开始计数,这是GelfMessage::setAdditional()
中的无效键【参考方案7】:
如果您想在抛出异常时仅记录堆栈跟踪,您可以在AppServiceProvider
中执行此操作:
public function register()
$logger = Log::getMonolog();
$logger->pushProcessor(function ($record)
if (isset($record['context']['exception']))
$record['extra']['stacktrace'] = $record['context']['exception']->getTraceAsString();
return $record;
);
这会将堆栈跟踪添加到extra
列,然后可以在每个 LineFormatter 中使用
【讨论】:
【参考方案8】:getTraceAsString 将为您提供堆栈跟踪数组作为“行尾”分隔的字符串。在 PHP_EOL 上展开,然后通过数组记录每个元素的 foreach。希望这会有所帮助。
<?php
function test()
throw new Exception;
try
test();
catch(Exception $e)
$array = explode(PHP_EOL, $e->getTraceAsString());
foreach($array as $line)
$mylogger->error($line);
应该产生这样的东西:
#0 index.php(14): test()
#1 main
【讨论】:
【参考方案9】:Upvoted answer works,但您不必为此创建自定义服务。
monolog.formatter.line
已经存在于 Symfony 3.4 全栈中。感谢CompilerPassInterface
,您可以简单地在其上添加方法调用:
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use use Symfony\Component\HttpKernel\Kernel;
class AppKernel extends Kernel implements CompilerPassInterface
public function process(ContainerBuilder $container)
$container->getDefinition('monolog.formatter.line')->addMethodCall('includeStacktraces');
monolog 处理程序似乎默认不接收服务,所以你还是要指定它。示例:
monolog:
handlers:
main:
type: rotating_file
max_files: 12
date_format: 'Y-m'
path: '%kernel.logs_dir%/%kernel.environment%.log'
level: debug
formatter: monolog.formatter.line
【讨论】:
以上是关于使用 Monolog 记录完整的堆栈跟踪的主要内容,如果未能解决你的问题,请参考以下文章