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
12 changes: 12 additions & 0 deletions src/EventListener/ErrorLoggerListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Overblog\GraphQLBundle\EventListener;

use GraphQL\Error\ClientAware;
use GraphQL\Error\UserError;
use Overblog\GraphQLBundle\Error\UserWarning;
use Overblog\GraphQLBundle\Event\ErrorFormattingEvent;
Expand Down Expand Up @@ -50,6 +51,17 @@ public function onErrorFormatting(ErrorFormattingEvent $event): void
return;
}

// A client-safe exception (e.g. ArgumentsValidationException) is a client
// fault, not an internal server error, so it must not be logged as CRITICAL.
// Handle it like a UserError: log its previous cause (if any) at ERROR.
if ($exception instanceof ClientAware && $exception->isClientSafe()) {
if ($exception->getPrevious()) {
$this->log($exception->getPrevious());
}

return;
}

$this->log($exception, LogLevel::CRITICAL);
}

Expand Down
28 changes: 28 additions & 0 deletions tests/EventListener/ErrorLoggerListenerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@
use Overblog\GraphQLBundle\Error\UserWarning;
use Overblog\GraphQLBundle\Event\ErrorFormattingEvent;
use Overblog\GraphQLBundle\EventListener\ErrorLoggerListener;
use Overblog\GraphQLBundle\Validator\Exception\ArgumentsValidationException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Component\Validator\Validation;

use function class_exists;
use function sprintf;

final class ErrorLoggerListenerTest extends TestCase
Expand Down Expand Up @@ -124,5 +128,29 @@ public static function onErrorFormattingDataProvider(): Generator
['exception' => $exception],
],
];

// The following cases exercise ArgumentsValidationException, which lives in
// the optional Symfony validator component; skip them when it is absent.
if (class_exists(Validation::class)) {
// A client-safe exception without a previous cause must NOT be logged
// (before the fix it was logged as CRITICAL). See #1193.
yield [
new Error('Wrapped ClientSafe exception without previous', null, null, [], null, new ArgumentsValidationException(new ConstraintViolationList())),
fn (TestCase $test) => $test->never(),
[fn (TestCase $test) => $test->anything()],
];

// A client-safe exception with a previous cause is logged at ERROR,
// like a UserError — not CRITICAL. See #1193.
yield [
new Error('Wrapped ClientSafe exception with previous', null, null, [], null, new ArgumentsValidationException(new ConstraintViolationList(), $exception)),
fn (TestCase $test) => $test->once(),
[
LogLevel::ERROR,
sprintf('[GraphQL] Exception: Ko![0] (caught throwable) at %s line %s.', __FILE__, $exception->getLine()),
['exception' => $exception],
],
];
}
}
}
Loading