raven-8.x-2.x-dev/src/EventSubscriber/RequestSubscriber.php

src/EventSubscriber/RequestSubscriber.php
<?php

namespace Drupal\raven\EventSubscriber;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Security\TrustedCallbackInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\raven\Logger\RavenInterface;
use Drupal\raven\Tracing\TracingTrait;
use Sentry\Tracing\TransactionSource;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Initializes Raven logger so Sentry functions can be called.
 */
class RequestSubscriber implements EventSubscriberInterface, TrustedCallbackInterface {

  use TracingTrait;

  /**
   * Constructs the request subscriber.
   */
  public function __construct(
    protected ConfigFactoryInterface $configFactory,
    #[Autowire('@logger.raven')]
    protected RavenInterface $logger,
    protected TimeInterface $time,
    #[Autowire('@event_dispatcher')]
    protected EventDispatcherInterface $eventDispatcher,
    protected ContainerInterface $container,
    protected AccountInterface $currentUser,
  ) {
  }

  /**
   * Starts a transaction if performance tracing is enabled.
   */
  public function onRequest(RequestEvent $event): void {
    if (!$event->isMainRequest()) {
      return;
    }
    $config = $this->configFactory->get('raven.settings');
    if (!$this->logger->getClient()) {
      return;
    }
    $request = $event->getRequest();
    $trace = $request->headers->get('sentry-trace') ?? $request->headers->get('traceparent') ?? '';
    $baggage = $request->headers->get('baggage') ?? '';
    $transactionContext = \Sentry\continueTrace($trace, $baggage);
    if (!$config->get('request_tracing') || !$this->currentUser->hasPermission('send performance traces to sentry')) {
      return;
    }
    // This name will later be replaced with the route path, if possible.
    $transactionContext->setName($request->getMethod() . ' ' . $request->getUri())
      ->setSource(TransactionSource::url())
      ->setOrigin('auto.http.server')
      ->setOp('http.server')
      ->setData([
        'http.request.method' => $request->getMethod(),
        'http.url' => $request->getUri(),
      ]);
    $this->startTransaction($transactionContext);
  }

  /**
   * Flush logs at end of request.
   */
  public function flushLogs(TerminateEvent $event): void {
    \Sentry\logger()->flush();
  }

  /**
   * Performance tracing.
   */
  public function onTerminate(TerminateEvent $event): void {
    if (!$this->transaction) {
      return;
    }
    // Clean up the transaction name if we have a route path.
    if ($this->transaction->getMetadata()->getSource() === TransactionSource::url() && $this->container->initialized('current_route_match')) {
      if ($route = $this->container->get('current_route_match')->getRouteObject()) {
        $this->transaction->setName($event->getRequest()->getMethod() . ' ' . $route->getPath())
          ->getMetadata()->setSource(TransactionSource::route());
      }
    }
    $config = $this->configFactory->get('raven.settings');
    $statusCode = $event->getResponse()->getStatusCode();
    $this->transaction->setHttpStatus($statusCode);
    if ($statusCode === Response::HTTP_NOT_FOUND && !$config->get('404_tracing')) {
      $this->transaction->setSampled(FALSE);
    }
    $this->transaction->finish();
  }

  /**
   * Registers the methods in this class that should be listeners.
   *
   * @return mixed[]
   *   An array of event listener definitions.
   */
  public static function getSubscribedEvents(): array {
    $events[KernelEvents::REQUEST][] = ['onRequest', 222];
    $events[KernelEvents::TERMINATE][] = ['onTerminate', 222];
    $events[KernelEvents::TERMINATE][] = ['flushLogs', -222];
    return $events;
  }

  /**
   * {@inheritdoc}
   */
  public static function trustedCallbacks() {
    return ['getBaggage', 'getTraceparent', 'getW3cTraceparent'];
  }

  /**
   * Sanitize baggage before sending as a header or rendering.
   */
  public function sanitizeBaggage(): void {
    if ($this->transaction && $this->transaction->getMetadata()->getSource() === TransactionSource::url() && $this->container->initialized('current_route_match')) {
      if ($request = $this->container->get('request_stack')->getCurrentRequest()) {
        if ($route = $this->container->get('current_route_match')->getRouteObject()) {
          $this->transaction->setName($request->getMethod() . ' ' . $route->getPath())
            ->getMetadata()->setSource(TransactionSource::route());
        }
      }
    }
  }

  /**
   * Callback for returning Sentry baggage as renderable array.
   *
   * @return string[]
   *   Renderable array.
   */
  public function getBaggage(): array {
    $this->sanitizeBaggage();
    // The baggage is URL-encoded and therefore should not need HTML encoding.
    return ['#markup' => \Sentry\getBaggage()];
  }

  /**
   * Callback for returning the Sentry trace string as renderable array.
   *
   * @return string[]
   *   Renderable array.
   */
  public function getTraceparent(): array {
    return ['#markup' => \Sentry\getTraceparent()];
  }

  /**
   * Obsolete callback returns empty string as a renderable array.
   *
   * @return string[]
   *   Renderable array.
   */
  public function getW3cTraceparent(): array {
    return ['#markup' => ''];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc