Skip to content

Add distributed tracing support for the Symfony Cache component #477

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

Merged
merged 3 commits into from
Apr 12, 2021
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ jobs:
restore-keys: ${{ runner.os }}-${{ matrix.php }}-composer-${{ matrix.dependencies }}-

- name: Remove optional packages
run: composer remove doctrine/dbal doctrine/doctrine-bundle symfony/messenger symfony/twig-bundle --dev --no-update
run: composer remove doctrine/dbal doctrine/doctrine-bundle symfony/messenger symfony/twig-bundle symfony/cache --dev --no-update

- name: Install highest dependencies
run: composer update --no-progress --no-interaction --prefer-dist
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
- Add support for distributed tracing of Twig template rendering (#430)
- Add support for distributed tracing of SQL queries while using Doctrine DBAL (#426)
- Add support for distributed tracing when running a console command (#455)
- Added missing `capture-soft-fails` config schema option (#417)
- Add support for distributed tracing of cache pools (#)
- Deprecate the `Sentry\SentryBundle\EventListener\ConsoleCommandListener` class in favor of its parent class `Sentry\SentryBundle\EventListener\ConsoleListener` (#429)
- Lower the required version of `symfony/psr-http-message-bridge` to allow installing it on a project that uses Symfony `3.4.x` components only (#480)

Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"phpstan/phpstan-phpunit": "^0.12",
"phpunit/phpunit": "^8.5||^9.0",
"symfony/browser-kit": "^3.4.44||^4.4.20||^5.0.11",
"symfony/cache": "^3.4.44||^4.4.20||^5.0.11",
"symfony/dom-crawler": "^3.4.44||^4.4.20||^5.0.11",
"symfony/framework-bundle": "^3.4.44||^4.4.20||^5.0.11",
"symfony/messenger": "^4.4.20||^5.0.11",
Expand All @@ -57,7 +58,8 @@
"suggest": {
"monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler.",
"doctrine/doctrine-bundle": "Allow distributed tracing of database queries using Sentry.",
"symfony/twig-bundle": "Allow distributed tracing of Twig template rendering using Sentry."
"symfony/twig-bundle": "Allow distributed tracing of Twig template rendering using Sentry.",
"symfony/cache": "Allow distributed tracing of cache pools using Sentry."
},
"autoload": {
"files": [
Expand Down
11 changes: 9 additions & 2 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="4.6.1@e93e532e4eaad6d68c4d7b606853800eaceccc72">
<files psalm-version="4.7.0@d4377c0baf3ffbf0b1ec6998e8d1be2a40971005">
<file src="src/EventListener/ConsoleCommandListener.php">
<InvalidExtendClass occurrences="1">
<code>ConsoleListener</code>
</InvalidExtendClass>
<MethodSignatureMismatch occurrences="1"/>
<MethodSignatureMismatch occurrences="1">
<code>public function __construct(HubInterface $hub, bool $captureErrors = true)</code>
</MethodSignatureMismatch>
</file>
<file src="src/Tracing/Cache/TraceableCacheAdapterTrait.php">
<InvalidReturnType occurrences="1">
<code>getItems</code>
</InvalidReturnType>
</file>
</files>
43 changes: 43 additions & 0 deletions src/DependencyInjection/Compiler/CacheTracingPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace Sentry\SentryBundle\DependencyInjection\Compiler;

use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

final class CacheTracingPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container): void
{
if (!$container->getParameter('sentry.tracing.cache.enabled')) {
return;
}

foreach ($container->findTaggedServiceIds('cache.pool') as $serviceId => $tags) {
$cachePoolDefinition = $container->getDefinition($serviceId);

if ($cachePoolDefinition->isAbstract()) {
continue;
}

if (is_subclass_of($cachePoolDefinition->getClass(), TagAwareAdapterInterface::class)) {
$traceableCachePoolDefinition = new ChildDefinition('sentry.tracing.traceable_tag_aware_cache_adapter');
} else {
$traceableCachePoolDefinition = new ChildDefinition('sentry.tracing.traceable_cache_adapter');
}

$traceableCachePoolDefinition->setDecoratedService($serviceId);
$traceableCachePoolDefinition->replaceArgument(1, new Reference($serviceId . '.traceable.inner'));

$container->setDefinition($serviceId . '.traceable', $traceableCachePoolDefinition);
}
}
}
4 changes: 4 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Contracts\Cache\CacheInterface;

final class Configuration implements ConfigurationInterface
{
Expand Down Expand Up @@ -163,6 +164,9 @@ private function addDistributedTracingSection(ArrayNodeDefinition $rootNode): vo
->arrayNode('twig')
->{class_exists(TwigBundle::class) ? 'canBeDisabled' : 'canBeEnabled'}()
->end()
->arrayNode('cache')
->{interface_exists(CacheInterface::class) ? 'canBeDisabled' : 'canBeEnabled'}()
->end()
->end()
->end()
->end();
Expand Down
17 changes: 17 additions & 0 deletions src/DependencyInjection/SentryExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\ErrorHandler\Error\FatalError;
use Symfony\Component\HttpKernel\DependencyInjection\ConfigurableExtension;
use Symfony\Contracts\Cache\CacheInterface;

final class SentryExtension extends ConfigurableExtension
{
Expand Down Expand Up @@ -68,6 +69,7 @@ protected function loadInternal(array $mergedConfig, ContainerBuilder $container
$this->registerTracingConfiguration($container, $mergedConfig['tracing']);
$this->registerDbalTracingConfiguration($container, $mergedConfig['tracing']);
$this->registerTwigTracingConfiguration($container, $mergedConfig['tracing']);
$this->registerCacheTracingConfiguration($container, $mergedConfig['tracing']);
}

/**
Expand Down Expand Up @@ -214,6 +216,21 @@ private function registerTwigTracingConfiguration(ContainerBuilder $container, a
}
}

/**
* @param array<string, mixed> $config
*/
private function registerCacheTracingConfiguration(ContainerBuilder $container, array $config): void
{
$isConfigEnabled = $this->isConfigEnabled($container, $config)
&& $this->isConfigEnabled($container, $config['cache']);

if ($isConfigEnabled && !interface_exists(CacheInterface::class)) {
throw new LogicException('Cache tracing support cannot be enabled because the symfony/cache Composer package is not installed.');
}

$container->setParameter('sentry.tracing.cache.enabled', $isConfigEnabled);
}

/**
* @param string[] $integrations
* @param array<string, mixed> $config
Expand Down
5 changes: 5 additions & 0 deletions src/Resources/config/schema/sentry-1.0.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
<xsd:choice maxOccurs="unbounded">
<xsd:element name="dbal" type="tracing-dbal" minOccurs="0" maxOccurs="1" />
<xsd:element name="twig" type="tracing-twig" minOccurs="0" maxOccurs="1" />
<xsd:element name="cache" type="tracing-cache" minOccurs="0" maxOccurs="1" />
</xsd:choice>

<xsd:attribute name="enabled" type="xsd:boolean" default="true"/>
Expand All @@ -101,4 +102,8 @@
<xsd:complexType name="tracing-twig">
<xsd:attribute name="enabled" type="xsd:boolean" />
</xsd:complexType>

<xsd:complexType name="tracing-cache">
<xsd:attribute name="enabled" type="xsd:boolean" />
</xsd:complexType>
</xsd:schema>
10 changes: 10 additions & 0 deletions src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@
<tag name="twig.extension" />
</service>

<service id="sentry.tracing.traceable_cache_adapter" class="Sentry\SentryBundle\Tracing\Cache\TraceableCacheAdapter" abstract="true">
<argument type="service" id="Sentry\State\HubInterface" />
<argument /> <!-- $decoratedAdapter -->
</service>

<service id="sentry.tracing.traceable_tag_aware_cache_adapter" class="Sentry\SentryBundle\Tracing\Cache\TraceableTagAwareCacheAdapter" abstract="true">
<argument type="service" id="Sentry\State\HubInterface" />
<argument /> <!-- $decoratedAdapter -->
</service>

<service id="Sentry\Integration\RequestFetcherInterface" class="Sentry\SentryBundle\Integration\RequestFetcher">
<argument type="service" id="Symfony\Component\HttpFoundation\RequestStack" />
<argument type="service" id="Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface" on-invalid="null" />
Expand Down
2 changes: 2 additions & 0 deletions src/SentryBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Sentry\SentryBundle;

use Sentry\SentryBundle\DependencyInjection\Compiler\CacheTracingPass;
use Sentry\SentryBundle\DependencyInjection\Compiler\DbalTracingPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
Expand All @@ -17,5 +18,6 @@ public function build(ContainerBuilder $container): void
parent::build($container);

$container->addCompilerPass(new DbalTracingPass());
$container->addCompilerPass(new CacheTracingPass());
}
}
33 changes: 33 additions & 0 deletions src/Tracing/Cache/TraceableCacheAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Sentry\SentryBundle\Tracing\Cache;

use Sentry\State\HubInterface;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\ResettableInterface;
use Symfony\Contracts\Cache\CacheInterface;

/**
* This implementation of a cache adapter supports the distributed tracing
* feature of Sentry.
*/
final class TraceableCacheAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface
{
/**
* @phpstan-use TraceableCacheAdapterTrait<AdapterInterface>
*/
use TraceableCacheAdapterTrait;

/**
* @param HubInterface $hub The current hub
* @param AdapterInterface $decoratedAdapter The decorated cache adapter
*/
public function __construct(HubInterface $hub, AdapterInterface $decoratedAdapter)
{
$this->hub = $hub;
$this->decoratedAdapter = $decoratedAdapter;
}
}
Loading