-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #163 from City-of-Helsinki/UHF-9635
UHF-9635: Custom Sentry traces_sampler callback
- Loading branch information
Showing
6 changed files
with
239 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Drupal\helfi_api_base\EventSubscriber; | ||
|
||
use Drupal\raven\Event\OptionsAlter; | ||
use Sentry\Tracing\SamplingContext; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
|
||
/** | ||
* Overrides the Sentry traces sampler to ignore certain data. | ||
*/ | ||
final class SentryTracesSamplerSubscriber implements EventSubscriberInterface { | ||
|
||
public const DEFAULT_SAMPLE_RATE = 0.2; | ||
|
||
/** | ||
* Checks if the trace url should be ignored. | ||
* | ||
* @param array $data | ||
* The data. | ||
* | ||
* @return bool | ||
* TRUE if url should be ignored. | ||
*/ | ||
private function ignoreTracerUrl(array $data) : bool { | ||
if (!isset($data['http.url'])) { | ||
return FALSE; | ||
} | ||
$path = parse_url($data['http.url'], PHP_URL_PATH); | ||
|
||
return str_ends_with($path, '/health'); | ||
} | ||
|
||
/** | ||
* Responds to OptionsAlter event. | ||
* | ||
* @param \Drupal\raven\Event\OptionsAlter $event | ||
* The options alter event. | ||
*/ | ||
public function setTracesSampler(OptionsAlter $event) : void { | ||
$event->options['traces_sampler'] = function (SamplingContext $context) use ($event): float { | ||
if ($context->getParentSampled()) { | ||
// If the parent transaction (for example, a JavaScript front-end) | ||
// is sampled, also sample the current transaction. | ||
return 1.0; | ||
} | ||
|
||
$data = $context->getTransactionContext()?->getData(); | ||
|
||
if ($data && $this->ignoreTracerUrl($data)) { | ||
return 0; | ||
} | ||
|
||
// Sample ~20% of transactions by default. | ||
// @see https://docs.sentry.io/platforms/php/configuration/sampling/ | ||
return $event->options['traces_sample_rate'] ?? self::DEFAULT_SAMPLE_RATE; | ||
}; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public static function getSubscribedEvents() : array { | ||
return [ | ||
'Drupal\raven\Event\OptionsAlter' => ['setTracesSampler'], | ||
]; | ||
} | ||
|
||
} |
50 changes: 50 additions & 0 deletions
50
tests/src/Kernel/EventSubscriber/SentryTracesSamplerSubscriberTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Drupal\Tests\helfi_api_base\Kernel\EventSubscriber; | ||
|
||
use Drupal\KernelTests\KernelTestBase; | ||
use Drupal\Tests\helfi_api_base\Traits\ApiTestTrait; | ||
use Sentry\SentrySdk; | ||
|
||
/** | ||
* Tests our custom Sentry 'traces_sampler' event subscriber. | ||
* | ||
* @group helfi_api_base | ||
*/ | ||
class SentryTracesSamplerSubscriberTest extends KernelTestBase { | ||
|
||
use ApiTestTrait; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
protected static $modules = [ | ||
'user', | ||
'raven', | ||
'helfi_api_base', | ||
]; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
protected function setUp(): void { | ||
parent::setUp(); | ||
|
||
$this->installConfig('helfi_api_base'); | ||
} | ||
|
||
/** | ||
* Make sure our 'traces_sampler' is actually registered. | ||
*/ | ||
public function testSamplerIsCalled() : void { | ||
$request = $this->getMockedRequest('/user/login'); | ||
$this->processRequest($request); | ||
|
||
$client = SentrySdk::getCurrentHub()->getClient(); | ||
$sampler = $client->getOptions()->getTracesSampler(); | ||
$this->assertIsCallable($sampler); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
tests/src/Unit/EventSubscriber/SentryTracesSamplerSubscriberTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Drupal\Tests\helfi_api_base\Unit\EventSubscriber; | ||
|
||
use Drupal\helfi_api_base\EventSubscriber\SentryTracesSamplerSubscriber; | ||
use Drupal\raven\Event\OptionsAlter; | ||
use Drupal\Tests\UnitTestCase; | ||
use Sentry\Tracing\SamplingContext; | ||
use Sentry\Tracing\TransactionContext; | ||
|
||
/** | ||
* Tests sentry traces sample. | ||
* | ||
* @group helfi_api_base | ||
*/ | ||
class SentryTracesSamplerSubscriberTest extends UnitTestCase { | ||
|
||
/** | ||
* Calls the sampler callback. | ||
* | ||
* @param array $options | ||
* The default options. | ||
* @param \Sentry\Tracing\SamplingContext $context | ||
* The sampling context. | ||
* | ||
* @return float | ||
* The sample rate. | ||
*/ | ||
private function callSampler(array $options, SamplingContext $context) : float { | ||
$sut = new SentryTracesSamplerSubscriber(); | ||
$sut->setTracesSampler(new OptionsAlter($options)); | ||
|
||
$this->assertIsCallable($options['traces_sampler']); | ||
|
||
return $options['traces_sampler']($context); | ||
} | ||
|
||
/** | ||
* Tests the default sample rate value. | ||
*/ | ||
public function testDefaultSamplerValue() : void { | ||
$rate = $this->callSampler([], new SamplingContext()); | ||
$this->assertEquals(SentryTracesSamplerSubscriber::DEFAULT_SAMPLE_RATE, $rate); | ||
} | ||
|
||
/** | ||
* Make sure the sample rate is inherited from parent. | ||
*/ | ||
public function testParentSampledValue() : void { | ||
$rate = $this->callSampler([], (new SamplingContext())->setParentSampled(TRUE)); | ||
$this->assertEquals(1.0, $rate); | ||
} | ||
|
||
/** | ||
* Make sure the sample rate is inherited from the setting. | ||
*/ | ||
public function testParentDefaultValue() : void { | ||
$rate = $this->callSampler(['traces_sample_rate' => 0.5], (new SamplingContext())); | ||
$this->assertEquals(0.5, $rate); | ||
} | ||
|
||
/** | ||
* Make sure nothing is done when URL context is not set. | ||
*/ | ||
public function testTracerNoUrl() : void { | ||
$transaction = new TransactionContext(); | ||
$transaction->setData(['something' => 'else']); | ||
$context = SamplingContext::getDefault($transaction); | ||
$rate = $this->callSampler([], $context); | ||
$this->assertEquals(SentryTracesSamplerSubscriber::DEFAULT_SAMPLE_RATE, $rate); | ||
} | ||
|
||
/** | ||
* Make sure the sample rate is set zero when we get a URL match. | ||
* | ||
* @dataProvider ignoreUrlData | ||
*/ | ||
public function testTracerIgnoreUrl(string $url) : void { | ||
$transaction = new TransactionContext(); | ||
$transaction->setData(['http.url' => $url]); | ||
$context = SamplingContext::getDefault($transaction); | ||
$rate = $this->callSampler([], $context); | ||
$this->assertEquals(0, $rate); | ||
} | ||
|
||
/** | ||
* Data provider. | ||
* | ||
* @return array[] | ||
* The data. | ||
*/ | ||
public function ignoreUrlData() : array { | ||
return [ | ||
['http://localhost/fi/health'], | ||
['https://localhost/health'], | ||
]; | ||
} | ||
|
||
} |