Skip to content

Commit a4ed8a4

Browse files
committed
Add doctrine dbal tracing support that is optional to enable
1 parent ed64c02 commit a4ed8a4

File tree

5 files changed

+119
-0
lines changed

5 files changed

+119
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sentry\SentryBundle\DependencyInjection\Compiler;
6+
7+
use Sentry\SentryBundle\EventListener\Tracing\DbalListener;
8+
use Sentry\State\HubInterface;
9+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
10+
use Symfony\Component\DependencyInjection\ContainerBuilder;
11+
use Symfony\Component\DependencyInjection\Definition;
12+
13+
class ConnectDbalQueryListenerPass implements CompilerPassInterface
14+
{
15+
/**
16+
* @return void
17+
*/
18+
public function process(ContainerBuilder $container)
19+
{
20+
$config = $container->getExtensionConfig('sentry');
21+
22+
$registerDbalListener = isset($config[0]['register_dbal_listener'])
23+
? $config[0]['register_dbal_listener']
24+
: false;
25+
26+
if ($registerDbalListener && $container->hasDefinition('doctrine.dbal.logger')) {
27+
$container->setDefinition(
28+
'doctrine.dbal.logger',
29+
new Definition(DbalListener::class, [$container->getDefinition(HubInterface::class)])
30+
);
31+
}
32+
}
33+
}

src/DependencyInjection/Configuration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public function getConfigTreeBuilder(): TreeBuilder
3737
->end()
3838
->end()
3939
->booleanNode('register_error_listener')->defaultTrue()->end()
40+
->booleanNode('register_dbal_listener')->defaultFalse()->end()
4041
->arrayNode('options')
4142
->addDefaultsIfNotSet()
4243
->fixXmlConfig('integration')
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sentry\SentryBundle\EventListener\Tracing;
6+
7+
use Doctrine\DBAL\Logging\SQLLogger;
8+
use Sentry\State\HubInterface;
9+
use Sentry\Tracing\Span;
10+
use Sentry\Tracing\SpanContext;
11+
12+
/**
13+
* Getting the logger, tied into dbal seems extremely hard. Cheating the system a bit by putting it in between the
14+
* debug stack logger.
15+
*/
16+
final class DbalListener implements SQLLogger
17+
{
18+
/**
19+
* @var HubInterface The current hub
20+
*/
21+
private $hub;
22+
23+
/**
24+
* @var Span
25+
*/
26+
private $querySpan;
27+
28+
/**
29+
* @param HubInterface $hub The current hub
30+
*/
31+
public function __construct(HubInterface $hub)
32+
{
33+
$this->hub = $hub;
34+
}
35+
36+
/**
37+
* @param string $sql
38+
*/
39+
public function startQuery($sql, ?array $params = null, ?array $types = null)
40+
{
41+
$transaction = $this->hub->getTransaction();
42+
43+
if (!$transaction) {
44+
return;
45+
}
46+
47+
$spanContext = new SpanContext();
48+
$spanContext->setOp('doctrine.query');
49+
$spanContext->setDescription($sql);
50+
51+
$this->querySpan = $transaction->startChild($spanContext);
52+
}
53+
54+
public function stopQuery()
55+
{
56+
if (!$this->querySpan instanceof Span) {
57+
return;
58+
}
59+
60+
$this->querySpan->finish();
61+
}
62+
}

src/SentryBundle.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,18 @@
44

55
namespace Sentry\SentryBundle;
66

7+
use Sentry\SentryBundle\DependencyInjection\Compiler\ConnectDbalQueryListenerPass;
8+
use Symfony\Component\DependencyInjection\ContainerBuilder;
79
use Symfony\Component\HttpKernel\Bundle\Bundle;
810

911
final class SentryBundle extends Bundle
1012
{
1113
public const SDK_IDENTIFIER = 'sentry.php.symfony';
14+
15+
public function build(ContainerBuilder $container): void
16+
{
17+
parent::build($container);
18+
19+
$container->addCompilerPass(new ConnectDbalQueryListenerPass());
20+
}
1221
}

src/aliases.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@
55
use Sentry\SentryBundle\EventListener\ErrorListenerExceptionEvent;
66
use Sentry\SentryBundle\EventListener\RequestListenerControllerEvent;
77
use Sentry\SentryBundle\EventListener\RequestListenerRequestEvent;
8+
use Sentry\SentryBundle\EventListener\RequestListenerResponseEvent;
9+
use Sentry\SentryBundle\EventListener\RequestListenerTerminateEvent;
810
use Sentry\SentryBundle\EventListener\SubRequestListenerRequestEvent;
911
use Symfony\Component\HttpKernel\Event\ControllerEvent;
1012
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
1113
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
1214
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
1315
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
1416
use Symfony\Component\HttpKernel\Event\RequestEvent;
17+
use Symfony\Component\HttpKernel\Event\ResponseEvent;
18+
use Symfony\Component\HttpKernel\Event\TerminateEvent;
1519
use Symfony\Component\HttpKernel\Kernel;
1620

1721
if (version_compare(Kernel::VERSION, '4.3.0', '>=')) {
@@ -30,6 +34,16 @@ class_alias(RequestEvent::class, RequestListenerRequestEvent::class);
3034
class_alias(ControllerEvent::class, RequestListenerControllerEvent::class);
3135
}
3236

37+
if (!class_exists(RequestListenerResponseEvent::class, false)) {
38+
/** @psalm-suppress UndefinedClass */
39+
class_alias(ResponseEvent::class, RequestListenerResponseEvent::class);
40+
}
41+
42+
if (!class_exists(RequestListenerTerminateEvent::class, false)) {
43+
/** @psalm-suppress UndefinedClass */
44+
class_alias(TerminateEvent::class, RequestListenerTerminateEvent::class);
45+
}
46+
3347
if (!class_exists(SubRequestListenerRequestEvent::class, false)) {
3448
/** @psalm-suppress UndefinedClass */
3549
class_alias(RequestEvent::class, SubRequestListenerRequestEvent::class);

0 commit comments

Comments
 (0)