src/Component/EventSubscriber/ApiLogSubscriber.php line 199

Open in your IDE?
  1. <?php
  2. namespace App\Component\EventSubscriber;
  3. use App\Component\Traits\EntityManagerTrait;
  4. use App\Component\Traits\Service\RepositoryServiceTrait;
  5. use App\Controller\Api\AbstractApiController;
  6. use App\Entity\Historique\Actionutilisateur\Api;
  7. use App\Entity\User;
  8. use Doctrine\ORM\Exception\ORMException;
  9. use Doctrine\ORM\OptimisticLockException;
  10. use Psr\Log\LoggerInterface;
  11. use Symfony\Component\HttpFoundation\Response;
  12. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  13. use Symfony\Component\HttpKernel\Event\TerminateEvent;
  14. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  15. class ApiLogSubscriber extends AbstractApiController
  16. {
  17. use EntityManagerTrait;
  18. use RepositoryServiceTrait;
  19. /**
  20. * @var LoggerInterface
  21. */
  22. private LoggerInterface $logger;
  23. /**
  24. * @var TokenStorageInterface
  25. */
  26. private TokenStorageInterface $tokenStorage;
  27. /**
  28. * ApiLogSubscriber constructor.
  29. * @param LoggerInterface $logger
  30. * @param TokenStorageInterface $tokenStorage
  31. */
  32. public function __construct(LoggerInterface $logger, TokenStorageInterface $tokenStorage)
  33. {
  34. $this->logger = $logger;
  35. $this->tokenStorage = $tokenStorage;
  36. }
  37. /**
  38. * @param ExceptionEvent $event
  39. * @throws ORMException
  40. * @throws OptimisticLockException
  41. */
  42. public function onKernelException(ExceptionEvent $event)
  43. {
  44. $this->addLog($event);
  45. }
  46. /**
  47. * @param ExceptionEvent|TerminateEvent $event
  48. * @throws ORMException
  49. * @throws OptimisticLockException
  50. */
  51. private function addLog($event)
  52. {
  53. $request = $event->getRequest();
  54. // On filtre sur les appels à l'api
  55. if (substr($request->getRequestUri(), 0, 5) != '/api/') {
  56. return;
  57. }
  58. // Les appels à ne pas mettre dans les logs
  59. if (in_array($request->getRequestUri(), [
  60. '/api/ping/',
  61. '/api/v2/ping',
  62. ])) {
  63. return;
  64. }
  65. $content = $request->getContent();
  66. $tmp = json_decode($content);
  67. if (is_object($tmp) && property_exists($tmp, 'password')) {
  68. $tmp->password = '***';
  69. $content = json_encode($tmp);
  70. }
  71. $user = $this->getApiUser($event);
  72. $uri = $request->getRequestUri();
  73. $method = $request->getMethod();
  74. if ($event instanceof TerminateEvent) {
  75. $response = $event->getResponse();
  76. /** @var Response $response */
  77. $responseText = $response->getContent();
  78. $status = $response->getStatusCode();
  79. } else {
  80. /** @var ExceptionEvent $event */
  81. $responseText = $event->getThrowable()->getMessage().PHP_EOL.$event->getThrowable()->getTraceAsString();
  82. $status = $event->getThrowable()->getCode();
  83. }
  84. if ($status == 0) {
  85. // pas de double log en cas d'exception
  86. return;
  87. }
  88. $headers = $request->headers->all();
  89. $token = $request->headers->get('x-auth-token');
  90. $this->addMonolog($uri, $content, $responseText, $method, $status, $headers);
  91. $this->addSqlLog($user, $uri, $content, $method, $responseText, $status, $token);
  92. }
  93. /**
  94. * @param ExceptionEvent|TerminateEvent $event
  95. * @return User|null
  96. */
  97. private function getApiUser($event): ?User
  98. {
  99. if ($event->getRequest()->getRequestUri() == '/api/login/' || $event->getRequest()->getRequestUri(
  100. ) == '/api/v2/login') {
  101. $username = json_decode($event->getRequest()->getContent())->username ?? null;
  102. if ($username) {
  103. return $this->repositoryService->getUser()->findOneByUsername($username);
  104. }
  105. }
  106. $headers = $event->getRequest()->headers;
  107. if ($headers->get('X-Auth-Token')) {
  108. $user = $this->repositoryService->getUser()->findOneByApiToken($headers->get('X-Auth-Token'));
  109. if ($user instanceof User) {
  110. return $user;
  111. }
  112. }
  113. return null;
  114. }
  115. public function addMonolog($uri, $content, $response, $method, $status, $headers)
  116. {
  117. switch ($status) {
  118. case Response::HTTP_OK:
  119. $logType = 'info';
  120. break;
  121. case Response::HTTP_UNAUTHORIZED:
  122. $logType = 'notice';
  123. break;
  124. default:
  125. $logType = 'error';
  126. }
  127. $this->logger->$logType($method.' '.$uri, [
  128. 'status' => $status,
  129. 'request body' => $content,
  130. 'response' => json_decode($response, true),
  131. 'headers' => $headers,
  132. ]);
  133. }
  134. /**
  135. * @param User|null $user
  136. * @param $uri
  137. * @param $content
  138. * @param $method
  139. * @param $response
  140. * @param $status
  141. * @param $token
  142. * @throws ORMException
  143. * @throws OptimisticLockException
  144. */
  145. public function addSqlLog(?User $user, $uri, $content, $method, $response, $status, $token)
  146. {
  147. if (!$this->entityManager->isOpen()) {
  148. $this->entityManager = $this->entityManager->create(
  149. $this->entityManager->getConnection(),
  150. $this->entityManager->getConfiguration(),
  151. $this->entityManager->getEventManager()
  152. );
  153. }
  154. $log = new Api();
  155. $log->setUri($uri)
  156. ->setBody($content)
  157. ->setMethod($method)
  158. ->setResponse($response)
  159. ->setStatus($status)
  160. ->setToken($token);
  161. if ($user && $user->getId()) {
  162. $log->setUser($this->entityManager->getReference(User::class, $user->getId()));
  163. }
  164. $this->entityManager->persist($log);
  165. $this->entityManager->flush();
  166. }
  167. /**
  168. * @param TerminateEvent $event
  169. * @throws ORMException
  170. * @throws OptimisticLockException
  171. */
  172. public function onKernelTerminate(TerminateEvent $event)
  173. {
  174. $this->addLog($event);
  175. }
  176. }