Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/Integration/ErrorListenerIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,13 @@ public function setupOnce(): void
static function (\ErrorException $exception): void {
$currentHub = SentrySdk::getCurrentHub();
$integration = $currentHub->getIntegration(self::class);
$client = $currentHub->getClient();

// The client bound to the current hub, if any, could not have this
// integration enabled. If this is the case, bail out
if ($integration === null || $client === null) {
if ($integration === null) {
return;
}

$client = $currentHub->getClient();

if ($exception instanceof SilencedErrorException && !$client->getOptions()->shouldCaptureSilencedErrors()) {
return;
}
Expand Down
7 changes: 3 additions & 4 deletions src/Integration/FatalErrorListenerIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,13 @@ public function setupOnce(): void
$errorHandler->addFatalErrorHandlerListener(static function (FatalErrorException $exception): void {
$currentHub = SentrySdk::getCurrentHub();
$integration = $currentHub->getIntegration(self::class);
$client = $currentHub->getClient();

// The client bound to the current hub, if any, could not have this
// integration enabled. If this is the case, bail out
if ($integration === null || $client === null) {
if ($integration === null) {
return;
}

$client = $currentHub->getClient();

if (!($client->getOptions()->getErrorTypes() & $exception->getSeverity())) {
return;
}
Expand Down
4 changes: 0 additions & 4 deletions src/Integration/FrameContextifierIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ public function setupOnce(): void
Scope::addGlobalEventProcessor(static function (Event $event): Event {
$client = SentrySdk::getCurrentHub()->getClient();

if ($client === null) {
return $event;
}

$maxContextLines = $client->getOptions()->getContextLines();
$integration = $client->getIntegration(self::class);

Expand Down
7 changes: 3 additions & 4 deletions src/Integration/RequestIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,13 @@ public function setupOnce(): void
Scope::addGlobalEventProcessor(function (Event $event): Event {
$currentHub = SentrySdk::getCurrentHub();
$integration = $currentHub->getIntegration(self::class);
$client = $currentHub->getClient();

// The client bound to the current hub, if any, could not have this
// integration enabled. If this is the case, bail out
if ($integration === null || $client === null) {
if ($integration === null) {
return $event;
}

$client = $currentHub->getClient();

$this->processEvent($event, $client->getOptions());

return $event;
Expand Down
5 changes: 0 additions & 5 deletions src/Logs/LogsAggregator.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ public function add(
$hub = SentrySdk::getCurrentHub();
$client = $hub->getClient();

// There is no need to continue if there is no client
if ($client === null) {
return;
}

$options = $client->getOptions();
$sdkLogger = $options->getLogger();

Expand Down
95 changes: 95 additions & 0 deletions src/NoOpClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

declare(strict_types=1);

namespace Sentry;

use Sentry\Integration\IntegrationInterface;
use Sentry\Serializer\RepresentationSerializer;
use Sentry\State\Scope;
use Sentry\Transport\Result;
use Sentry\Transport\ResultStatus;

/**
* This client does not perform any operations, it acts as an interface compatible layer in order to
* simply workflows where previously the client was null.
* It also holds options which helps with situations where no options were available if the client was set to `null`.
*/
class NoOpClient implements ClientInterface
{
/**
* @var array<string, mixed>
*/
private $options;

/**
* @var Options
*/
private $sentryOptions;

/**
* @var StacktraceBuilder|null
*/
private $stacktraceBuilder;

/**
* @param array<string, mixed> $options
*/
public function __construct(array $options = [])
{
$this->options = $options;
}

public function getOptions(): Options
{
if ($this->sentryOptions === null) {
$this->sentryOptions = new Options($this->options);
}

return $this->sentryOptions;
}

public function getCspReportUrl(): ?string
{
return null;
}

public function captureMessage(string $message, ?Severity $level = null, ?Scope $scope = null, ?EventHint $hint = null): ?EventId
{
return null;
}

public function captureException(\Throwable $exception, ?Scope $scope = null, ?EventHint $hint = null): ?EventId
{
return null;
}

public function captureLastError(?Scope $scope = null, ?EventHint $hint = null): ?EventId
{
return null;
}

public function captureEvent(Event $event, ?EventHint $hint = null, ?Scope $scope = null): ?EventId
{
return null;
}

public function getIntegration(string $className): ?IntegrationInterface
{
return null;
}

public function flush(?int $timeout = null): Result
{
return new Result(ResultStatus::skipped());
}

public function getStacktraceBuilder(): StacktraceBuilder
{
if ($this->stacktraceBuilder === null) {
$this->stacktraceBuilder = new StacktraceBuilder($this->getOptions(), new RepresentationSerializer($this->getOptions()));
}

return $this->stacktraceBuilder;
}
}
9 changes: 6 additions & 3 deletions src/SentrySdk.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ private function __construct()
* Initializes the SDK by creating a new hub instance each time this method
* gets called.
*/
public static function init(): HubInterface
public static function init(?ClientInterface $client = null): HubInterface
{
self::$currentHub = new Hub();
if ($client === null) {
$client = new NoOpClient();
}
self::$currentHub = new Hub($client);

return self::$currentHub;
}
Expand All @@ -44,7 +47,7 @@ public static function init(): HubInterface
public static function getCurrentHub(): HubInterface
{
if (self::$currentHub === null) {
self::$currentHub = new Hub();
self::$currentHub = new Hub(new NoOpClient());
}

return self::$currentHub;
Expand Down
67 changes: 18 additions & 49 deletions src/State/Hub.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Sentry\State;

use Psr\Log\NullLogger;
use Sentry\Attachment\Attachment;
use Sentry\Breadcrumb;
use Sentry\CheckIn;
Expand All @@ -15,6 +14,7 @@
use Sentry\EventId;
use Sentry\Integration\IntegrationInterface;
use Sentry\MonitorConfig;
use Sentry\NoOpClient;
use Sentry\Severity;
use Sentry\Tracing\SamplingContext;
use Sentry\Tracing\Span;
Expand All @@ -39,18 +39,18 @@ class Hub implements HubInterface
/**
* Hub constructor.
*
* @param ClientInterface|null $client The client bound to the hub
* @param Scope|null $scope The scope bound to the hub
* @param ClientInterface $client The client bound to the hub
* @param Scope|null $scope The scope bound to the hub
*/
public function __construct(?ClientInterface $client = null, ?Scope $scope = null)
public function __construct(ClientInterface $client, ?Scope $scope = null)
{
$this->stack[] = new Layer($client, $scope ?? new Scope());
}

/**
* {@inheritdoc}
*/
public function getClient(): ?ClientInterface
public function getClient(): ClientInterface
{
return $this->getStackTop()->getClient();
}
Expand Down Expand Up @@ -123,55 +123,31 @@ public function bindClient(ClientInterface $client): void
*/
public function captureMessage(string $message, ?Severity $level = null, ?EventHint $hint = null): ?EventId
{
$client = $this->getClient();

if ($client !== null) {
return $this->lastEventId = $client->captureMessage($message, $level, $this->getScope(), $hint);
}

return null;
return $this->lastEventId = $this->getClient()->captureMessage($message, $level, $this->getScope(), $hint);
}

/**
* {@inheritdoc}
*/
public function captureException(\Throwable $exception, ?EventHint $hint = null): ?EventId
{
$client = $this->getClient();

if ($client !== null) {
return $this->lastEventId = $client->captureException($exception, $this->getScope(), $hint);
}

return null;
return $this->lastEventId = $this->getClient()->captureException($exception, $this->getScope(), $hint);
}

/**
* {@inheritdoc}
*/
public function captureEvent(Event $event, ?EventHint $hint = null): ?EventId
{
$client = $this->getClient();

if ($client !== null) {
return $this->lastEventId = $client->captureEvent($event, $hint, $this->getScope());
}

return null;
return $this->lastEventId = $this->getClient()->captureEvent($event, $hint, $this->getScope());
}

/**
* {@inheritdoc}
*/
public function captureLastError(?EventHint $hint = null): ?EventId
{
$client = $this->getClient();

if ($client !== null) {
return $this->lastEventId = $client->captureLastError($this->getScope(), $hint);
}

return null;
return $this->lastEventId = $this->getClient()->captureLastError($this->getScope(), $hint);
}

/**
Expand All @@ -183,7 +159,7 @@ public function captureCheckIn(string $slug, CheckInStatus $status, $duration =
{
$client = $this->getClient();

if ($client === null) {
if ($client instanceof NoOpClient) {
return null;
}

Expand Down Expand Up @@ -211,7 +187,8 @@ public function addBreadcrumb(Breadcrumb $breadcrumb): bool
{
$client = $this->getClient();

if ($client === null) {
// No point in storing breadcrumbs if the client will never send them
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: NullClient misreports success on captureCheckIn

The captureCheckIn method returns a check-in ID when a NullClient is active, implying success even though no event is sent. This behavior is inconsistent with its previous return of null and with addBreadcrumb/addAttachment which correctly short-circuit for NullClient.

Fix in Cursor Fix in Web

if ($client instanceof NoOpClient) {
return false;
}

Expand All @@ -234,9 +211,8 @@ public function addBreadcrumb(Breadcrumb $breadcrumb): bool

public function addAttachment(Attachment $attachment): bool
{
$client = $this->getClient();

if ($client === null) {
// No point in storing attachments if the client will never send them
if ($this->getClient() instanceof NoOpClient) {
return false;
}

Expand All @@ -250,13 +226,7 @@ public function addAttachment(Attachment $attachment): bool
*/
public function getIntegration(string $className): ?IntegrationInterface
{
$client = $this->getClient();

if ($client !== null) {
return $client->getIntegration($className);
}

return null;
return $this->getClient()->getIntegration($className);
}

/**
Expand All @@ -267,11 +237,10 @@ public function getIntegration(string $className): ?IntegrationInterface
public function startTransaction(TransactionContext $context, array $customSamplingContext = []): Transaction
{
$transaction = new Transaction($context, $this);
$client = $this->getClient();
$options = $client !== null ? $client->getOptions() : null;
$logger = $options !== null ? $options->getLoggerOrNullLogger() : new NullLogger();
$options = $this->getClient()->getOptions();
$logger = $options->getLoggerOrNullLogger();

if ($options === null || !$options->isTracingEnabled()) {
if (!$options->isTracingEnabled()) {
$transaction->setSampled(false);

$logger->warning(\sprintf('Transaction [%s] was started but tracing is not enabled.', (string) $transaction->getTraceId()), ['context' => $context]);
Expand Down
2 changes: 1 addition & 1 deletion src/State/HubAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static function getInstance(): self
/**
* {@inheritdoc}
*/
public function getClient(): ?ClientInterface
public function getClient(): ClientInterface
{
return SentrySdk::getCurrentHub()->getClient();
}
Expand Down
2 changes: 1 addition & 1 deletion src/State/HubInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface HubInterface
/**
* Gets the client bound to the top of the stack.
*/
public function getClient(): ?ClientInterface;
public function getClient(): ClientInterface;

/**
* Gets the ID of the last captured event.
Expand Down
Loading