diff --git a/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php index 93bf496121..d8d207971f 100644 --- a/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php @@ -57,6 +57,21 @@ public function on404(ExceptionEvent $event) { $this->logger->get('page not found')->warning('@uri', ['@uri' => $request->getRequestUri()]); } + /** + * Log 4xx errors. + * + * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event + * The event to process. + */ + public function on4xx(ExceptionEvent $event) { + $exception = $event->getThrowable(); + $request = $event->getRequest(); + $this->logger->get('4xx error')->warning( + 'HTTP %status_code error: @message', + ['%status_code' => $exception->getStatusCode(), '@message' => $exception->getMessage(), '@uri' => $request->getRequestUri()] + ); + } + /** * Log not-otherwise-specified errors, including HTTP 500. * @@ -88,9 +103,18 @@ public function onException(ExceptionEvent $event) { // Treat any non-HTTP exception as if it were one, so we log it the same. if ($exception instanceof HttpExceptionInterface) { $possible_method = 'on' . $exception->getStatusCode(); + + // If the specific status code isn't handled, we try to match the status code type + // For example if there's no on406() method, this will match on4xx(). + $method_fallback = 'on' . substr($exception->getStatusCode(), 0, 1) . 'xx'; + + // Check for methods to handle this error. if (method_exists($this, $possible_method)) { $method = $possible_method; } + elseif (method_exists($this, $method_fallback)) { + $method = $method_fallback; + } } $this->$method($event); diff --git a/core/modules/dblog/tests/src/Functional/DbLogTest.php b/core/modules/dblog/tests/src/Functional/DbLogTest.php index ede663477a..6e1e68c471 100644 --- a/core/modules/dblog/tests/src/Functional/DbLogTest.php +++ b/core/modules/dblog/tests/src/Functional/DbLogTest.php @@ -881,4 +881,26 @@ public function testBacktrace() { $this->assertRaw('
');
   }
 
+  /**
+   * Tests that a 4xx exceptions are handled.
+   */
+  public function test4xxExceptionHandling() {
+    // Create a node.
+    $this->drupalCreateContentType(['type' => 'article']);
+    $node = $this->drupalCreateNode(['type' => 'article', 'title' => 'Test article']);
+    $uri = $node->toUrl('canonical', [
+      'query' => ['_format' => 'hal_json'],
+    ]);
+
+    $this->drupalGet($uri);
+    $php = Database::getConnection()->query("SELECT * FROM {watchdog} WHERE type='php'")->fetchAll();
+    $fxx = Database::getConnection()->query("SELECT * FROM {watchdog} WHERE type='4xx error'")->fetchAll();
+    $this->assertCount(0, $php);
+    $this->assertCount(1, $fxx);
+
+    $watchdog_message = array_shift($fxx);
+    $formatted_message = new FormattableMarkup($watchdog_message->message, unserialize($watchdog_message->variables));
+    $this->assertEquals('HTTP 406 error: Not acceptable format: hal_json', $formatted_message->__toString());
+  }
+
 }