File: D:/HostingSpaces/SBogers10/shop.komma.nl/vendor/sentry/sentry/src/Transport/HttpTransport.php
<?php
declare(strict_types=1);
namespace Sentry\Transport;
use GuzzleHttp\Promise\EachPromise;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\PromiseInterface;
use Http\Client\HttpAsyncClient as HttpAsyncClientInterface;
use Http\Message\RequestFactory as RequestFactoryInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Sentry\Dsn;
use Sentry\Event;
use Sentry\Options;
use Sentry\Util\JSON;
/**
* This transport sends the events using a syncronous HTTP client that will
* delay sending of the requests until the shutdown of the application.
*
* @author Stefano Arlandini <sarlandini@alice.it>
*/
final class HttpTransport implements TransportInterface, ClosableTransportInterface
{
/**
* @var Options The Sentry client options
*/
private $options;
/**
* @var HttpAsyncClientInterface The HTTP client
*/
private $httpClient;
/**
* @var RequestFactoryInterface The PSR-7 request factory
*/
private $requestFactory;
/**
* @var array<array<mixed>> The list of pending requests
*
* @psalm-var array<array{\Psr\Http\Message\RequestInterface, Event}>
*/
private $pendingRequests = [];
/**
* @var bool Flag indicating whether the sending of the events should be
* delayed until the shutdown of the application
*/
private $delaySendingUntilShutdown = false;
/**
* @var LoggerInterface A PSR-3 logger
*/
private $logger;
/**
* Constructor.
*
* @param Options $options The Sentry client configuration
* @param HttpAsyncClientInterface $httpClient The HTTP client
* @param RequestFactoryInterface $requestFactory The PSR-7 request factory
* @param bool $delaySendingUntilShutdown This flag controls whether to delay
* sending of the events until the shutdown
* of the application
* @param bool $triggerDeprecation Flag controlling whether to throw
* a deprecation if the transport is
* used relying on the deprecated behavior
* of delaying the sending of the events
* until the shutdown of the application
* @param LoggerInterface|null $logger An instance of a PSR-3 logger
*/
public function __construct(
Options $options,
HttpAsyncClientInterface $httpClient,
RequestFactoryInterface $requestFactory,
bool $delaySendingUntilShutdown = true,
bool $triggerDeprecation = true,
?LoggerInterface $logger = null
) {
if ($delaySendingUntilShutdown && $triggerDeprecation) {
@trigger_error(sprintf('Delaying the sending of the events using the "%s" class is deprecated since version 2.2 and will not work in 3.0.', __CLASS__), E_USER_DEPRECATED);
}
$this->options = $options;
$this->httpClient = $httpClient;
$this->requestFactory = $requestFactory;
$this->delaySendingUntilShutdown = $delaySendingUntilShutdown;
$this->logger = $logger ?? new NullLogger();
// By calling the cleanupPendingRequests function from a shutdown function
// registered inside another shutdown function we can be confident that it
// will be executed last
register_shutdown_function('register_shutdown_function', \Closure::fromCallable([$this, 'cleanupPendingRequests']));
}
/**
* Destructor. Ensures that all pending requests ends before destroying this
* object instance.
*/
public function __destruct()
{
$this->cleanupPendingRequests();
}
/**
* {@inheritdoc}
*/
public function send(Event $event): ?string
{
$dsn = $this->options->getDsn(false);
if (!$dsn instanceof Dsn) {
throw new \RuntimeException(sprintf('The DSN option must be set to use the "%s" transport.', self::class));
}
$request = $this->requestFactory->createRequest(
'POST',
$dsn->getStoreApiEndpointUrl(),
['Content-Type' => 'application/json'],
JSON::encode($event->toArray())
);
if ($this->delaySendingUntilShutdown) {
$this->pendingRequests[] = [$request, $event];
} else {
try {
$this->httpClient->sendAsyncRequest($request)->wait();
} catch (\Throwable $exception) {
$this->logger->error(
sprintf('Failed to send the event to Sentry. Reason: "%s".', $exception->getMessage()),
[
'exception' => $exception,
'event' => $event,
]
);
return null;
}
}
return (string) $event->getId(false);
}
/**
* {@inheritdoc}
*/
public function close(?int $timeout = null): PromiseInterface
{
$this->cleanupPendingRequests();
return new FulfilledPromise(true);
}
/**
* Sends the pending requests. Any error that occurs will be ignored.
*
* @deprecated since version 2.2.3, to be removed in 3.0. Even though this
* method is `private` we cannot delete it because it's used
* in some old versions of the `sentry-laravel` package using
* tricky code involving reflection and Closure binding
*/
private function cleanupPendingRequests(): void
{
$requestGenerator = function (): \Generator {
foreach ($this->pendingRequests as $key => $data) {
yield $key => $this->httpClient->sendAsyncRequest($data[0]);
}
};
try {
$eachPromise = new EachPromise($requestGenerator(), [
'concurrency' => 30,
'rejected' => function (\Throwable $exception, int $requestIndex): void {
$this->logger->error(
sprintf('Failed to send the event to Sentry. Reason: "%s".', $exception->getMessage()),
[
'exception' => $exception,
'event' => $this->pendingRequests[$requestIndex][1],
]
);
},
]);
$eachPromise->promise()->wait();
} catch (\Throwable $exception) {
$this->logger->error(
sprintf('Failed to send the event to Sentry. Reason: "%s".', $exception->getMessage()),
['exception' => $exception]
);
}
$this->pendingRequests = [];
}
}