Skip to content
Merged
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
6 changes: 6 additions & 0 deletions analysis-baseline.toml
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,12 @@ code = "possibly-invalid-argument"
message = 'Possible argument type mismatch for argument #1 of `Monolog\Handler\AbstractHandler::isHandling`: expected `Monolog\LogRecord`, but possibly received `Monolog\LogRecord|array<string, mixed>`.'
count = 1

[[issues]]
file = "src/Monolog/ExceptionToSentryIssueHandler.php"
code = "possibly-invalid-argument"
message = 'Possible argument type mismatch for argument #1 of `Monolog\Handler\AbstractProcessingHandler::handle`: expected `Monolog\LogRecord`, but possibly received `Monolog\LogRecord|array<string, mixed>`.'
count = 1

[[issues]]
file = "src/Monolog/Handler.php"
code = "mixed-argument"
Expand Down
23 changes: 19 additions & 4 deletions src/Monolog/ExceptionToSentryIssueHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Sentry\Monolog;

use Monolog\Handler\AbstractHandler;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Level;
use Monolog\Logger;
use Monolog\LogRecord;
Expand All @@ -15,8 +15,10 @@
/**
* This Monolog handler will collect monolog events and send them to sentry.
*/
class ExceptionToSentryIssueHandler extends AbstractHandler
class ExceptionToSentryIssueHandler extends AbstractProcessingHandler
{
use CompatibilityProcessingHandlerTrait;

/**
* @var HubInterface
*/
Expand Down Expand Up @@ -44,6 +46,21 @@ public function handle($record): bool
return false;
}

/** @phpstan-ignore argument.type */
return parent::handle($record);
}

/**
* @param array<string, mixed>|LogRecord $record
*/
protected function doWrite($record): void
{
// A processor may have removed the exception from the context
$exception = $this->getExceptionFromRecord($record);
if ($exception === null) {
return;
}

$this->hub->withScope(function (Scope $scope) use ($record, $exception): void {
$scope->setExtra('monolog.channel', $record['channel']);
$scope->setExtra('monolog.level', $record['level_name']);
Expand All @@ -63,8 +80,6 @@ public function handle($record): bool

$this->hub->captureException($exception);
});

return $this->bubble === false;
}

/**
Expand Down
37 changes: 37 additions & 0 deletions tests/Monolog/ExceptionToSentryIssueHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Monolog\Logger;
use Monolog\LogRecord;
use Monolog\Processor\PsrLogMessageProcessor;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sentry\ClientInterface;
Expand Down Expand Up @@ -97,6 +98,42 @@ public function testHandleReturnsTrueWhenBubblingDisabled(): void
$this->assertTrue($handler->handle($record));
}

public function testHandleAppliesProcessors(): void
{
$exception = new \RuntimeException('boom');

/** @var ClientInterface&MockObject $client */
$client = $this->createMock(ClientInterface::class);
$client->expects($this->once())
->method('captureException')
->with(
$this->identicalTo($exception),
$this->callback(function (Scope $scopeArg): bool {
$event = $scopeArg->applyToEvent(Event::createEvent());

$this->assertNotNull($event);
$this->assertSame('Failed to sync user john', $event->getExtra()['monolog.message']);

return true;
}),
null
);

$handler = new ExceptionToSentryIssueHandler(new Hub($client, new Scope()));
$handler->pushProcessor(new PsrLogMessageProcessor());

$handler->handle(RecordFactory::create(
'Failed to sync user {username}',
Logger::ERROR,
'channel.foo',
[
'username' => 'john',
'exception' => $exception,
],
[]
));
}

/**
* @dataProvider ignoredRecordsDataProvider
*
Expand Down
Loading