<?php
namespace App\Component\EventSubscriber;
use App\Component\Traits\EntityManagerTrait;
use App\Component\Traits\Service\RepositoryServiceTrait;
use App\Controller\Api\AbstractApiController;
use App\Entity\Historique\Actionutilisateur\Api;
use App\Entity\User;
use Doctrine\ORM\Exception\ORMException;
use Doctrine\ORM\OptimisticLockException;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class ApiLogSubscriber extends AbstractApiController
{
use EntityManagerTrait;
use RepositoryServiceTrait;
/**
* @var LoggerInterface
*/
private LoggerInterface $logger;
/**
* @var TokenStorageInterface
*/
private TokenStorageInterface $tokenStorage;
/**
* ApiLogSubscriber constructor.
* @param LoggerInterface $logger
* @param TokenStorageInterface $tokenStorage
*/
public function __construct(LoggerInterface $logger, TokenStorageInterface $tokenStorage)
{
$this->logger = $logger;
$this->tokenStorage = $tokenStorage;
}
/**
* @param ExceptionEvent $event
* @throws ORMException
* @throws OptimisticLockException
*/
public function onKernelException(ExceptionEvent $event)
{
$this->addLog($event);
}
/**
* @param ExceptionEvent|TerminateEvent $event
* @throws ORMException
* @throws OptimisticLockException
*/
private function addLog($event)
{
$request = $event->getRequest();
// On filtre sur les appels à l'api
if (substr($request->getRequestUri(), 0, 5) != '/api/') {
return;
}
// Les appels à ne pas mettre dans les logs
if (in_array($request->getRequestUri(), [
'/api/ping/',
'/api/v2/ping',
])) {
return;
}
$content = $request->getContent();
$tmp = json_decode($content);
if (is_object($tmp) && property_exists($tmp, 'password')) {
$tmp->password = '***';
$content = json_encode($tmp);
}
$user = $this->getApiUser($event);
$uri = $request->getRequestUri();
$method = $request->getMethod();
if ($event instanceof TerminateEvent) {
$response = $event->getResponse();
/** @var Response $response */
$responseText = $response->getContent();
$status = $response->getStatusCode();
} else {
/** @var ExceptionEvent $event */
$responseText = $event->getThrowable()->getMessage().PHP_EOL.$event->getThrowable()->getTraceAsString();
$status = $event->getThrowable()->getCode();
}
if ($status == 0) {
// pas de double log en cas d'exception
return;
}
$headers = $request->headers->all();
$token = $request->headers->get('x-auth-token');
$this->addMonolog($uri, $content, $responseText, $method, $status, $headers);
$this->addSqlLog($user, $uri, $content, $method, $responseText, $status, $token);
}
/**
* @param ExceptionEvent|TerminateEvent $event
* @return User|null
*/
private function getApiUser($event): ?User
{
if ($event->getRequest()->getRequestUri() == '/api/login/' || $event->getRequest()->getRequestUri(
) == '/api/v2/login') {
$username = json_decode($event->getRequest()->getContent())->username ?? null;
if ($username) {
return $this->repositoryService->getUser()->findOneByUsername($username);
}
}
$headers = $event->getRequest()->headers;
if ($headers->get('X-Auth-Token')) {
$user = $this->repositoryService->getUser()->findOneByApiToken($headers->get('X-Auth-Token'));
if ($user instanceof User) {
return $user;
}
}
return null;
}
public function addMonolog($uri, $content, $response, $method, $status, $headers)
{
switch ($status) {
case Response::HTTP_OK:
$logType = 'info';
break;
case Response::HTTP_UNAUTHORIZED:
$logType = 'notice';
break;
default:
$logType = 'error';
}
$this->logger->$logType($method.' '.$uri, [
'status' => $status,
'request body' => $content,
'response' => json_decode($response, true),
'headers' => $headers,
]);
}
/**
* @param User|null $user
* @param $uri
* @param $content
* @param $method
* @param $response
* @param $status
* @param $token
* @throws ORMException
* @throws OptimisticLockException
*/
public function addSqlLog(?User $user, $uri, $content, $method, $response, $status, $token)
{
if (!$this->entityManager->isOpen()) {
$this->entityManager = $this->entityManager->create(
$this->entityManager->getConnection(),
$this->entityManager->getConfiguration(),
$this->entityManager->getEventManager()
);
}
$log = new Api();
$log->setUri($uri)
->setBody($content)
->setMethod($method)
->setResponse($response)
->setStatus($status)
->setToken($token);
if ($user && $user->getId()) {
$log->setUser($this->entityManager->getReference(User::class, $user->getId()));
}
$this->entityManager->persist($log);
$this->entityManager->flush();
}
/**
* @param TerminateEvent $event
* @throws ORMException
* @throws OptimisticLockException
*/
public function onKernelTerminate(TerminateEvent $event)
{
$this->addLog($event);
}
}