Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance tracking #106

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
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
8 changes: 8 additions & 0 deletions Helper/Data.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,14 @@ public function isPhpTrackingEnabled()
return $this->scopeConfig->isSetFlag(static::XML_PATH_SRS.'enable_php_tracking');
}

/**
* @return bool
*/
public function isPerformanceTrackingEnabled()
{
return $this->scopeConfig->isSetFlag(static::XML_PATH_SRS.'enable_performance_tracking');
}

/**
* @return bool
*/
Expand Down
98 changes: 98 additions & 0 deletions Model/SentryPerformance.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

declare(strict_types=1);

namespace JustBetter\Sentry\Model;

// phpcs:disable Magento2.Functions.DiscouragedFunction

use Magento\Framework\App\Request\Http as HttpRequest;
use Magento\Framework\App\Response\Http as HttpResponse;
use Magento\Framework\App\ResponseInterface;
use Sentry\SentrySdk;
use Sentry\Tracing\SpanContext;
use Sentry\Tracing\Transaction;
use Sentry\Tracing\TransactionContext;
use Sentry\Tracing\TransactionSource;

class SentryPerformance
{
/** @var Transaction|null */
private $transaction;

/** @var \Magento\Framework\App\ResourceConnection */
private $resourceConnection;

public function __construct(\Magento\Framework\App\ResourceConnection $resourceConnection)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The $resourceConnection is not used in this file, can it be removed without issues?

{
$this->resourceConnection = $resourceConnection;
}

public function startTransaction(HttpRequest $request)
{
$requestStartTime = $request->getServer('REQUEST_TIME_FLOAT', microtime(true));

$context = TransactionContext::fromHeaders(
$request->getHeader('sentry-trace') ?: '',
$request->getHeader('baggage') ?: ''
);

$requestPath = '/'.ltrim($request->getRequestUri(), '/');

$context->setOp('http.server');
$context->setName($requestPath);
$context->setSource(TransactionSource::url());
$context->setStartTimestamp($requestStartTime);

$context->setData([
'url' => $requestPath,
'method' => strtoupper($request->getMethod()),
]);

// Start the transaction
$transaction = \Sentry\startTransaction($context);

// If this transaction is not sampled, don't set it either and stop doing work from this point on
if (!$transaction->getSampled()) {
return;
}

$this->transaction = $transaction;

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

/**
* @param ResponseInterface|Response $response
*/
public function finishTransaction(ResponseInterface $response)
{
if ($this->transaction) {
if ($response instanceof HttpResponse) {
$this->transaction->setHttpStatus($response->getStatusCode());
}

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

$this->transaction = null;
}
}

public function addSqlQuery($sql, $startTime, $endTime = null)
{
$parentSpan = SentrySdk::getCurrentHub()->getSpan();
if (!$parentSpan) {
return;
}

$context = new SpanContext();
$context->setOp('db.sql.query');
$context->setDescription($sql);
$context->setStartTimestamp($startTime);
$context->setEndTimestamp($endTime ?: microtime(true));

$parentSpan->startChild($context);
}
}
27 changes: 27 additions & 0 deletions Observer/ControllerActionPredispatchObserver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace JustBetter\Sentry\Observer;

use JustBetter\Sentry\Model\SentryPerformance;
use Magento\Framework\App\Request\Http;
use Magento\Framework\Event\ObserverInterface;

class ControllerActionPredispatchObserver implements ObserverInterface
{
/** @var SentryPerformance */
private $sentryPerformance;

/** @var Http */
private $request;

public function __construct(SentryPerformance $sentryPerformance, Http $request)
{
$this->sentryPerformance = $sentryPerformance;
$this->request = $request;
}

public function execute(\Magento\Framework\Event\Observer $observer)
{
$this->sentryPerformance->startTransaction($this->request);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might it be a good idea to add the check wether we're doing performance tracking in these places as well? To ensure no code related to performance tracking is executed when it's disabled

}
}
4 changes: 4 additions & 0 deletions Plugin/GlobalExceptionCatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ public function aroundLaunch(AppInterface $subject, callable $proceed)
$config->setEnvironment($environment);
}

if ($this->sentryHelper->isTracingEnabled() && $this->sentryHelper->isPerformanceTrackingEnabled()) {
$config->setTracesSampleRate($this->sentryHelper->getTracingSampleRate());
}

$this->eventManager->dispatch('sentry_before_init', [
'config' => $config,
]);
Expand Down
44 changes: 44 additions & 0 deletions Plugin/LoggerProxyPlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace JustBetter\Sentry\Plugin;

use JustBetter\Sentry\Model\SentryPerformance;
use Magento\Framework\DB\Logger\LoggerProxy;

/**
* Plugin to add DB Queries from the ProxyLogger to Sentry
*/
class LoggerProxyPlugin
{
/** @var SentryPerformance */
private $sentryPerformance;

/** @var float|null */
private $timer;

public function __construct(SentryPerformance $sentryPerformance)
{
$this->sentryPerformance = $sentryPerformance;
}

/**
* {@inheritdoc}
*/
public function beforeStartTimer()
{
$this->timer = microtime(true);
}

/**
* @param LoggerProxy $subject
* @param string $type
* @param string $sql
* @param array $bind
* @param \Zend_Db_Statement_Pdo|null $result
* @return void
*/
public function beforeLogStats(LoggerProxy $subject, $type, $sql, $bind = [], $result = null)
{
$this->sentryPerformance->addSqlQuery($sql, $this->timer);
}
}
35 changes: 35 additions & 0 deletions Plugin/SampleRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace JustBetter\Sentry\Plugin;

use JustBetter\Sentry\Model\SentryPerformance;
use Magento\Framework\App\Request\Http;
use Magento\Framework\App\ResponseInterface;

/**
* Plugin to sample request and send them to Sentry
*/
class SampleRequest
{
/** @var SentryPerformance */
private $sentryPerformance;

/** @var Http */
private $request;

public function __construct(SentryPerformance $sentryPerformance, Http $request)
{
$this->sentryPerformance = $sentryPerformance;
$this->request = $request;
}

/**
* Add our toolbar to the response.
*
* @param ResponseInterface $response
*/
public function beforeSendResponse(ResponseInterface $response)
{
$this->sentryPerformance->finishTransaction($response);
}
}
4 changes: 4 additions & 0 deletions etc/adminhtml/system.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
<label>Enable PHP Tracking</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id="enable_performance_tracking" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="0" showInStore="0">
<label>Enable Performance Tracking</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id="enable_script_tag" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="0" showInStore="0">
<label>Enable Javascript Tracking</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
Expand Down
1 change: 1 addition & 0 deletions etc/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<sentry>
<general>
<enable_php_tracking>1</enable_php_tracking>
<enable_performance_tracking>0</enable_performance_tracking>
<enable_script_tag>0</enable_script_tag>
<script_tag_placement>before.body.end</script_tag_placement>
<use_logrocket>0</use_logrocket>
Expand Down
18 changes: 18 additions & 0 deletions etc/frontend/di.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

<type name="Magento\Framework\App\ResponseInterface">
<plugin name="JustBetter\Sentry\Plugin\SampleRequest"
type="JustBetter\Sentry\Plugin\SampleRequest"
sortOrder="99"
/>
</type>

<type name="Magento\Framework\DB\Logger\LoggerProxy">
<plugin name="JustBetter\Sentry\Plugin\LoggerProxyPlugin"
type="JustBetter\Sentry\Plugin\LoggerProxyPlugin"
sortOrder="99"
/>
</type>

</config>
6 changes: 6 additions & 0 deletions etc/frontend/events.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="controller_action_predispatch">
<observer name="SentryPredispatch" instance="JustBetter\Sentry\Observer\ControllerActionPredispatchObserver" />
</event>
</config>