Skip to content

Commit

Permalink
improve performance tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
rommelfreddy committed Aug 8, 2024
1 parent e7dbc18 commit 2c696dd
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 143 deletions.
33 changes: 33 additions & 0 deletions Model/PerformanceTracingDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace JustBetter\Sentry\Model;

use Sentry\State\Scope;
use Sentry\Tracing\Span;

class PerformanceTracingDto
{
public function __construct(
private Scope $scope,
private ?Span $parentSpan = null,
private ?Span $span = null
) {
}

public function getScope(): Scope
{
return $this->scope;
}

public function getParentSpan(): ?Span
{
return $this->parentSpan;
}

public function getSpan(): ?Span
{
return $this->span;
}
}
22 changes: 19 additions & 3 deletions Model/SentryInteraction.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,36 @@

// phpcs:disable Magento2.Functions.DiscouragedFunction

use JustBetter\Sentry\Helper\Data;
use Throwable;

use function Sentry\captureException;
use function Sentry\init;

class SentryInteraction
{
public function initialize($config)
public function __construct(
private Data $sentryHelper
) {
}

public function initialize($config): void
{
init($config);
}

public function captureException(\Throwable $ex)
public function captureException(Throwable $ex): void
{
if (!$this->sentryHelper->shouldCaptureException($ex)) {
return;
}

ob_start();
captureException($ex);

try {
captureException($ex);
} catch (Throwable) {
}
ob_end_clean();
}
}
41 changes: 26 additions & 15 deletions Model/SentryPerformance.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\ObjectManagerInterface;
use Sentry\SentrySdk;
use Sentry\Tracing\Span;
use Sentry\Tracing\SpanContext;
use Sentry\Tracing\Transaction;
use Sentry\Tracing\TransactionContext;
use Sentry\Tracing\TransactionSource;

use Throwable;
use function Sentry\startTransaction;
use function Sentry\trace;

class SentryPerformance
{
Expand Down Expand Up @@ -68,8 +71,6 @@ public function startTransaction(AppInterface $app): void
}

$this->transaction = $transaction;

// Set the current transaction as the current span so we can retrieve it later
SentrySdk::getCurrentHub()->setSpan($transaction);
}

Expand Down Expand Up @@ -113,28 +114,38 @@ public function finishTransaction(ResponseInterface|int $statusCode): void
} elseif ($state->getAreaCode() === 'graphql') {
$this->transaction->setOp('graphql');
} else {
$this->transaction->setOp('other');
$this->transaction->setOp($state->getAreaCode());
}

// Finish the transaction, this submits the transaction and it's span to Sentry
$this->transaction->finish();
try {
// Finish the transaction, this submits the transaction and it's span to Sentry
$this->transaction->finish();
} catch (Throwable) {
}

$this->transaction = null;
}

public function addSqlQuery($sql, $startTime, $endTime = null): void
public static function traceStart(SpanContext $context): PerformanceTracingDto
{
$parentSpan = SentrySdk::getCurrentHub()->getSpan();
if (!$parentSpan) {
return;
$scope = SentrySdk::getCurrentHub()->pushScope();
$span = null;

$parentSpan = $scope->getSpan();
if ($parentSpan !== null && $parentSpan->getSampled()) {
$span = $parentSpan->startChild($context);
$scope->setSpan($span);
}

$context = new SpanContext();
$context->setOp('db.sql.query');
$context->setDescription($sql);
$context->setStartTimestamp($startTime);
$context->setEndTimestamp($endTime ?: microtime(true));
return new PerformanceTracingDto($scope, $parentSpan, $span);
}

$parentSpan->startChild($context);
public static function traceEnd(PerformanceTracingDto $context): void
{
if ($context->getSpan()) {
$context->getSpan()->finish();
$context->getScope()->setSpan($context->getParentSpan());
}
SentrySdk::getCurrentHub()->popScope();
}
}
25 changes: 8 additions & 17 deletions Plugin/GlobalExceptionCatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@

// phpcs:disable Magento2.CodeAnalysis.EmptyBlock

use JustBetter\Sentry\Helper\Data as SenteryHelper;
use JustBetter\Sentry\Helper\Data as SentryHelper;
use JustBetter\Sentry\Model\ReleaseIdentifier;
use JustBetter\Sentry\Model\SentryInteraction;
use JustBetter\Sentry\Model\SentryPerformance;
use Magento\Framework\AppInterface;
use Magento\Framework\DataObject;
use Magento\Framework\DataObjectFactory;
use Magento\Framework\Event\ManagerInterface as EventManagerInterface;
use Throwable;

class GlobalExceptionCatcher
{
public function __construct(
protected SenteryHelper $sentryHelper,
private SentryHelper $sentryHelper,
private ReleaseIdentifier $releaseIdentifier,
private SentryInteraction $sentryInteraction,
private EventManagerInterface $eventManager,
Expand Down Expand Up @@ -71,22 +72,12 @@ public function aroundLaunch(AppInterface $subject, callable $proceed)

try {
return $response = $proceed();
} catch (\Throwable $ex) {
try {
if ($this->sentryHelper->shouldCaptureException($ex)) {
$this->sentryInteraction->captureException($ex);
}
} catch (\Throwable $bigProblem) {
// do nothing if sentry fails
}

throw $ex;
} catch (Throwable $exception) {
$this->sentryInteraction->captureException($exception);

throw $exception;
} finally {
try {
$this->sentryPerformance->finishTransaction($response ?? 500);
} catch (\Throwable $bigProblem) {
// do nothing if sentry fails
}
$this->sentryPerformance->finishTransaction($response ?? 500);
}
}
}
44 changes: 0 additions & 44 deletions Plugin/LoggerProxyPlugin.php

This file was deleted.

35 changes: 35 additions & 0 deletions Plugin/Profiling/DbQueryLoggerPlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace JustBetter\Sentry\Plugin\Profiling;

use JustBetter\Sentry\Model\PerformanceTracingDto;
use JustBetter\Sentry\Model\SentryPerformance;
use Magento\Framework\DB\LoggerInterface;
use Sentry\Tracing\SpanContext;

class DbQueryLoggerPlugin
{
private ?PerformanceTracingDto $tracingDto = null;

public function beforeStartTimer(LoggerInterface $subject): void
{
$this->tracingDto = SentryPerformance::traceStart(
SpanContext::make()
->setOp('db.sql.query')
->setStartTimestamp(microtime(true))
);
}

public function beforeLogStats(LoggerInterface $subject, $type, $sql, $bind = [], $result = null): void
{
if ($this->tracingDto === null) {
return;
}

$this->tracingDto->getSpan()?->setDescription($sql);
SentryPerformance::traceEnd($this->tracingDto);
$this->tracingDto = null;
}
}
52 changes: 20 additions & 32 deletions Plugin/Profiling/EventManagerPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@

namespace JustBetter\Sentry\Plugin\Profiling;

use JustBetter\Sentry\Model\SentryPerformance;
use Magento\Framework\Event\ConfigInterface;
use Magento\Framework\Event\ManagerInterface;
use Sentry\SentrySdk;
use Sentry\Tracing\Span;
use Sentry\Tracing\SpanContext;

class EventManagerPlugin
{
private const SPAN_STORAGE_KEY = '__sentry_profiling_span';

public function __construct(
private ConfigInterface $config,
private array $excludePatterns = []
Expand All @@ -24,29 +21,33 @@ public function __construct(
'_load_after$',
'_$',
'^view_block_abstract_',
'^core_layout_render_e',
], $excludePatterns);
}

public function beforeDispatch(ManagerInterface $subject, string|null $eventName, array $data = []): array
private function _canTrace(string|null $eventName): bool
{
if ($eventName === null) {
return [$eventName, $data];
}

$parent = SentrySdk::getCurrentHub()->getSpan();
if ($parent === null) {
// can happen if no transaction has been started
return [$eventName, $data];
return false;
}

foreach ($this->excludePatterns as $excludePattern) {
if (preg_match('/'.$excludePattern.'/i', $eventName)) {
return [$eventName, $data];
return false;
}
}

if ($this->config->getObservers(mb_strtolower($eventName)) === []) {
return [$eventName, $data];
return false;
}

return true;
}

public function aroundDispatch(ManagerInterface $subject, callable $callable, string $eventName, array $data = []): mixed
{
if (!$this->_canTrace($eventName)) {
return $callable($eventName, $data);
}

$context = SpanContext::make()
Expand All @@ -56,25 +57,12 @@ public function beforeDispatch(ManagerInterface $subject, string|null $eventName
'event.name' => $eventName,
]);

$span = $parent->startChild($context);
SentrySdk::getCurrentHub()->setSpan($span);
$data[self::SPAN_STORAGE_KEY] = [$span, $parent];

return [$eventName, $data];
}

public function afterDispatch(ManagerInterface $subject, $result, string $name, array $data = []): void
{
/** @var Span[]|null $span */
$span = $data[self::SPAN_STORAGE_KEY] ?? null;
if (!is_array($span)) {
return;
}

if (isset($span[0])) {
$span[0]->finish();
$tracingDto = SentryPerformance::traceStart($context);

SentrySdk::getCurrentHub()->setSpan($span[1]);
try {
return $callable($eventName, $data);
} finally {
SentryPerformance::traceEnd($tracingDto);
}
}
}
Loading

0 comments on commit 2c696dd

Please sign in to comment.