Skip to content
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

Add support for Doctrine auto-instrumentation #300

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

DominicDetta
Copy link

No description provided.

@DominicDetta DominicDetta requested a review from a team as a code owner October 3, 2024 07:05
Copy link

linux-foundation-easycla bot commented Oct 3, 2024

CLA Signed

The committers listed above are authorized under a signed CLA.

Copy link

codecov bot commented Oct 3, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 80.42%. Comparing base (65de07e) to head (fb18a17).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##               main     #300   +/-   ##
=========================================
  Coverage     80.42%   80.42%           
  Complexity     1502     1502           
=========================================
  Files           128      128           
  Lines          6176     6176           
=========================================
  Hits           4967     4967           
  Misses         1209     1209           
Flag Coverage Δ
Aws 85.55% <ø> (ø)
Context/Swoole 0.00% <ø> (ø)
Instrumentation/CakePHP 20.27% <ø> (ø)
Instrumentation/CodeIgniter 73.77% <ø> (ø)
Instrumentation/Curl 90.42% <ø> (ø)
Instrumentation/ExtAmqp 89.26% <ø> (ø)
Instrumentation/ExtRdKafka 86.23% <ø> (ø)
Instrumentation/Guzzle 69.51% <ø> (ø)
Instrumentation/HttpAsyncClient 78.31% <ø> (ø)
Instrumentation/IO 70.68% <ø> (ø)
Instrumentation/Laravel 62.68% <ø> (ø)
Instrumentation/MongoDB 74.28% <ø> (ø)
Instrumentation/MySqli 95.81% <ø> (ø)
Instrumentation/OpenAIPHP 87.31% <ø> (ø)
Instrumentation/PDO 90.15% <ø> (ø)
Instrumentation/Psr14 77.14% <ø> (ø)
Instrumentation/Psr15 89.41% <ø> (ø)
Instrumentation/Psr16 97.56% <ø> (ø)
Instrumentation/Psr18 77.77% <ø> (ø)
Instrumentation/Psr3 59.49% <ø> (ø)
Instrumentation/Psr6 97.67% <ø> (ø)
Instrumentation/Slim 86.30% <ø> (ø)
Instrumentation/Symfony 84.93% <ø> (ø)
Instrumentation/Yii 77.68% <ø> (ø)
Logs/Monolog 100.00% <ø> (ø)
Propagation/TraceResponse 100.00% <ø> (ø)
ResourceDetectors/Azure 91.66% <ø> (ø)
ResourceDetectors/Container 93.02% <ø> (ø)
Sampler/RuleBased 33.51% <ø> (ø)
Shims/OpenTracing 92.45% <ø> (ø)
Symfony 87.81% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 65de07e...fb18a17. Read the comment docs.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@brettmc
Copy link
Collaborator

brettmc commented Oct 3, 2024

@DominicDetta one more thing to add is an entry to the top-level .gitsplit.yaml. When this is merged, that'll be used to split the package into a read-only repository which we can point packagist at.
You'll also need to add an entry to .github/workflows/php.yml so that the tests will run.

@DominicDetta
Copy link
Author

@brettmc I included the Doctrine directory in the files you specified

@DominicDetta
Copy link
Author

I agreed the EasyCLA and waiting for the merge approval

@brettmc
Copy link
Collaborator

brettmc commented Oct 4, 2024

Can you also update workflows/php to exclude 7.4 from the version matrix? The php version requirement is ^8.2, but I think it would work back to 8.0 since it doesn't hook internal functions. Either way, we need to either drop the requirement back to 8.0 or exclude pre-8.2 versions from the test matrix.

@DominicDetta
Copy link
Author

it's done

@DominicDetta
Copy link
Author

In the end I integrated again the PHP 7.4 version and excluded Doctrine from the pre-8.2 versions tests

@brettmc
Copy link
Collaborator

brettmc commented Oct 4, 2024

Green build is an excellent start. I'm happy to push this out as a 0.0.1 release. Since this works against doctrine 3 (according to the composer.json), and doesn't hook any internal/extension functions, I think it would probably work in 8.0 and 8.1 as well. But, that's not a blocker to getting this out if you're happy with the PR as it is.

@DominicDetta
Copy link
Author

I'm pretty confident it works even with PHP 8.0 version.
I can confirm that the classes \Doctrine\DBAL\Driver\Connection and \Doctrine\DBAL\Driver exist even in the next major versions of doctrine. (I'm using doctrine 3 at the moment). I'm glad I was able to contribute.

Copy link
Contributor

@Nevay Nevay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hooking driver methods will cause duplicated spans if a middleware like Symfony Debug Middleware is used.
An alternative approach to avoid this problem would be to move the implementation into a middleware and use a hook to inject this middleware into every connection; see also Nevay/otel-instrumentation-doctrine-dbal.

@DominicDetta
Copy link
Author

DominicDetta commented Oct 7, 2024

@brettmc @Nevay

Hooking driver methods will cause duplicated spans if a middleware like Symfony Debug Middleware is used. An alternative approach to avoid this problem would be to move the implementation into a middleware and use a hook to inject this middleware into every connection; see also Nevay/otel-instrumentation-doctrine-dbal.

The duplicate problem is also a common problem with other auto-instrumentations. In fact, we could not use psr-15 as it generated too many spans. I wonder if I really need to fix this problem or is there a way to filter the results.
Does OpenTelemetry have a feature to configure and filter duplicated spans?

@dkarlovi
Copy link

dkarlovi commented Oct 9, 2024

Does OpenTelemetry have a feature to configure and filter duplicated spans?

AFAIK the idea is to allow the agent to do that:
https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/filterprocessor/README.md

Copy link
Contributor

@cedricziel cedricziel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My proposal is to figure out if this instrumentation should depend on the existence of PDO and then define how the two interact. My understanding is that if a PDO is used and the PDO instrumentation is active, there will be 2 nested CLIENT spans for the same interaction. - IMHO this is severely impacting the user experience.

pre: static function (\Doctrine\DBAL\Driver $driver, array $params, string $class, string $function, ?string $filename, ?int $lineno) use ($instrumentation) {
/** @psalm-suppress ArgumentTypeCoercion */
$builder = self::makeBuilder($instrumentation, 'Doctrine\DBAL\Driver::connect', $function, $class, $filename, $lineno)
->setSpanKind(SpanKind::KIND_CLIENT);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we think about the duality of PDO and dbal here? Most instrumented methods have a pendant in the PDO instrumentation i.e. - a compatible pdo driver will cause two client spans and the hierarchy will probably be

my_func (internal)
 -> connect (client) # from dbal
   -> PDO::__construct (client ) # from pdo

IMO the two should be either mutually exclusive or enrich each other. WDYT?

Copy link
Collaborator

@brettmc brettmc Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not have a way for two auto-instrumentations to cooperate like this (it's an idea that has come up before, and would be cool). So I think mutually exclusive is the best we have - or at least it's up to the user to install only one instrumentation, I don't think we need to go as far as setting them up as conflicting in composer.
Is documenting that recommendation good enough for now?

edit: a hacky approach would be to have this package check if PDO instrumentation is installed and enabled, and only apply some of its hooks (if it provides any value that PDO itself doesn't)...?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the PDO instrumentation re-write the doctrine span from CLIENT to internal or bail if it recognizes the parent is already client?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To your point - i think documenting it makes the experience worse because users then need to make a whole lot of decisions when instrumenting

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think documenting it makes the experience worse

I only meant documenting such as "use pdo or doctrine auto-instrumentation, but probably not both" - I expect users to make decisions about which auto-instrumentations to install based on their workload/stack...just installing everything available is probably too noisy.

Could the PDO instrumentation re-write the doctrine span from CLIENT to internal or bail if it recognizes the parent is already client?

I think the issue here would be that pre/post hooks operate in isolation, so there's currently no way for a post hook to know whether the pre hook created a span or just modified the active span. All the implementations we have assume that pre created and activated a span, and post just closes whichever is the active span at the time.
We have previously brainstormed whether we could manage some state between a pre and post hook, but we thought it was going to be a hard problem.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect users to make decisions about which auto-instrumentations to install based on their workload/stack...just installing everything available is probably too noisy.

I completely agree on this matter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the PDO instrumentation ... bail if it recognizes the parent is already client?

Bailing out requires storing additional data within the Context to be able to detect duplicate instrumentations, see Javas span suppression strategies:
Instrumentation span suppression behavior
SpanSuppressionStrategy.java
SpanSuppressors.java

AFAIK the idea is to allow the agent to do that

Dropping at the agent is too late as it may lead to broken traces "Dropping a span may lead to orphaned spans if the dropped span is a parent." ref.

there's currently no way for a post hook to know whether the pre hook created a span or just modified the active span

Scopes attached via Context::storage()->attach() implement ArrayAccess to allow propagating state from pre hook to post hook ref.

hook(
    null,
    'example',
    static function() use ($tracer): void {
        $context = Context::getCurrent();
        if (lcg_value() > .5 /* some suppression condition */) {
            $span = $tracer
                ->spanBuilder('example')
                ->startSpan();
            $context = $span->storeInContext($context);
        }
        $scope = Context::storage()->attach($context);
        $scope[SpanInterface::class] = $span ?? null;
    },
    static function(): void {
        if (!$scope = Context::storage()->scope()) {
            return;
        }
        $scope->detach();
        /** @var SpanInterface|null $span */
        $span = $scope[SpanInterface::class] ?? null;
        $span?->end();
    },
);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brettmc Can you post-process the spans and just remove / enrich the duplicated ones?

e.g. Is there something that runs before the exporter?

@brettmc
Copy link
Collaborator

brettmc commented Mar 3, 2025

@DominicDetta I didn't notice that you'd signed the CLA now. Let's get this merged, can you merge in main and resolve conflicts?

@DominicDetta
Copy link
Author

@brettmc I resolved the conflict, I didnt have time to put more effort in this project. I'm too busy at the moment.

@DominicDetta
Copy link
Author

@brettmc Maybe you didnt see but I merged to the main branch

Copy link
Contributor

@ChrisLightfootWild ChrisLightfootWild left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple of tidy-ups from me 👍

@@ -45,6 +45,7 @@ jobs:
'Instrumentation/Slim',
'Instrumentation/Symfony',
'Instrumentation/Yii',
'Instrumentation/Doctrine',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please can you move this into alphabetical order?

Comment on lines +71 to +72
- project: 'Instrumentation/Doctrine'
php-version: 8.1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above.

@@ -157,4 +160,4 @@ jobs:
directory: src/${{ matrix.project }}
files: ./coverage.clover
flags: ${{ matrix.project }}
verbose: false
verbose: false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert to newline EOF.

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

Successfully merging this pull request may close these issues.

8 participants