From 5c012fc865a51363a70ab40c785c3b953a0378c4 Mon Sep 17 00:00:00 2001 From: samandeggs Date: Mon, 22 Apr 2024 12:24:09 +1200 Subject: [PATCH] FEAT: basic implementation of traces sampling for performance monitoring --- src/Adaptor/SentryAdaptor.php | 28 ++++++++++++++++++++++++++++ src/Handler/SentryHandler.php | 5 ++++- src/Log/SentryLogger.php | 26 ++++++++++++++++++++++++-- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/Adaptor/SentryAdaptor.php b/src/Adaptor/SentryAdaptor.php index 067a2db..bc26a2f 100755 --- a/src/Adaptor/SentryAdaptor.php +++ b/src/Adaptor/SentryAdaptor.php @@ -19,6 +19,10 @@ use SilverStripe\Core\Environment as Env; use PhpTek\Sentry\Adaptor\SentrySeverity; use PhpTek\Sentry\Helper\SentryHelper; +use Sentry\Tracing\DynamicSamplingContext; +use Sentry\Tracing\TransactionContext; +use Sentry\Tracing\TransactionMetadata; +use Sentry\Tracing\TransactionSource; /** * The SentryAdaptor provides a functionality bridge between the getsentry/sentry @@ -83,6 +87,7 @@ public function setContext(string $field, $data): SentryAdaptor $scope->setUser($data); $this->context['user'] = $data; }); + break; case 'extra': $hub->configureScope(function (Scope $scope) use ($data): void { @@ -98,6 +103,10 @@ public function setContext(string $field, $data): SentryAdaptor $scope->setLevel(new Severity(SentrySeverity::process_severity($level = $data))); }); break; + case 'traces_sample_rate': + // set's the rate in which traces are sampled 1 is 100%, 0.1 is 10% etc + $options->setTracesSampleRate($data); + break; default: break; } @@ -155,6 +164,10 @@ public static function get_opts(): array $opts['release'] = $release; } + if ($traces_sample_rate = Env::getEnv('SENTRY_TRACES_SAMPLE_RATE')) { + $opts['traces_sample_rate'] = $traces_sample_rate; + } + // Env vars take precedence over YML config in array_merge() $optsConfig = Config::inst()->get(static::class, 'opts') ?? []; @@ -176,4 +189,19 @@ public static function get_opts(): array return $opts; } + public function startTransaction() + { + $hub = SentrySdk::getCurrentHub(); + $options = $hub->getClient()->getOptions(); + $rate = $options->getTracesSampleRate(); + + // create a new transaction and finish it to send the traces to sentry + $samplingContext = DynamicSamplingContext::fromOptions($options, $this->getContext()); + $source = TransactionSource::url(); + $metadata = new TransactionMetadata($rate, $samplingContext, $source); + + $transaction_context = new TransactionContext('Bong_3', null, $metadata); + $Transaction = $hub->startTransaction($transaction_context); + $Transaction->finish(); + } } diff --git a/src/Handler/SentryHandler.php b/src/Handler/SentryHandler.php index c369e34..2dc44d8 100755 --- a/src/Handler/SentryHandler.php +++ b/src/Handler/SentryHandler.php @@ -72,7 +72,10 @@ public function __construct($level = null, bool $bubble = true, array $config = $level = Level::fromName($level ?? Level::Debug->getName()); SentrySdk::setCurrentHub(new Hub($client)); - + + $trace_sample_rate = SentryAdaptor::get_opts()['traces_sample_rate'] ?? null; + $config['traces_sample_rate'] = $trace_sample_rate ?: 0.0; + $config['level'] = $level; $this->logger = SentryLogger::factory($client, $config); diff --git a/src/Log/SentryLogger.php b/src/Log/SentryLogger.php index 95f192a..59060ee 100755 --- a/src/Log/SentryLogger.php +++ b/src/Log/SentryLogger.php @@ -69,6 +69,8 @@ public static function factory(Client $client, array $config = []): SentryLogger $env = $logger->defaultEnv(); $tags = $logger->defaultTags(); $extra = $logger->defaultExtra(); + $traces_sample_rate = $logger->defaultTracesSample(); + $user = []; $level = Logger::DEBUG; @@ -78,15 +80,25 @@ public static function factory(Client $client, array $config = []): SentryLogger $extra = array_merge($extra, $config['extra'] ?? []); $user = $config['user'] ?? $user; $level = $config['level'] ?? $level; + $traces_sample_rate = $config['traces_sample_rate'] ?? $traces_sample_rate; } $adaptor = (new SentryAdaptor($client)) ->setContext('env', $env) ->setContext('tags', $tags) ->setContext('extra', $extra) - ->setContext('user', $user); + ->setContext('user', $user) + ->setContext('traces_sample_rate', $traces_sample_rate); + + + $set_adaptor = $logger->setAdaptor($adaptor); - return $logger->setAdaptor($adaptor); + // trigger the performance tracing if set + if ($traces_sample_rate) { + $set_adaptor->getAdaptor()->startTransaction(); + } + + return $set_adaptor; } /** @@ -161,6 +173,16 @@ public function defaultExtra(): array ]; } + /** + * Returns a default empty array for traces_sample_rate, as this should be blank if not set manually + * + * @return array + */ + public function defaultTracesSample(): array + { + return []; + } + /** * What sort of request is this? (A harder question to answer than you might * think: http://stackoverflow.com/questions/6275363/what-is-the-correct-terminology-for-a-non-ajax-request)