Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Sentry bundle breaks Symfony cache adapter #530

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

Closed
Jeroeny opened this issue Jul 6, 2021 · 10 comments
Closed

Sentry bundle breaks Symfony cache adapter #530

Jeroeny opened this issue Jul 6, 2021 · 10 comments

Comments

@Jeroeny
Copy link
Contributor

Jeroeny commented Jul 6, 2021

Environment

PHP: 8.0.8
Sentry dependencies installed via composer 2.1.3:

  • sentry/sdk 3.1.0
  • sentry/sentry 3.3.1
  • sentry/sentry-symfony 4.1.4

Steps to Reproduce

  1. Install symfony/cache 5.3.* (haven't checked other major/minor versions, but I expect the same behaviour in other supported versions) and doctrine/dbal 3.1.1
  2. Configure a doctrine connection in cache/packages/{env}/doctrine.php:
return static function (ContainerConfigurator $containerConfigurator): void {
    $containerConfigurator
        ->extension('doctrine', [
            'dbal' => [
                'default_connection' => 'mysql',
                'connections' => [
                    'mysql' => [
                        'driver' => 'pdo_mysql',
                        'host' => env('..'),
                        'dbname' => env('..'),
                        'user' => env('..'),
                        'password' => env('..'),
                        'server_version' => param('..'),
                        'mapping_types' => ['enum' => 'string'],
                    ],
                ]
            ]
        ]);
  1. Configure a cache adapter in cache/packages/{env}/cache.php:
return static function (ContainerConfigurator $containerConfigurator): void {
    $containerConfigurator->extension('framework', [
        'cache' => [
            'pools' => [
                'pdo' => [
                    'default_lifetime' => 86400,
                    'adapters' => [
                        [
                            'name' => 'cache.adapter.pdo',
                            'provider' => 'doctrine.dbal.mysql_connection',
                        ],
                    ],
                ],
           ]
      ]
]);
  1. Configure Sentry in cache/packages/{env}/sentry.php:
return static function (SentryConfig $configurator): void {
    $configurator
        ->dsn('..');

    $tracing = $configurator
        ->tracing()
            ->enabled(true);

    $tracing
        ->dbal()
            ->enabled(true)
            ->connections(['mysql']);

(This uses the new generated Config objects, but can be achieved with regular php or yaml config as well).

This results in:

  • A Symfony DI-service: doctrine.dbal.mysql_connection
  • Sentry wraps the Connection of the driver of this mysql connection with the TracingDriver (similar with Dbal v2)
  • A PDO Cache adapter that using this mysql connection

Expected Result

The cache adapter continues to work and Sentry is able to do its tracing on dbal queries.

Actual Result

14:22:03 WARNING   [cache] Failed to save key "xxx" of type string: Creating the cache table is currently not implemented for PDO driver "Sentry\SentryBundle\Tracing\Doctrine\DBAL\TracingDriver".

Which is thrown here: https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/Cache/Adapter/PdoAdapter.php#L156

That method expects the driver to be one of Dbal's known drivers, but instead gets the TracingDriver (set at https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/Cache/Adapter/PdoAdapter.php#L477).

Is this a known issue and/or something I can do to prevent this? If needed I can try to provide a reproducer project.

@Jean85
Copy link
Contributor

Jean85 commented Jul 6, 2021

This is possibly a duplicate of #488

@Jeroeny
Copy link
Contributor Author

Jeroeny commented Jul 7, 2021

This is possibly a duplicate of #488

The cause of the issue seems to be the same indeed (the fact that the Driver is wrapped in another class which isn't recognized). Though the solution that's being discussed there would likely not solve this part.

I wonder if the SQLLogger could be used instead of the middleware/driver wrapper. It seems it's made for both logging and tracing/timing. It's set in the same Configuration class as the middleware. And for example the Symfony profiler also uses this integration to measure the timings of queries: https://github.com/symfony/doctrine-bridge/blob/5.3/Logger/DbalLogger.php#L59.

Edit: apparently this was the original approach: #426 (comment). With

more precise tracing of different parts of Doctrine

stated as reasoning. I wonder if it's really that more precise to be worth it? Or could it be possible that both implementations could be used, determined by a configuration value in this bundle? I'd be willing to submit a PR.

@Jean85
Copy link
Contributor

Jean85 commented Jul 7, 2021

@ste93cry WDYT? The wrapping method seems to create a lot of issues.

@ste93cry
Copy link
Contributor

ste93cry commented Jul 7, 2021

The wrapping method seems to create a lot of issues.

Unfortuntely 😢 But our approach to wrapping is something considered safe and ok to do, otherwise the middleware feature of Doctrine would not have been implemented...

I wonder if the SQLLogger could be used instead of the middleware/driver wrapper

As you found out, that was our first approach. However, our is more reliable in the measurement of the query time because the implementation is closer to the native driver. Moreover, some queries like the ones to start or commit a transaction are logged in the DBAL using an hardcoded string rather than passing the real query to the logger, and although it's a nitpick I prefer the precision of our approach in logging also these queries with 100% fidelity regardless of what could happen

I'd be willing to submit a PR

I don't think it's worth it mainly because we would have to maintain two different implementations that at the end provide the same feature. I instead prefer to solve this upstream, where the real issue is. About this, I see that you already opened a PR there which is being reviewed, so I would say that there is nothing to do here

@Jean85
Copy link
Contributor

Jean85 commented Jul 7, 2021

I would also add that adding the approach through the SQLLogger is basically blocked (or made a lot harder to implement) due to doctrine/DoctrineBundle#1280

@Jean85
Copy link
Contributor

Jean85 commented Jul 7, 2021

But our approach to wrapping is something considered safe and ok to do, otherwise the middleware feature of Doctrine would not have been implemented...

Yes, I agree with this. Basically, using a plain instanceof onto the DBAL driver to check which kind of connection do you have will no longer be tenable with DBAL 3.0, with our manual wrapping we're just ahead of the curve. IMHO we could nudge other packages toward changing their approach with this reasoning.

[EDIT] I reported this upstream at symfony/symfony#42022

@Jean85
Copy link
Contributor

Jean85 commented Jul 8, 2021

Great news, this will be fixed upstream in symfony/symfony#42011 !

@Jeroeny
Copy link
Contributor Author

Jeroeny commented Jul 8, 2021

@ste93cry Thanks for the insights. I first stumbled upon the v2 implementation using Reflection. But the v3 implementation using the new Middleware functionality indeed should be usable like this. That's also why I started the PR for symfony/cache :).

I guess this issue can be closed (or wait until the Symfony PR is merged) ?

@ste93cry
Copy link
Contributor

ste93cry commented Jul 8, 2021

Let's leave this open until the bugfix is released so that if people stumble upon this they hopefully don't create a duplicate issue 😀

Tobion added a commit to symfony/symfony that referenced this issue Jul 14, 2021
…eny)

This PR was squashed before being merged into the 4.4 branch.

Discussion
----------

[Cache] Support decorated Dbal drivers in PdoAdapter

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Explanation in this PR
| License       | MIT

Doctrine v3 supports middleware for Drivers. Upon creating the Connection, `middleware->wrap(Driver): Driver` [is called](https://github.com/doctrine/dbal/blob/3.1.x/src/DriverManager.php#L210), in which the middleware can wrap/decorate the Driver class. So that it can perform tracing [for example](https://github.com/getsentry/sentry-symfony/blob/master/src/Tracing/Doctrine/DBAL/TracingDriverMiddleware.php#L37).

When this happens, the Driver class inside the Connection is no longer one of Doctrine's well known Driver classes. The `PdoAdapter ` uses this class to determine the database platform. Which breaks once the Driver is decorated and no longer one of the classes [listed](https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/Cache/Adapter/PdoAdapter.php#L452) in the `PdoAdapter`.

Since Dbal exposes this middleware as a feature, I think it would be nice for the `PdoAdapter` to support this.

To solve this, the `getDatabasePlatform` can be used. This returns a `Doctrine\DBAL\Platforms\AbstractPlatform` which defines the abstract method `getName`. This returns a value very similar to the list in the `PdoAdapter`. The names don't match exactly, so therefor a small mapping is done to get right the name used in the adapter. As far as a I know, there'd be no other implications with this change.

Related: getsentry/sentry-symfony#530

Commits
-------

58d74e3 [Cache] Support decorated Dbal drivers in PdoAdapter
symfony-splitter pushed a commit to symfony/cache that referenced this issue Jul 14, 2021
…eny)

This PR was squashed before being merged into the 4.4 branch.

Discussion
----------

[Cache] Support decorated Dbal drivers in PdoAdapter

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Explanation in this PR
| License       | MIT

Doctrine v3 supports middleware for Drivers. Upon creating the Connection, `middleware->wrap(Driver): Driver` [is called](https://github.com/doctrine/dbal/blob/3.1.x/src/DriverManager.php#L210), in which the middleware can wrap/decorate the Driver class. So that it can perform tracing [for example](https://github.com/getsentry/sentry-symfony/blob/master/src/Tracing/Doctrine/DBAL/TracingDriverMiddleware.php#L37).

When this happens, the Driver class inside the Connection is no longer one of Doctrine's well known Driver classes. The `PdoAdapter ` uses this class to determine the database platform. Which breaks once the Driver is decorated and no longer one of the classes [listed](https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/Cache/Adapter/PdoAdapter.php#L452) in the `PdoAdapter`.

Since Dbal exposes this middleware as a feature, I think it would be nice for the `PdoAdapter` to support this.

To solve this, the `getDatabasePlatform` can be used. This returns a `Doctrine\DBAL\Platforms\AbstractPlatform` which defines the abstract method `getName`. This returns a value very similar to the list in the `PdoAdapter`. The names don't match exactly, so therefor a small mapping is done to get right the name used in the adapter. As far as a I know, there'd be no other implications with this change.

Related: getsentry/sentry-symfony#530

Commits
-------

58d74e30be [Cache] Support decorated Dbal drivers in PdoAdapter
@ste93cry
Copy link
Contributor

I'm closing this because the patched version of Symfony has finally been released 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants