-
Notifications
You must be signed in to change notification settings - Fork 558
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(oracledb): Add support for Oracle DB instrumentation #2612
base: main
Are you sure you want to change the base?
Conversation
Add Oracledb instrumentation
|
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.
Did another round of review and added few more comments.
Currently marking as "RequestChanges" due to the following 2 issues:
- the copyright to oracle should be addressed (not sure in what way) @open-telemetry/javascript-maintainers
- the instrumentation must not import from the instrumented package.
Thanks again
|
||
// Register the instance with oracledb. | ||
newmoduleExports.traceHandler.setTraceInstance(obj); | ||
this._tmHandler = obj; |
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.
the patch
function can be called more than once per instrumentation instance.
It will happen if the instrumented package is installed multiple times in the node_modules
(for example - with 2 different versions).
While it's not very likely for oracle db driver, it's an anti pattern for instrumentation.
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 am using non null check to see if its patched already, then unregister and register again. Please add if i missed anything.
if (this._tmHandler) {
'oracledb', | ||
['>= 6.7 < 7'], | ||
(moduleExports: typeof oracleDBTypes) => { | ||
const newmoduleExports: any = moduleExports; |
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.
nit: it's not actually new, right?
the changes we apply here will modify the moduleExports
itself.
I think all other instrumentation are updating the moduleExports
var directly so it can be nice to align for consistency and to reflect that the original object is modified and not a copy.
same for the unpatch
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.
Yes removed newmoduleExports
variable.
ATTR_DB_NAMESPACE, | ||
ATTR_DB_OPERATION_NAME, | ||
} from './semconv'; | ||
import * as oracledbTypes from 'oracledb'; |
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.
when this instrumentation is added to the auto-instrumentation package, or any other otel distribution, this line will ALWAYS run.
If the user has the oracledb
package in the node_modules
, with an up-to-date version, things will work fine. When the instrumented package is not install, this line will crash the app as the import will fail.
read more here
Why do you need to extend a class and not implement an interface? unfortunately this cannot merge as is
if (this._instrumentConfig.enhancedDatabaseReporting && !roundTrip) { | ||
const values = this._getValues(callConfig.values); | ||
if (values) { | ||
span.setAttribute(AttributeNames.ORACLE_BIND_VALUES, values); |
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.
semantic conventions defined an attribute per value:
https://github.com/open-telemetry/semantic-conventions/blob/main/docs/attributes-registry/db.md#db-operation-parameter
should we align this instrumentation?
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 will try. But since it was more for debugging and its a sensitive information, I think its less priority.
enhancedDatabaseReporting?: boolean; | ||
|
||
/** | ||
* If true, db.statement will have sql in the spans generated. |
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.
also here - the query will be recorded and can potentially contain sensitive unparameterized data. can be nice to add a note here to let users know this option might be dangerous.
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.
Added the following:
If true, db.statement will have sql which could potentially contain
sensitive unparameterized data in the spans generated.
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.
this file is named utils
but it's not hosting util functions.
consider renaming it to OracleTelemetryTraceHandler.ts
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.
Renamed to OracleTelemetryTraceHandler.ts
|
||
export interface OracleRequestHookInformation { | ||
inputArgs: any; | ||
connection: SpanConnectionConfig | undefined; |
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.
when will this be undefined
?
or is it only for safety?
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.
removed undefined
.
Once this PR is finalized and ready to merge, I can be your second sponsor for the organization membership |
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.
Renamed to OracleTelemetryTraceHandler.ts
enhancedDatabaseReporting?: boolean; | ||
|
||
/** | ||
* If true, db.statement will have sql in the spans generated. |
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.
Added the following:
If true, db.statement will have sql which could potentially contain
sensitive unparameterized data in the spans generated.
'oracledb', | ||
['>= 6.7 < 7'], | ||
(moduleExports: typeof oracleDBTypes) => { | ||
const newmoduleExports: any = moduleExports; |
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.
Yes removed newmoduleExports
variable.
|
||
// Register the instance with oracledb. | ||
newmoduleExports.traceHandler.setTraceInstance(obj); | ||
this._tmHandler = obj; |
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 am using non null check to see if its patched already, then unregister and register again. Please add if i missed anything.
if (this._tmHandler) {
|
||
export interface OracleRequestHookInformation { | ||
inputArgs: any; | ||
connection: SpanConnectionConfig | undefined; |
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.
removed undefined
.
import type { traceHandler } from 'oracledb'; // Import only for type checking | ||
|
||
// It returns the TraceHandlerBase class, if oracledb module is available. | ||
function getTraceHandlerBaseClass(): TraceHandlerBaseConstructor | null { |
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.
For the issue with requiring oracledb to be present in node_modules with this line:
import * as oracledbTypes from 'oracledb';
I made changes to import types instead:
import type { traceHandler } from 'oracledb';
Now since oracledb
module exposes TraceHandlerBase
as abstract class where some default implementations (enable
) are available, I can not do implements TraceHandlerBase
.
Added a function, getTraceHandlerBaseClass which gives the constructor for TraceHandlerBase dynamically during patch avoiding global require("oracledb")
in generated js files.
The types added inside this file will be removed once this PR and release including this change is done.
Please confirm if i am missed anything or any suggestions.
Thanks for pointing it out with details.
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.
Note that the instance of oracledb
that's being require
d by the instrumentation package here might differ from the one that is being patched. Given you have access to the exports from the patch method it would be a better idea to pass them here as a parameter and get the base class from the instance that's being instrumented.
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.
got it. I made the changes accordingly.
I have addressed the second point by including types , Please see. |
I have removed the copyrights from src/. It is only added in |
removed copyright from component_owners.yml
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.
LGTM.
adding the relevant part from OpenTelemetry community regarding the copyright notice for future reference:
obj: typeof oracleDBTypes | ||
): any { | ||
const traceHandlerBase = getTraceHandlerBaseClass(obj); | ||
if (traceHandlerBase) { |
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.
nit: instead of creating an if
with >300 lines of code, we can revert the check and exist fast:
if (traceHandlerBase) { | |
if (!traceHandlerBase) { | |
return undefined; | |
} | |
// else - all the code below, not nested and no indentation. |
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.
Done.
use new propery, instrumentationScope and replaced addSpanProcessor with new syntax of BasicTracerProvider constructor.
Add Oracledb instrumentation
Which problem is this PR solving?
Adding instrumentation support for node-oracledb applications connecting to Oracle database.
Short description of the changes
From node-oracledb version 6.7 onwards, oracledb module exports a class,
TraceHandlerBase
which simulates interface kind of functionality with abstract methods to be overwritten by the derived class.The current OT module derives this class
TraceHandlerBase
and implements abstract methods; It usessetTraceInstance
method oforacledb
module to register this new derived classOracleTelemetryTraceHandler
These methods are invoked by
oracledb
module providing thetraceContext
which is used to dump the data in to the span after converting to standard span attributes.Following are the abstract methods implemented:
oracledb
module when application invokesgetConnection
to create a connection todatabase or
execute
method to run a sql. It is invoked before invoking the public API calls made by application.