ExceptionLoggingSubscriber.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. <?php
  2. namespace Drupal\Core\EventSubscriber;
  3. use Drupal\Core\Logger\LoggerChannelFactoryInterface;
  4. use Drupal\Core\Utility\Error;
  5. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  6. use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
  7. use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
  8. use Symfony\Component\HttpKernel\KernelEvents;
  9. /**
  10. * Log exceptions without further handling.
  11. */
  12. class ExceptionLoggingSubscriber implements EventSubscriberInterface {
  13. /**
  14. * The logger channel factory.
  15. *
  16. * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
  17. */
  18. protected $logger;
  19. /**
  20. * Constructs a new ExceptionLoggingSubscriber.
  21. *
  22. * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger
  23. * The logger channel factory.
  24. */
  25. public function __construct(LoggerChannelFactoryInterface $logger) {
  26. $this->logger = $logger;
  27. }
  28. /**
  29. * Log 403 errors.
  30. *
  31. * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
  32. * The event to process.
  33. */
  34. public function on403(GetResponseForExceptionEvent $event) {
  35. // Log the exception with the page where it happened so that admins know
  36. // why access was denied.
  37. $exception = $event->getException();
  38. $error = Error::decodeException($exception);
  39. unset($error['@backtrace_string']);
  40. $error['@uri'] = $event->getRequest()->getRequestUri();
  41. $this->logger->get('access denied')->warning('Path: @uri. %type: @message in %function (line %line of %file).', $error);
  42. }
  43. /**
  44. * Log 404 errors.
  45. *
  46. * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
  47. * The event to process.
  48. */
  49. public function on404(GetResponseForExceptionEvent $event) {
  50. $request = $event->getRequest();
  51. $this->logger->get('page not found')->warning('@uri', ['@uri' => $request->getRequestUri()]);
  52. }
  53. /**
  54. * Log not-otherwise-specified errors, including HTTP 500.
  55. *
  56. * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
  57. * The event to process.
  58. */
  59. public function onError(GetResponseForExceptionEvent $event) {
  60. $exception = $event->getException();
  61. $error = Error::decodeException($exception);
  62. $this->logger->get('php')->log($error['severity_level'], '%type: @message in %function (line %line of %file).', $error);
  63. $is_critical = !$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500;
  64. if ($is_critical) {
  65. error_log(sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine()));
  66. }
  67. }
  68. /**
  69. * Log all exceptions.
  70. *
  71. * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
  72. * The event to process.
  73. */
  74. public function onException(GetResponseForExceptionEvent $event) {
  75. $exception = $event->getException();
  76. $method = 'onError';
  77. // Treat any non-HTTP exception as if it were one, so we log it the same.
  78. if ($exception instanceof HttpExceptionInterface) {
  79. $possible_method = 'on' . $exception->getStatusCode();
  80. if (method_exists($this, $possible_method)) {
  81. $method = $possible_method;
  82. }
  83. }
  84. $this->$method($event);
  85. }
  86. /**
  87. * {@inheritdoc}
  88. */
  89. public static function getSubscribedEvents() {
  90. $events[KernelEvents::EXCEPTION][] = ['onException', 50];
  91. return $events;
  92. }
  93. }