-
Notifications
You must be signed in to change notification settings - Fork 97
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
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #300 +/- ##
=========================================
Coverage 80.42% 80.42%
Complexity 1502 1502
=========================================
Files 128 128
Lines 6176 6176
=========================================
Hits 4967 4967
Misses 1209 1209 Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
@DominicDetta one more thing to add is an entry to the top-level |
@brettmc I included the Doctrine directory in the files you specified |
I agreed the EasyCLA and waiting for the merge approval |
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. |
it's done |
In the end I integrated again the PHP 7.4 version and excluded Doctrine from the pre-8.2 versions tests |
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. |
I'm pretty confident it works even with PHP 8.0 version. |
There was a problem hiding this 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.
Co-authored-by: Tobias Bachert <[email protected]>
Co-authored-by: Tobias Bachert <[email protected]>
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. |
AFAIK the idea is to allow the agent to do that: |
There was a problem hiding this 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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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)...?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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();
},
);
There was a problem hiding this comment.
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?
@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? |
@brettmc I resolved the conflict, I didnt have time to put more effort in this project. I'm too busy at the moment. |
@brettmc Maybe you didnt see but I merged to the main branch |
There was a problem hiding this 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', |
There was a problem hiding this comment.
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?
- project: 'Instrumentation/Doctrine' | ||
php-version: 8.1 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert to newline EOF.
No description provided.