Browse Source

Improve console error display

I've often found that the console error log format includes way too much
noise in the stack trace. I'm often most interested in the file/line
numbers in the stack trace, so that's all that remains.

I've also added newlines and small formatting changes to how messages
are display so they don't wrap quite so often.
Mark Story 6 years ago
parent
commit
44178142eb

+ 2 - 2
src/Error/ConsoleErrorHandler.php

@@ -80,7 +80,7 @@ class ConsoleErrorHandler extends BaseErrorHandler
         }
 
         $message = sprintf(
-            '<error>%s</error> %s in [%s, line %s]',
+            "<error>%s</error> %s\nIn [%s, line %s]\n",
             $errorName,
             $exception->getMessage(),
             $exception->getFile(),
@@ -101,7 +101,7 @@ class ConsoleErrorHandler extends BaseErrorHandler
     protected function _displayError(array $error, bool $debug): void
     {
         $message = sprintf(
-            '%s in [%s, line %s]',
+            "%s\nIn [%s, line %s]",
             $error['description'],
             $error['file'],
             $error['line']

+ 5 - 1
src/Error/ErrorLogger.php

@@ -107,7 +107,11 @@ class ErrorLogger
         }
 
         if ($this->getConfig('trace')) {
-            $message .= "\nStack Trace:\n" . $exception->getTraceAsString();
+            $trace = Debugger::formatTrace($exception, ['format' => 'points']);
+            $message .= "\nStack Trace:\n";
+            foreach ($trace as $line) {
+                $message .= "- {$line['file']}:{$line['line']}\n";
+            }
         }
 
         $previous = $exception->getPrevious();

+ 17 - 26
tests/TestCase/Error/ConsoleErrorHandlerTest.php

@@ -16,6 +16,7 @@ declare(strict_types=1);
  */
 namespace Cake\Test\TestCase\Error;
 
+use Cake\TestSuite\Stub\ConsoleOutput;
 use Cake\Controller\Exception\MissingActionException;
 use Cake\Core\Exception\Exception;
 use Cake\Http\Exception\InternalErrorException;
@@ -36,9 +37,7 @@ class ConsoleErrorHandlerTest extends TestCase
     public function setUp(): void
     {
         parent::setUp();
-        $this->stderr = $this->getMockBuilder('Cake\Console\ConsoleOutput')
-            ->disableOriginalConstructor()
-            ->getMock();
+        $this->stderr = new ConsoleOutput();
         $this->Error = $this->getMockBuilder('Cake\Error\ConsoleErrorHandler')
             ->setMethods(['_stop'])
             ->setConstructorArgs([['stderr' => $this->stderr]])
@@ -64,13 +63,12 @@ class ConsoleErrorHandlerTest extends TestCase
      */
     public function testHandleError()
     {
-        $content = "<error>Notice Error:</error> This is a notice error in [/some/file, line 275]\n";
-        $this->stderr->expects($this->once())->method('write')
-            ->with($content);
+        $content = "<error>Notice Error:</error> This is a notice error\nIn [/some/file, line 275]\n";
         $this->Error->expects($this->never())
             ->method('_stop');
 
         $this->Error->handleError(E_NOTICE, 'This is a notice error', '/some/file', 275);
+        $this->assertEquals($content, $this->stderr->messages()[0]);
     }
 
     /**
@@ -81,11 +79,11 @@ class ConsoleErrorHandlerTest extends TestCase
     public function testHandleFatalError()
     {
         ob_start();
-        $content = '<error>Fatal Error:</error> This is a fatal error in [/some/file, line 275]';
-        $this->stderr->expects($this->once())->method('write')
-            ->with($this->stringContains($content));
+        $content = "<error>Fatal Error:</error> This is a fatal error\nIn [/some/file, line 275]\n";
 
         $this->Error->handleError(E_USER_ERROR, 'This is a fatal error', '/some/file', 275);
+        $this->assertCount(1, $this->stderr->messages());
+        $this->assertEquals($content, $this->stderr->messages()[0]);
         ob_end_clean();
     }
 
@@ -97,14 +95,15 @@ class ConsoleErrorHandlerTest extends TestCase
     public function testCakeErrors()
     {
         $exception = new MissingActionException('Missing action');
-        $message = sprintf('Missing action in [%s, line %s]', $exception->getFile(), $exception->getLine());
-        $this->stderr->expects($this->once())->method('write')
-            ->with($this->stringContains($message));
+        $message = sprintf("<error>Exception:</error> Missing action\nIn [%s, line %s]\n", $exception->getFile(), $exception->getLine());
 
         $this->Error->expects($this->once())
             ->method('_stop');
 
         $this->Error->handleException($exception);
+
+        $this->assertCount(1, $this->stderr->messages());
+        $this->assertEquals($message, $this->stderr->messages()[0]);
     }
 
     /**
@@ -116,10 +115,8 @@ class ConsoleErrorHandlerTest extends TestCase
     {
         $exception = new \InvalidArgumentException('Too many parameters.');
 
-        $this->stderr->expects($this->once())->method('write')
-            ->with($this->stringContains('Too many parameters.'));
-
         $this->Error->handleException($exception);
+        $this->assertStringContainsString('Too many parameters', $this->stderr->messages()[0]);
     }
 
     /**
@@ -129,12 +126,10 @@ class ConsoleErrorHandlerTest extends TestCase
      */
     public function testError404Exception()
     {
-        $exception = new NotFoundException('don\'t use me in cli.');
-
-        $this->stderr->expects($this->once())->method('write')
-            ->with($this->stringContains('don\'t use me in cli.'));
+        $exception = new NotFoundException("don't use me in cli.");
 
         $this->Error->handleException($exception);
+        $this->assertStringContainsString("don't use me in cli", $this->stderr->messages()[0]);
     }
 
     /**
@@ -144,12 +139,10 @@ class ConsoleErrorHandlerTest extends TestCase
      */
     public function testError500Exception()
     {
-        $exception = new InternalErrorException('don\'t use me in cli.');
-
-        $this->stderr->expects($this->once())->method('write')
-            ->with($this->stringContains('don\'t use me in cli.'));
+        $exception = new InternalErrorException("don't use me in cli.");
 
         $this->Error->handleException($exception);
+        $this->assertStringContainsString("don't use me in cli", $this->stderr->messages()[0]);
     }
 
     /**
@@ -166,13 +159,11 @@ class ConsoleErrorHandlerTest extends TestCase
         $property->setAccessible(true);
         $property->setValue($exception, '42S22');
 
-        $this->stderr->expects($this->once())->method('write')
-            ->with($this->stringContains('Non-integer exception code'));
-
         $this->Error->expects($this->once())
             ->method('_stop')
             ->with(1);
 
         $this->Error->handleException($exception);
+        $this->assertStringContainsString('Non-integer exception code', $this->stderr->messages()[0]);
     }
 }

+ 3 - 3
tests/TestCase/Error/ErrorHandlerTest.php

@@ -271,14 +271,14 @@ class ErrorHandlerTest extends TestCase
             ->method('log')
             ->with('error', $this->logicalAnd(
                 $this->stringContains('[Cake\Http\Exception\NotFoundException] Kaboom!'),
-                $this->stringContains('ErrorHandlerTest->testHandleExceptionLog')
+                $this->stringContains('vendor/phpunit/phpunit/src/Framework/TestCase.php')
             ));
 
         $this->_logger->expects($this->at(1))
             ->method('log')
             ->with('error', $this->logicalAnd(
                 $this->stringContains('[Cake\Http\Exception\NotFoundException] Kaboom!'),
-                $this->logicalNot($this->stringContains('ErrorHandlerTest->testHandleExceptionLog'))
+                $this->logicalNot($this->stringContains('vendor/phpunit/phpunit/src/Framework/TestCase.php'))
             ));
 
         $errorHandler->handleException($error);
@@ -352,7 +352,7 @@ class ErrorHandlerTest extends TestCase
             ->with('error', $this->logicalAnd(
                 $this->stringContains('[Cake\Http\Exception\NotFoundException] Kaboom!'),
                 $this->stringContains('Caused by: [Cake\Datasource\Exception\RecordNotFoundException] Previous logged'),
-                $this->stringContains('ErrorHandlerTest->testHandleExceptionLogPrevious')
+                $this->stringContains('vendor/phpunit/phpunit/src/Framework/TestCase.php')
             ));
 
         $errorHandler->handleException($error);

+ 2 - 2
tests/TestCase/Error/Middleware/ErrorHandlerMiddlewareTest.php

@@ -176,7 +176,7 @@ class ErrorHandlerMiddlewareTest extends TestCase
             ->method('log')
             ->with('error', $this->logicalAnd(
                 $this->stringContains('[Cake\Http\Exception\NotFoundException] Kaboom!'),
-                $this->stringContains('ErrorHandlerMiddlewareTest->testHandleException'),
+                $this->stringContains('vendor/phpunit/phpunit/src/Framework/TestCase.php'),
                 $this->stringContains('Request URL: /target/url'),
                 $this->stringContains('Referer URL: /other/path'),
                 $this->logicalNot(
@@ -209,7 +209,7 @@ class ErrorHandlerMiddlewareTest extends TestCase
             ->with('error', $this->logicalAnd(
                 $this->stringContains('[Cake\Http\Exception\NotFoundException] Kaboom!'),
                 $this->stringContains('Caused by: [Cake\Datasource\Exception\RecordNotFoundException] Previous logged'),
-                $this->stringContains('ErrorHandlerMiddlewareTest->testHandleExceptionLogAndTraceWithPrevious'),
+                $this->stringContains('vendor/phpunit/phpunit/src/Framework/TestCase.php'),
                 $this->stringContains('Request URL: /target/url'),
                 $this->stringContains('Referer URL: /other/path')
             ));