【问题标题】:Logging full stack trace with Monolog使用 Monolog 记录完整的堆栈跟踪
【发布时间】:2014-01-06 13:58:04
【问题描述】:

我在我的应用程序中使用Monolog 作为独立库,最近我遇到了一个问题。比方说,在我的应用程序的某个时刻,我捕获了一个异常,我想记录它:

$mylogger->error('Exception caught', array('exception' => $exception));

除了一件小事之外,这一切都很好 - 它不会记录整个堆栈跟踪。是否可以使用 monolog 内置格式化程序记录异常的完整堆栈跟踪?

【问题讨论】:

    标签: php 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-&gt;error('Exception caught', $exception-&gt;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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-11-16
            • 1970-01-01
            • 2018-04-24
            • 1970-01-01
            • 2011-04-06
            • 1970-01-01
            • 2011-03-29
            • 2014-11-01
            相关资源
            最近更新 更多