Skip to content

Commit

Permalink
Respect Exception information from the log entry data
Browse files Browse the repository at this point in the history
According to PSR3,

> If an Exception object is passed in the context data, it MUST be in
the 'exception' key. Logging exceptions is a common pattern and this
allows implementors to extract a stack trace from the exception when the
log backend supports it. Implementors MUST still verify that the
'exception' key is actually an Exception before using it as such, as it
MAY contain anything.
  • Loading branch information
SilverFire authored and CookiesEater committed Jan 12, 2021
1 parent 092dc8b commit 1c5a5f2
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
language: php

php:
- 7.1
- 7.2
- 8.0

cache:
directories:
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"type": "yii2-extension",
"license": "MIT",
"require": {
"php": "^7.2",
"php": "^7.2|^8.0",
"yiisoft/yii2": "^2.0",
"sentry/sdk": "^3.0"
},
Expand Down
19 changes: 18 additions & 1 deletion src/SentryTarget.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
namespace notamedia\sentry;

use Sentry\ClientBuilder;
use Sentry\Event;
use Sentry\EventHint;
use Sentry\Integration\ErrorListenerIntegration;
use Sentry\Integration\ExceptionListenerIntegration;
use Sentry\Integration\FatalErrorListenerIntegration;
Expand Down Expand Up @@ -119,12 +121,21 @@ public function export()
$data['message'] = $text['msg'];
unset($text['msg']);
}
if (isset($text['message'])) {
$data['message'] = $text['message'];
unset($text['message']);
}

if (isset($text['tags'])) {
$data['tags'] = ArrayHelper::merge($data['tags'], $text['tags']);
unset($text['tags']);
}

if (isset($text['exception'])) {
$data['exception'] = $text['exception'];
unset($text['exception']);
}

$data['extra'] = $text;
} else {
$data['message'] = (string) $text;
Expand All @@ -149,7 +160,13 @@ public function export()
if ($text instanceof Throwable) {
\Sentry\captureException($text);
} else {
\Sentry\captureMessage($data['message'], $this->getLogLevel($level));
$event = Event::createEvent();
$event->setMessage($data['message']);
$event->setLevel($this->getLogLevel($level));

\Sentry\captureEvent($event, EventHint::fromArray(array_filter([
'exception' => $data['exception'] ?? null,
])));
}
});
}
Expand Down
77 changes: 75 additions & 2 deletions tests/unit/SentryTargetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@

namespace notamedia\sentry\tests\unit;

use Sentry\Event;
use Sentry\EventHint;
use Sentry\EventId;
use yii\log\Logger;
use ReflectionClass;
use RuntimeException;
use Sentry\SentrySdk;
use Sentry\State\Scope;
use Codeception\Test\Unit;
use Sentry\ClientInterface;
use notamedia\sentry\SentryTarget;
use ReflectionClass;
use yii\log\Logger;

/**
* Unit-tests for SentryTarget
Expand Down Expand Up @@ -35,6 +42,72 @@ public function testGetContextMessage()
$this->assertEmpty($result);
}

public function testExceptionPassing()
{
$sentryTarget = $this->getConfiguredSentryTarget();

$logData = [
'message' => 'This exception was caught, but still needs to be reported',
'exception' => new RuntimeException('Package loss detected'),
'something_extra' => ['foo' => 'bar'],
];

$messageWasSent = false;

$client = $this->createMock(ClientInterface::class);
$client->expects($this->once())
->method('captureEvent')
->willReturnCallback(function (Event $event, ?EventHint $hint = null, ?Scope $scope = null) use ($logData, &$messageWasSent): ?EventId {
$messageWasSent = true;
$this->assertSame($logData['exception'], $hint->exception);
$this->assertSame($logData['message'], $event->getMessage());

return EventId::generate();
});

SentrySdk::getCurrentHub()->bindClient($client);

$sentryTarget->collect([[$logData, Logger::LEVEL_INFO, 'application', 1481513561.197593, []]], true);
$this->assertTrue($messageWasSent);
}

public function messageDataProvider()
{
$msg = 'A message';

yield [$msg, $msg];

yield [$msg, ['msg' => $msg]];

yield [$msg, ['message' => $msg]];

yield [$msg, ['message' => $msg, 'msg' => 'Ignored']];
}

/**
* @dataProvider messageDataProvider
*/
public function testMessageConverting($expectedMessageText, $loggedMessage)
{
$sentryTarget = $this->getConfiguredSentryTarget();
$messageWasSent = false;

$client = $this->createMock(ClientInterface::class);
$client->expects($this->once())
->method('captureEvent')
->willReturnCallback(function (Event $event, ?EventHint $hint = null, ?Scope $scope = null) use ($expectedMessageText, &$messageWasSent): ?EventId {
$messageWasSent = true;
$this->assertSame($expectedMessageText, $event->getMessage());

return EventId::generate();
});

SentrySdk::getCurrentHub()->bindClient($client);

$sentryTarget->collect([[$loggedMessage, Logger::LEVEL_INFO, 'application', 1481513561.197593, []]], true);
$this->assertTrue($messageWasSent);
}

/**
* Testing method getLevelName()
* - returns level name for each logger level
Expand Down

0 comments on commit 1c5a5f2

Please sign in to comment.