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

feat: postgresql responseHook support #528

Merged
merged 7 commits into from Jun 28, 2021
Merged

Conversation

nata7che
Copy link
Contributor

@nata7che nata7che commented Jun 9, 2021

Which problem is this PR solving?

  • Add the ability to collect the response to a pg query (as an optional configuration). This data can be used for monitoring purposes.

Short description of the changes

  • add responseHook config to PgInstrumentationConfig
  • When provided (in addition to the enhancedDatabaseReporting flag, safely use it to collect the data from the execution result

@nata7che nata7che requested a review from a team as a code owner June 9, 2021 14:00
@codecov
Copy link

codecov bot commented Jun 9, 2021

Codecov Report

Merging #528 (38b78c6) into main (a52deec) will increase coverage by 0.00%.
The diff coverage is 97.41%.

@@           Coverage Diff            @@
##             main     #528    +/-   ##
========================================
  Coverage   94.92%   94.93%            
========================================
  Files         162      159     -3     
  Lines        9991     9828   -163     
  Branches      992      932    -60     
========================================
- Hits         9484     9330   -154     
+ Misses        507      498     -9     
Impacted Files Coverage Δ
...ntelemetry-instrumentation-pg/test/pg-pool.test.ts 91.42% <96.15%> (+1.91%) ⬆️
...e/opentelemetry-instrumentation-pg/test/pg.test.ts 95.01% <98.00%> (+0.59%) ⬆️
...elemetry-instrumentation-pg/src/instrumentation.ts 82.47% <100.00%> (+0.18%) ⬆️
...node/opentelemetry-instrumentation-pg/src/utils.ts 97.61% <100.00%> (+0.35%) ⬆️
...ation-user-interaction/src/enums/AttributeNames.ts
...umentation-user-interaction/src/instrumentation.ts
...ry-instrumentation-user-interaction/src/version.ts

@nata7che
Copy link
Contributor Author

nata7che commented Jun 9, 2021

Hey @obecny, fixed the commits issue (had to create a new PR), tnx!

@@ -199,6 +200,7 @@ export class PgInstrumentation extends InstrumentationBase {
.then((result: unknown) => {
// Return a pass-along promise which ends the span and then goes to user's orig resolvers
return new Promise(resolve => {
Copy link
Member

Choose a reason for hiding this comment

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

I understand that nested new Promise was here before but it really is not needed.
You can just do the sync calls inside the then callback function and it behaves exactly the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks @rauno56, I agree and also noticed it when writing this PR. However, and if that is alright with you, I'd prefer to leave this change to a different PR?

@rauno56
Copy link
Member

rauno56 commented Jun 11, 2021

Generally looks good! Thanks for the effort you've put into it and sorry for the late review!

import { InstrumentationConfig } from '@opentelemetry/instrumentation';

export interface PgInstrumentationExecutionResponseHook {
(span: api.Span, data: pgTypes.QueryResult | pgTypes.QueryArrayResult): void;
Copy link
Member

Choose a reason for hiding this comment

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

Instead of sending data as the second parameter, it might be better to send an responseInfo with the data on it.
That way, when someone wants to add new parameters in the future, the function signature will not grow more and more.

Link to discussion
Example

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good Idea! will change.

},
err => {
if (err) {
diag.error('Error running response hook', err);
Copy link
Member

@blumamir blumamir Jun 13, 2021

Choose a reason for hiding this comment

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

optional: I like to add a prefix to my logs so if it prints, there is context on where it's coming from. Something like: pg instrumentation: ${...}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great idea, I’d suggest implementing this (in a separate PR, of course) at the InstrumentationBase level so that it won't be necessary to manually add the prefix separately for each instrumentation class. WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

I think it's a great idea :)

Copy link
Member

Choose a reason for hiding this comment

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

I now read the v0.21.0 release notes and looks like it was added there:
open-telemetry/opentelemetry-js#2261

Copy link
Member

Choose a reason for hiding this comment

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

It was indeed added on instrumentation but you should use this._diag from the instrumentation class to be able to use it. I think you'll need to give the instance class here to make it work

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@vmarchaud, @blumamir for this PR I recommend not adding this change.
_diag is a protected member, it's accessible only internally within the class or any class that extends it but not externally. Since the pg instrumentation uses the utils module, passing the instrumentation will not be enough and a refactor is needed here.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, I agree. We tried to refactor our instrumentations as well and bumped into the same issue, and decided not to use this component logger after all.
However, we made sure all the log prints are prefixed with ${packageName} instrumentation:, for example.

But I see there is no convention for the contrib instrumentations on that, so it's up to you.

Copy link
Member

@obecny obecny Jun 24, 2021

Choose a reason for hiding this comment

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

why not passing the component logger to the util class directly from class when you call the util method ? @blumamir @nata7che in worst scenario I would change the signature to be public from protected instead of trying to mimic the behaviour of component diag logger. But it should be possible to simply pass the logger from class to util

pgResult: pgTypes.QueryResult | pgTypes.QueryArrayResult | unknown
) {
if (
config.enhancedDatabaseReporting &&
Copy link
Member

Choose a reason for hiding this comment

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

why do you require truthy enhancedDatabaseReporting for calling responseHook?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will be removed also in accordance to @rauno56's comment above

0
);
runCallbackTest(span, pgAttributes, events, unsetStatus, 2, 1);
assert.ok(result, 'pool.query() returns a promise');
Copy link
Member

Choose a reason for hiding this comment

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

result here was already awaited, right? so it's not a promise, it's the actual response for the invocation. Not sure what this assertion is meant to test... (but I don't mind if it stays here as well).

@@ -176,7 +212,10 @@ export function patchCallback(
code: SpanStatusCode.ERROR,
message: err.message,
});
} else {
handleExecutionResult(instrumentationConfig, span, res);
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't we also call the response hook in the patchCallbackPGPool function below?
Probably not, as I see there are tests for that, but how come it works?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The PgPool instrumentation added an additional patching to the pgPool.connect method, and uses the same query patching.

Copy link
Member

Choose a reason for hiding this comment

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

I have to admit I'm not very familiar with this instrumentation and its behavior.
So in what cases is "patchCallbackPGPool" being called?

@nata7che nata7che requested a review from vmarchaud June 16, 2021 12:01
@nata7che
Copy link
Contributor Author

hey @rauno56! I'd love to get your approval if you don't have any further comments 🙏🏻

@nata7che nata7che requested a review from obecny June 23, 2021 10:51
span: Span,
pgResult: pgTypes.QueryResult | pgTypes.QueryArrayResult | unknown
) {
if (config.responseHook !== undefined && pgResult !== undefined) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment from the other "add responseHook", why explicitly only checking against undefined? Why not if (config.responseHook && pg...)

Or event better if (typeof config.responseHook === "function" && pg...)

Copy link
Member

Choose a reason for hiding this comment

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

I think we should just have if (typeof config.responseHook === "function") if user adds hook we should always run it whether the pgResult is undefined or not as this is also some kind of information for someone. Preventing running this hook in such case will confuse user why the hook didn't run soo I would definitely remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@obecny pushed 👍🏻 good idea!

@nata7che
Copy link
Contributor Author

@obecny @MSNev @vmarchaud thanks for your approval 💪🏻 are we good to go ahead and merge?

@rauno56
Copy link
Member

rauno56 commented Jun 28, 2021

hey @rauno56! I'd love to get your approval if you don't have any further comments 🙏🏻

Hey, @nata7che, sorry for disappearing - I was offline for a week.
My comments weren't meant to be blocking anyways! :) LGTM!

@vmarchaud vmarchaud merged commit a8465a2 into open-telemetry:main Jun 28, 2021
@dyladan dyladan added the enhancement New feature or request label Jul 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants