src/EventListener/FatalErrorListener.php line 38

Open in your IDE?
  1. <?php
  2. namespace App\EventListener;
  3. use App\Entity\DailyErrorLog;
  4. use App\Service\Logger;
  5. use App\Service\Slack;
  6. use DateTime;
  7. use Doctrine\ORM\EntityManagerInterface;
  8. use Symfony\Component\Console\ConsoleEvents;
  9. use Symfony\Component\Console\Event\ConsoleErrorEvent;
  10. use Symfony\Component\Console\Event\ConsoleTerminateEvent;
  11. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  12. use Symfony\Component\HttpKernel\KernelEvents;
  13. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  14. use Symfony\Component\HttpKernel\KernelInterface;
  15. use Symfony\Contracts\EventDispatcher\Event;
  16. class FatalErrorListener implements EventSubscriberInterface
  17. {
  18. public function __construct(
  19. private EntityManagerInterface $entityManager,
  20. private Slack $slackService,
  21. private Logger $logger,
  22. )
  23. {
  24. }
  25. public static function getSubscribedEvents(): array
  26. {
  27. // Specify the event and method to be called
  28. return [
  29. KernelEvents::EXCEPTION => 'onKernelException',
  30. ConsoleEvents::ERROR => 'onConsoleError',
  31. ];
  32. }
  33. public function onKernelException(ExceptionEvent $event): void
  34. {
  35. $request = $event->getRequest();
  36. $date = new DateTime();
  37. $errorInfo = $this->getErrorInfo($event);
  38. $logContent = $errorInfo['logContent']
  39. . 'Request: ==========================================================' . PHP_EOL
  40. . 'Method: ' . $request->getMethod() . PHP_EOL
  41. . 'URI: ' . $request->getRequestUri() . PHP_EOL
  42. . 'ClientIP: ' . $request->getClientIp() . PHP_EOL
  43. . 'Host: ' . $request->getHost() . PHP_EOL
  44. . 'Query-JSON: ' . json_encode($request->query->all()) . PHP_EOL
  45. . 'Headers-JSON: ' . json_encode($request->headers->all()) . PHP_EOL
  46. . 'Body-JSON: ' . json_encode($request->request->all()) . PHP_EOL
  47. . 'EndOfError: ===============================================' . PHP_EOL;
  48. $this->writeLog($date, $logContent, $errorInfo['sendMessage']);
  49. }
  50. public function onConsoleError(ConsoleErrorEvent $event): void
  51. {
  52. $input = $event->getInput();
  53. $date = new DateTime();
  54. $errorInfo = $this->getErrorInfo($event);
  55. $logContent = $errorInfo['logContent'];
  56. $command = $event->getCommand();
  57. $logContent .= 'Command: ==========================================================' . PHP_EOL;
  58. if (null != $command) {
  59. $logContent .= 'Command Name: ' . $command->getName() . PHP_EOL
  60. . 'Options-JSON: ' . json_encode($input->getOptions()) . PHP_EOL
  61. . 'Arguments-JSON: ' . json_encode($input->getArguments()) . PHP_EOL;
  62. } else {
  63. $logContent .= 'Command not found.' . PHP_EOL;
  64. }
  65. $logContent .= 'EndOfError: ===============================================' . PHP_EOL . PHP_EOL;
  66. $this->writeLog($date, $logContent, $errorInfo['sendMessage']);
  67. }
  68. private function writeLog(DateTime $date, string $logContent, bool $sendMessage): void
  69. {
  70. $file = "error_{$date->format('d')}_" . '.log';
  71. $this->logger->writeLog($logContent, $file);
  72. if ($sendMessage) {
  73. $this->slackService->sendMessage($logContent);
  74. }
  75. }
  76. private function getErrorInfo(Event $event): array
  77. {
  78. $exception = method_exists($event, 'getError') ? $event->getError()
  79. : (method_exists($event, 'getThrowable') ? $event->getThrowable() : null);
  80. $date = new DateTime();
  81. $environment = getenv('APP_ENV');
  82. $result = [
  83. 'sendMessage' => false,
  84. 'logContent' => PHP_EOL
  85. . '================== ' . $date->format('Y-m-d H:i:s') . '======================' . PHP_EOL
  86. . "Environment: {$environment}" . PHP_EOL,
  87. ];
  88. if (null === $exception) {
  89. $result['logContent'] .= "class: " . get_class($event) . PHP_EOL
  90. . "class: " . json_encode(get_class_methods($event)) . PHP_EOL
  91. . "No error information available!" . PHP_EOL;
  92. return $result;
  93. }
  94. $result['logContent'] .= 'TimeZone: ' . date_default_timezone_get() . PHP_EOL
  95. . 'Error: ============================================================' . PHP_EOL
  96. . 'Message: ' . $exception->getMessage() . PHP_EOL
  97. . 'File: ' . $exception->getFile() . PHP_EOL
  98. . 'Line: ' . $exception->getLine() . PHP_EOL
  99. . 'Code: ' . $exception->getCode() . PHP_EOL
  100. . 'Trace-JSON: ' . json_encode($exception->getTrace()) . PHP_EOL;
  101. $result['sendMessage'] = $this->addError($exception, $date);
  102. return $result;
  103. }
  104. private function addError($exception, DateTime $dateTime): bool
  105. {
  106. $repository = $this->entityManager->getRepository(DailyErrorLog::class);
  107. $loggedError = $repository->findBy(
  108. [
  109. 'file' => $exception->getFile(),
  110. 'code' => $exception->getCode(),
  111. 'line' => $exception->getLine(),
  112. 'appear' => $dateTime,
  113. ]
  114. );
  115. if (!$loggedError) {
  116. $loggedError = new DailyErrorLog();
  117. $loggedError->setCode($exception->getCode());
  118. $loggedError->setFile($exception->getFile());
  119. $loggedError->setLine($exception->getLine());
  120. $loggedError->setAppear($dateTime);
  121. $loggedError->setMessage($exception->getMessage());
  122. $this->entityManager->persist($loggedError);
  123. $this->entityManager->flush();
  124. return true;
  125. }
  126. return false;
  127. }
  128. }