Skip to content

Commit 79837b5

Browse files
committed
Add a DBAL driver that supports distributed tracing
1 parent ebbacf3 commit 79837b5

17 files changed

+1057
-408
lines changed

composer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
"symfony/security-core": "^3.4.43||^4.4.11||^5.0.11"
3333
},
3434
"require-dev": {
35-
"doctrine/dbal": "^2.10||^3.0",
3635
"doctrine/doctrine-bundle": "^2.2",
3736
"friendsofphp/php-cs-fixer": "^2.17",
3837
"jangregor/phpstan-prophecy": "^0.8",

src/DependencyInjection/Compiler/DbalSqlTracingLoggerPass.php

Lines changed: 0 additions & 96 deletions
This file was deleted.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sentry\SentryBundle\DependencyInjection\Compiler;
6+
7+
use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverMiddleware;
8+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
9+
use Symfony\Component\DependencyInjection\ContainerBuilder;
10+
use Symfony\Component\DependencyInjection\Definition;
11+
use Symfony\Component\DependencyInjection\Reference;
12+
13+
final class DbalTracingDriverPass implements CompilerPassInterface
14+
{
15+
/**
16+
* {@inheritdoc}
17+
*/
18+
public function process(ContainerBuilder $container): void
19+
{
20+
if (!$container->hasParameter('doctrine.connections')) {
21+
return;
22+
}
23+
24+
/** @var string[] $connections */
25+
$connections = $container->getParameter('doctrine.connections');
26+
27+
/** @var string[] $connectionsToTrace */
28+
$connectionsToTrace = $container->getParameter('sentry.tracing.dbal.connections');
29+
30+
foreach ($connectionsToTrace as $connectionName) {
31+
if (!\in_array(sprintf('doctrine.dbal.%s_connection', $connectionName), $connections, true)) {
32+
continue;
33+
}
34+
35+
$configurationDefinition = $container->getDefinition(sprintf('doctrine.dbal.%s_connection.configuration', $connectionName));
36+
$setMiddlewaresMethodCallArguments = $this->getSetMiddlewaresMethodCallArguments($configurationDefinition);
37+
$setMiddlewaresMethodCallArguments[0] = array_merge($setMiddlewaresMethodCallArguments[0] ?? [], [new Reference(TracingDriverMiddleware::class)]);
38+
39+
$configurationDefinition
40+
->removeMethodCall('setMiddlewares')
41+
->addMethodCall('setMiddlewares', $setMiddlewaresMethodCallArguments);
42+
}
43+
}
44+
45+
/**
46+
* @return mixed[]
47+
*/
48+
private function getSetMiddlewaresMethodCallArguments(Definition $definition): array
49+
{
50+
foreach ($definition->getMethodCalls() as $methodCall) {
51+
if ('setMiddlewares' === $methodCall[0]) {
52+
return $methodCall[1];
53+
}
54+
}
55+
56+
return [];
57+
}
58+
}

src/DependencyInjection/SentryExtension.php

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace Sentry\SentryBundle\DependencyInjection;
66

77
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
8-
use InvalidArgumentException;
98
use Jean85\PrettyVersions;
109
use LogicException;
1110
use Sentry\Client;
@@ -18,7 +17,7 @@
1817
use Sentry\SentryBundle\EventListener\ErrorListener;
1918
use Sentry\SentryBundle\EventListener\MessengerListener;
2019
use Sentry\SentryBundle\SentryBundle;
21-
use Sentry\SentryBundle\Tracing\DbalSqlTracingLogger;
20+
use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverMiddleware;
2221
use Sentry\Serializer\RepresentationSerializer;
2322
use Sentry\Serializer\Serializer;
2423
use Sentry\Transport\TransportFactoryInterface;
@@ -145,7 +144,7 @@ private function registerErrorListenerConfiguration(ContainerBuilder $container,
145144
*/
146145
private function registerMessengerListenerConfiguration(ContainerBuilder $container, array $config): void
147146
{
148-
if (!$config['enabled']) {
147+
if (!$this->isConfigEnabled($container, $config)) {
149148
$container->removeDefinition(MessengerListener::class);
150149

151150
return;
@@ -159,14 +158,16 @@ private function registerMessengerListenerConfiguration(ContainerBuilder $contai
159158
*/
160159
private function registerTracingConfiguration(ContainerBuilder $container, array $config): void
161160
{
162-
if ($this->isConfigEnabled($container, $config['dbal']) && !class_exists(DoctrineBundle::class)) {
163-
throw new LogicException('DBAL tracing support cannot be enabled as the DoctrineBundle bundle is not installed. Try running "composer require doctrine/doctrine-bundle".');
161+
$isConfigEnabled = $this->isConfigEnabled($container, $config['dbal']);
162+
163+
if ($isConfigEnabled && !class_exists(DoctrineBundle::class)) {
164+
throw new LogicException('DBAL tracing support cannot be enabled as the DoctrineBundle bundle is not installed.');
164165
}
165166

166-
$container->setParameter('sentry.tracing.dbal.connections', $config['dbal']['enabled'] ? $config['dbal']['connections'] : []);
167+
$container->setParameter('sentry.tracing.dbal.connections', $isConfigEnabled ? $config['dbal']['connections'] : []);
167168

168-
if (!$config['dbal']['enabled']) {
169-
$container->removeDefinition(DbalSqlTracingLogger::class);
169+
if (!$isConfigEnabled) {
170+
$container->removeDefinition(TracingDriverMiddleware::class);
170171
}
171172
}
172173

@@ -237,16 +238,4 @@ private function isIntegrationEnabled(string $integrationClass, array $integrati
237238

238239
return false;
239240
}
240-
241-
/**
242-
* @param array<string, mixed> $config
243-
*/
244-
protected function isConfigEnabled(ContainerBuilder $container, array $config): bool
245-
{
246-
if (!isset($config['enabled'])) {
247-
throw new InvalidArgumentException('The $config argument has no key named "enabled".');
248-
}
249-
250-
return (bool) $container->getParameterBag()->resolveValue($config['enabled']);
251-
}
252241
}

src/Resources/config/services.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
<tag name="console.command" />
6464
</service>
6565

66-
<service id="Sentry\SentryBundle\Tracing\DbalSqlTracingLogger" class="Sentry\SentryBundle\Tracing\DbalSqlTracingLogger">
66+
<service id="Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverMiddleware" class="Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverMiddleware">
6767
<argument type="service" id="Sentry\State\HubInterface" />
6868
</service>
6969

src/SentryBundle.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace Sentry\SentryBundle;
66

7-
use Sentry\SentryBundle\DependencyInjection\Compiler\DbalSqlTracingLoggerPass;
7+
use Sentry\SentryBundle\DependencyInjection\Compiler\DbalTracingDriverPass;
88
use Symfony\Component\DependencyInjection\ContainerBuilder;
99
use Symfony\Component\HttpKernel\Bundle\Bundle;
1010

@@ -16,6 +16,6 @@ public function build(ContainerBuilder $container): void
1616
{
1717
parent::build($container);
1818

19-
$container->addCompilerPass(new DbalSqlTracingLoggerPass());
19+
$container->addCompilerPass(new DbalTracingDriverPass());
2020
}
2121
}

src/Tracing/DbalSqlTracingLogger.php

Lines changed: 0 additions & 65 deletions
This file was deleted.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sentry\SentryBundle\Tracing\Doctrine\DBAL;
6+
7+
use Doctrine\DBAL\Connection;
8+
use Doctrine\DBAL\Driver\API\ExceptionConverter;
9+
use Doctrine\DBAL\Driver as DriverInterface;
10+
use Doctrine\DBAL\Platforms\AbstractPlatform;
11+
use Sentry\State\HubInterface;
12+
13+
/**
14+
* This is a simple implementation of the {@see DriverInterface} interface that
15+
* decorates an existing driver to support distributed tracing capabilities.
16+
*/
17+
final class TracingDriver implements DriverInterface
18+
{
19+
/**
20+
* @var HubInterface The current hub
21+
*/
22+
private $hub;
23+
24+
/**
25+
* @var DriverInterface The instance of the decorated driver
26+
*/
27+
private $decoratedDriver;
28+
29+
/**
30+
* Constructor.
31+
*
32+
* @param HubInterface $hub The current hub
33+
* @param DriverInterface $decoratedDriver The instance of the driver to decorate
34+
*/
35+
public function __construct(HubInterface $hub, DriverInterface $decoratedDriver)
36+
{
37+
$this->hub = $hub;
38+
$this->decoratedDriver = $decoratedDriver;
39+
}
40+
41+
/**
42+
* {@inheritdoc}
43+
*/
44+
public function connect(array $params)
45+
{
46+
return new TracingDriverConnection(
47+
$this->hub,
48+
$this->decoratedDriver->connect($params),
49+
$this->decoratedDriver->getDatabasePlatform()->getName(),
50+
$params
51+
);
52+
}
53+
54+
/**
55+
* {@inheritdoc}
56+
*/
57+
public function getDatabasePlatform()
58+
{
59+
return $this->decoratedDriver->getDatabasePlatform();
60+
}
61+
62+
/**
63+
* {@inheritdoc}
64+
*/
65+
public function getSchemaManager(Connection $conn, AbstractPlatform $platform)
66+
{
67+
return $this->decoratedDriver->getSchemaManager($conn, $platform);
68+
}
69+
70+
/**
71+
* {@inheritdoc}
72+
*/
73+
public function getExceptionConverter(): ExceptionConverter
74+
{
75+
return $this->decoratedDriver->getExceptionConverter();
76+
}
77+
}

0 commit comments

Comments
 (0)