Monolog: Add Formatter that uses MWExceptionHandler::getRedactedTraceAsString
authorBryan Davis <bd808@wikimedia.org>
Thu, 30 Jul 2015 19:02:35 +0000 (13:02 -0600)
committerBryan Davis <bd808@wikimedia.org>
Fri, 31 Jul 2015 19:02:39 +0000 (13:02 -0600)
Add a Monolog Formatter class that uses
MWExceptionHandler::getRedactedTraceAsString when outputting stack
traces.

Bug: T107440
Change-Id: Ic580c137e27aac95435f7b073a18cf61820b172f

autoload.php
includes/debug/logger/LegacyLogger.php
includes/debug/logger/monolog/LineFormatter.php [new file with mode: 0644]
tests/phpunit/includes/debug/logger/monolog/LineFormatterTest.php [new file with mode: 0644]

index 4109740..28884c3 100644 (file)
@@ -754,6 +754,7 @@ $wgAutoloadLocalClasses = array(
        'MediaWiki\\Logger\\MonologSpi' => __DIR__ . '/includes/debug/logger/MonologSpi.php',
        'MediaWiki\\Logger\\Monolog\\LegacyFormatter' => __DIR__ . '/includes/debug/logger/monolog/LegacyFormatter.php',
        'MediaWiki\\Logger\\Monolog\\LegacyHandler' => __DIR__ . '/includes/debug/logger/monolog/LegacyHandler.php',
+       'MediaWiki\\Logger\\Monolog\\LineFormatter' => __DIR__ . '/includes/debug/logger/monolog/LineFormatter.php',
        'MediaWiki\\Logger\\Monolog\\SyslogHandler' => __DIR__ . '/includes/debug/logger/monolog/SyslogHandler.php',
        'MediaWiki\\Logger\\Monolog\\WikiProcessor' => __DIR__ . '/includes/debug/logger/monolog/WikiProcessor.php',
        'MediaWiki\\Logger\\NullSpi' => __DIR__ . '/includes/debug/logger/NullSpi.php',
index 831ad1b..b6439b8 100644 (file)
@@ -222,7 +222,7 @@ class LegacyLogger extends AbstractLogger {
                        $context['exception'] instanceof Exception
                ) {
                        $text .= MWExceptionHandler::getRedactedTraceAsString(
-                               $context['exception']->getTraceAsString()
+                               $context['exception']
                        ) . "\n";
                }
 
diff --git a/includes/debug/logger/monolog/LineFormatter.php b/includes/debug/logger/monolog/LineFormatter.php
new file mode 100644 (file)
index 0000000..e593d63
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Logger\Monolog;
+
+use Exception;
+use Monolog\Formatter\LineFormatter as MonologLineFormatter;
+use MWExceptionHandler;
+
+/**
+ * Formats incoming records into a one-line string.
+ *
+ * Exceptions that are logged with this formatter will optional have their
+ * stack traces appended. If that is done,
+ * MWExceptionHandler::getRedactedTraceAsString() will be used to redact the
+ * trace information.
+ *
+ * @since 1.26
+ * @author Bryan Davis <bd808@wikimedia.org>
+ * @copyright © 2015 Bryan Davis and Wikimedia Foundation.
+ */
+class LineFormatter extends MonologLineFormatter {
+
+       /**
+        * @param string $format The format of the message
+        * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
+        * @param bool $allowInlineLineBreaks Whether to allow inline line breaks in log entries
+        * @param bool $ignoreEmptyContextAndExtra
+        * @param bool $includeStacktraces
+        */
+       public function __construct(
+               $format = null, $dateFormat = null, $allowInlineLineBreaks = false,
+               $ignoreEmptyContextAndExtra = false, $includeStacktraces = false
+       ) {
+               parent::__construct(
+                       $format, $dateFormat, $allowInlineLineBreaks,
+                       $ignoreEmptyContextAndExtra
+               );
+               $this->includeStacktraces( $includeStacktraces );
+       }
+
+
+       /**
+        * Convert an Exception to a string.
+        *
+        * @param Exception $e
+        * @return string
+        */
+       protected function normalizeException( Exception $e ) {
+               $str = '[Exception ' . get_class( $e ) . '] (' .
+                       $e->getFile() . ':' . $e->getLine() . ') ' .
+                       $e->getMessage();
+
+               $prev = $e->getPrevious();
+               while ( $prev ) {
+                       $str .= ', [Exception ' . get_class( $prev ) . '] (' .
+                               $prev->getFile() . ':' . $prev->getLine() . ') ' .
+                               $prev->getMessage();
+                       $prev = $prev->getPrevious();
+               }
+
+               if ( $this->includeStacktraces ) {
+                       $str .= "\n[stacktrace]\n" .
+                               MWExceptionHandler::getRedactedTraceAsString( $e ) .
+                               "\n";
+               }
+
+               return $str;
+       }
+}
diff --git a/tests/phpunit/includes/debug/logger/monolog/LineFormatterTest.php b/tests/phpunit/includes/debug/logger/monolog/LineFormatterTest.php
new file mode 100644 (file)
index 0000000..05c32a0
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Logger\Monolog;
+
+use InvalidArgumentException;
+use LengthException;
+use LogicException;
+use MediaWikiTestCase;
+use TestingAccessWrapper;
+
+class LineFormatterTest extends MediaWikiTestCase {
+
+       /**
+        * @covers LineFormatter::normalizeException
+        */
+       public function testNormalizeExceptionNoTrace() {
+               $fixture = new LineFormatter();
+               $fixture->includeStacktraces( false );
+               $fixture = TestingAccessWrapper::newFromObject( $fixture );
+               $boom = new InvalidArgumentException( 'boom', 0,
+                       new LengthException( 'too long', 0,
+                               new LogicException( 'Spock wuz here' )
+                       )
+               );
+               $out = $fixture->normalizeException( $boom );
+               $this->assertContains( '[Exception InvalidArgumentException]', $out );
+               $this->assertContains( ', [Exception LengthException]', $out );
+               $this->assertContains( ', [Exception LogicException]', $out );
+               $this->assertNotContains( '[stacktrace]', $out );
+       }
+
+       /**
+        * @covers LineFormatter::normalizeException
+        */
+       public function testNormalizeExceptionTrace() {
+               $fixture = new LineFormatter();
+               $fixture->includeStacktraces( true );
+               $fixture = TestingAccessWrapper::newFromObject( $fixture );
+               $boom = new InvalidArgumentException( 'boom', 0,
+                       new LengthException( 'too long', 0,
+                               new LogicException( 'Spock wuz here' )
+                       )
+               );
+               $out = $fixture->normalizeException( $boom );
+               $this->assertContains( '[Exception InvalidArgumentException', $out );
+               $this->assertContains( ', [Exception LengthException]', $out );
+               $this->assertContains( ', [Exception LogicException]', $out );
+               $this->assertContains( '[stacktrace]', $out );
+       }
+}