<?php
namespace App\EventSubscriber;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Security;
class RequestLoggingSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly LoggerInterface $logger,
private readonly Security $security,
) {
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 100],
KernelEvents::RESPONSE => ['onKernelResponse', -100],
];
}
public function onKernelRequest(RequestEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
$requestId = $request->headers->get('X-Request-Id');
if (!$requestId) {
$requestId = bin2hex(random_bytes(8));
}
$request->attributes->set('_request_id', $requestId);
$request->attributes->set('_request_start', microtime(true));
}
public function onKernelResponse(ResponseEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
$response = $event->getResponse();
$requestId = (string) $request->attributes->get('_request_id', '');
if ($requestId !== '') {
$response->headers->set('X-Request-Id', $requestId);
}
$start = (float) $request->attributes->get('_request_start', microtime(true));
$durationMs = (microtime(true) - $start) * 1000;
$user = $this->security->getUser();
$userId = $user && method_exists($user, 'getId') ? $user->getId() : null;
$this->logger->info('http_request', [
'request_id' => $requestId,
'method' => $request->getMethod(),
'path' => $request->getPathInfo(),
'status' => $response->getStatusCode(),
'duration_ms' => (int) round($durationMs),
'user_id' => $userId,
'ip' => $request->getClientIp(),
]);
}
}