src/EventListener/DataDogRequestListener.php line 46

Open in your IDE?
  1. <?php
  2. namespace App\EventListener;
  3. use App\Service\DataDogService;
  4. use Psr\Log\LoggerInterface;
  5. use Symfony\Component\HttpKernel\Event\RequestEvent;
  6. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  7. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  8. use Symfony\Component\HttpKernel\HttpKernelInterface;
  9. class DataDogRequestListener
  10. {
  11. private $dataDogService;
  12. private $logger;
  13. private $spans = [];
  14. public function __construct(DataDogService $dataDogService, LoggerInterface $logger)
  15. {
  16. $this->dataDogService = $dataDogService;
  17. $this->logger = $logger;
  18. }
  19. public function onKernelRequest(RequestEvent $event): void
  20. {
  21. if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) {
  22. return;
  23. }
  24. $request = $event->getRequest();
  25. // Start main request span
  26. $span = $this->dataDogService->startSpan('http.request', [
  27. 'http.method' => $request->getMethod(),
  28. 'http.url' => $request->getRequestUri(),
  29. 'http.route' => $request->attributes->get('_route'),
  30. 'http.controller' => $request->attributes->get('_controller'),
  31. 'http.user_agent' => $request->headers->get('User-Agent'),
  32. 'http.referer' => $request->headers->get('Referer'),
  33. 'http.ip' => $request->getClientIp()
  34. ]);
  35. $this->spans['request'] = $span;
  36. }
  37. public function onKernelResponse(ResponseEvent $event): void
  38. {
  39. if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) {
  40. return;
  41. }
  42. if (!isset($this->spans['request'])) {
  43. return;
  44. }
  45. $response = $event->getResponse();
  46. $request = $event->getRequest();
  47. // End request span
  48. $span = $this->dataDogService->endSpan($this->spans['request']);
  49. $span['tags']['http.status_code'] = $response->getStatusCode();
  50. $span['tags']['http.response_size'] = strlen($response->getContent());
  51. // Send trace to DataDog
  52. $this->dataDogService->sendTrace([$span]);
  53. // Send performance metric
  54. $duration = $span['duration'] / 1000000; // Convert to seconds
  55. $route = $request->attributes->get('_route');
  56. $route = $route ? $route : 'unknown';
  57. $this->dataDogService->sendMetric('http.request.duration', $duration, [
  58. 'method:' . $request->getMethod(),
  59. 'status_code:' . $response->getStatusCode(),
  60. 'route:' . $route
  61. ]);
  62. // Log request completion
  63. $this->logger->info('Request completed', [
  64. 'method' => $request->getMethod(),
  65. 'url' => $request->getRequestUri(),
  66. 'status_code' => $response->getStatusCode(),
  67. 'duration_ms' => round($duration * 1000, 2),
  68. 'route' => $route
  69. ], ['datadog']);
  70. // Clear spans
  71. $this->spans = [];
  72. }
  73. public function onKernelException(ExceptionEvent $event): void
  74. {
  75. if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) {
  76. return;
  77. }
  78. if (!isset($this->spans['request'])) {
  79. return;
  80. }
  81. $exception = $event->getThrowable();
  82. $request = $event->getRequest();
  83. // End request span with error
  84. $span = $this->dataDogService->endSpan($this->spans['request'], $exception);
  85. $span['tags']['http.status_code'] = 500;
  86. // Send trace to DataDog
  87. $this->dataDogService->sendTrace([$span]);
  88. // Send error metric
  89. $route = $request->attributes->get('_route');
  90. $route = $route ? $route : 'unknown';
  91. $this->dataDogService->sendMetric('http.request.errors', 1, [
  92. 'method:' . $request->getMethod(),
  93. 'route:' . $route,
  94. 'exception:' . get_class($exception)
  95. ]);
  96. // Log error
  97. $this->logger->error('Request failed with exception', [
  98. 'method' => $request->getMethod(),
  99. 'url' => $request->getRequestUri(),
  100. 'exception' => get_class($exception),
  101. 'message' => $exception->getMessage(),
  102. 'file' => $exception->getFile(),
  103. 'line' => $exception->getLine(),
  104. 'route' => $route
  105. ], ['datadog']);
  106. // Clear spans
  107. $this->spans = [];
  108. }
  109. }