Skip to content

Commit 6d29db8

Browse files
committed
Implementation of optional sentry tracing with twig
1 parent d526d9d commit 6d29db8

File tree

17 files changed

+271
-2
lines changed

17 files changed

+271
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44

5+
- Add support for distributed tracing of Twig template rendering (#430)
56
- Add support for distributed tracing of SQL queries while using Doctrine DBAL (#426)
67
- Added missing `capture-soft-fails` config schema option (#417)
78
- Deprecate the `Sentry\SentryBundle\EventListener\ConsoleCommandListener` class in favor of its parent class `Sentry\SentryBundle\EventListener\ConsoleListener` (#429)

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@
5050
"symfony/monolog-bundle": "^3.4",
5151
"symfony/phpunit-bridge": "^5.0",
5252
"symfony/polyfill-php80": "^1.22",
53+
"symfony/twig-bundle": "^3.4.44||^4.4.12||^5.0.11",
5354
"symfony/yaml": "^3.4.44||^4.4.11||^5.0.11",
5455
"vimeo/psalm": "^4.3"
5556
},
5657
"suggest": {
5758
"monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler.",
58-
"doctrine/doctrine-bundle": "Allow distributed tracing of database queries using Sentry."
59+
"doctrine/doctrine-bundle": "Allow distributed tracing of database queries using Sentry.",
60+
"symfony/twig-bundle": "Allow distributed tracing of twig template rendering using Sentry."
5961
},
6062
"autoload": {
6163
"files": [

phpstan-baseline.neon

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@ parameters:
9595
count: 1
9696
path: src/Tracing/Doctrine/DBAL/TracingDriverConnection.php
9797

98+
-
99+
message: "#^Method Sentry\\\\SentryBundle\\\\Tracing\\\\Twig\\\\TwigTracingExtension\\:\\:enter\\(\\) has parameter \\$profile with no value type specified in iterable type Twig\\\\Profiler\\\\Profile\\.$#"
100+
count: 1
101+
path: src/Tracing/Twig/TwigTracingExtension.php
102+
103+
-
104+
message: "#^Method Sentry\\\\SentryBundle\\\\Tracing\\\\Twig\\\\TwigTracingExtension\\:\\:leave\\(\\) has parameter \\$profile with no value type specified in iterable type Twig\\\\Profiler\\\\Profile\\.$#"
105+
count: 1
106+
path: src/Tracing/Twig/TwigTracingExtension.php
107+
98108
-
99109
message: "#^Class Symfony\\\\Component\\\\HttpKernel\\\\Event\\\\GetResponseForExceptionEvent not found\\.$#"
100110
count: 1
@@ -219,4 +229,3 @@ parameters:
219229
message: "#^Trying to mock an undefined method convertException\\(\\) on class Sentry\\\\SentryBundle\\\\Tests\\\\Tracing\\\\Doctrine\\\\DBAL\\\\StubExceptionConverterDriverInterface\\.$#"
220230
count: 1
221231
path: tests/Tracing/Doctrine/DBAL/TracingDriverTest.php
222-

src/DependencyInjection/Configuration.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ private function addDistributedTracingSection(ArrayNodeDefinition $rootNode): vo
163163
->end()
164164
->end()
165165
->end()
166+
->arrayNode('twig')
167+
->canBeEnabled()
168+
->end()
166169
->end()
167170
->end()
168171
->end();

src/DependencyInjection/SentryExtension.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Sentry\SentryBundle\SentryBundle;
2020
use Sentry\SentryBundle\Tracing\Doctrine\DBAL\ConnectionConfigurator;
2121
use Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverMiddleware;
22+
use Sentry\SentryBundle\Tracing\Twig\TwigTracingExtension;
2223
use Sentry\Serializer\RepresentationSerializer;
2324
use Sentry\Serializer\Serializer;
2425
use Sentry\Transport\TransportFactoryInterface;
@@ -62,6 +63,7 @@ protected function loadInternal(array $mergedConfig, ContainerBuilder $container
6263
$this->registerErrorListenerConfiguration($container, $mergedConfig);
6364
$this->registerMessengerListenerConfiguration($container, $mergedConfig['messenger']);
6465
$this->registerTracingConfiguration($container, $mergedConfig['tracing']);
66+
$this->registerTracingTwigExtensionConfiguration($container, $mergedConfig['tracing']);
6567
}
6668

6769
/**
@@ -173,6 +175,18 @@ private function registerTracingConfiguration(ContainerBuilder $container, array
173175
}
174176
}
175177

178+
/**
179+
* @param array<string, mixed> $config
180+
*/
181+
private function registerTracingTwigExtensionConfiguration(ContainerBuilder $container, array $config): void
182+
{
183+
$isConfigEnabled = $this->isConfigEnabled($container, $config['twig']);
184+
185+
if (!$isConfigEnabled) {
186+
$container->removeDefinition(TwigTracingExtension::class);
187+
}
188+
}
189+
176190
/**
177191
* @param string[] $integrations
178192
* @param array<string, mixed> $config

src/Resources/config/schema/sentry-1.0.xsd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
<xsd:complexType name="tracing">
8585
<xsd:choice maxOccurs="unbounded">
8686
<xsd:element name="dbal" type="tracing-dbal" minOccurs="0" maxOccurs="1" />
87+
<xsd:element name="twig" type="tracing-twig" minOccurs="0" maxOccurs="1" />
8788
</xsd:choice>
8889
</xsd:complexType>
8990

@@ -94,4 +95,7 @@
9495

9596
<xsd:attribute name="enabled" type="xsd:boolean" />
9697
</xsd:complexType>
98+
<xsd:complexType name="tracing-twig">
99+
<xsd:attribute name="enabled" type="xsd:boolean" />
100+
</xsd:complexType>
97101
</xsd:schema>

src/Resources/config/services.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@
7373
<argument type="service" id="Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriverMiddleware" />
7474
</service>
7575

76+
<service id="Sentry\SentryBundle\Tracing\Twig\TwigTracingExtension" class="Sentry\SentryBundle\Tracing\Twig\TwigTracingExtension">
77+
<argument type="service" id="Sentry\State\HubInterface" />
78+
<tag name="twig.extension" />
79+
</service>
80+
7681
<service id="Sentry\Integration\RequestFetcherInterface" class="Sentry\SentryBundle\Integration\RequestFetcher">
7782
<argument type="service" id="Symfony\Component\HttpFoundation\RequestStack" />
7883
<argument type="service" id="Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface" on-invalid="null" />
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sentry\SentryBundle\Tracing\Twig;
6+
7+
use Sentry\State\HubInterface;
8+
use Sentry\Tracing\SpanContext;
9+
use SplObjectStorage;
10+
use Twig\Extension\AbstractExtension;
11+
use Twig\Profiler\NodeVisitor\ProfilerNodeVisitor;
12+
use Twig\Profiler\Profile;
13+
14+
final class TwigTracingExtension extends AbstractExtension
15+
{
16+
/**
17+
* @var HubInterface The current hub
18+
*/
19+
private $hub;
20+
21+
/**
22+
* @var SplObjectStorage<object, \Sentry\Tracing\Span>
23+
*/
24+
private $events;
25+
26+
/**
27+
* @param HubInterface $hub The current hub
28+
*/
29+
public function __construct(HubInterface $hub)
30+
{
31+
$this->hub = $hub;
32+
$this->events = new SplObjectStorage();
33+
}
34+
35+
public function enter(Profile $profile): void
36+
{
37+
$transaction = $this->hub->getTransaction();
38+
39+
if (null === $transaction || !$profile->isTemplate()) {
40+
return;
41+
}
42+
43+
$spanContext = new SpanContext();
44+
$spanContext->setOp('twig.template');
45+
$spanContext->setDescription($profile->getName());
46+
47+
$this->events[$profile] = $transaction->startChild($spanContext);
48+
}
49+
50+
public function leave(Profile $profile): void
51+
{
52+
if (empty($this->events[$profile]) || !$profile->isTemplate()) {
53+
return;
54+
}
55+
56+
$this->events[$profile]->finish();
57+
unset($this->events[$profile]);
58+
}
59+
60+
public function getNodeVisitors(): array
61+
{
62+
return [new ProfilerNodeVisitor(static::class)];
63+
}
64+
}

tests/DependencyInjection/ConfigurationTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ public function testProcessConfigurationWithDefaultConfiguration(): void
4141
'enabled' => false,
4242
'connections' => class_exists(DoctrineBundle::class) ? ['%doctrine.default_connection%'] : [],
4343
],
44+
'twig' => [
45+
'enabled' => false,
46+
],
4447
],
4548
];
4649

tests/DependencyInjection/Fixtures/php/full.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,8 @@
4747
'enabled' => false,
4848
'connections' => ['default'],
4949
],
50+
'twig' => [
51+
'enabled' => false,
52+
],
5053
],
5154
]);

0 commit comments

Comments
 (0)