1- import { context , setSpan , Span , SpanKind , SpanStatusCode , getSpan , diag } from '@opentelemetry/api' ;
1+ import {
2+ context ,
3+ setSpan ,
4+ Span ,
5+ SpanKind ,
6+ SpanStatusCode ,
7+ getSpan ,
8+ diag ,
9+ suppressInstrumentation ,
10+ } from '@opentelemetry/api' ;
211import { DatabaseAttribute , GeneralAttribute } from '@opentelemetry/semantic-conventions' ;
312import * as sequelize from 'sequelize' ;
413import { SequelizeInstrumentationConfig } from './types' ;
@@ -8,6 +17,7 @@ import {
817 InstrumentationConfig ,
918 InstrumentationModuleDefinition ,
1019 InstrumentationNodeModuleDefinition ,
20+ InstrumentationNodeModuleFile ,
1121 isWrapped ,
1222 safeExecuteInTheMiddle ,
1323} from '@opentelemetry/instrumentation' ;
@@ -27,15 +37,40 @@ export class SequelizeInstrumentation extends InstrumentationBase<typeof sequeli
2737 }
2838
2939 protected init ( ) : InstrumentationModuleDefinition < typeof sequelize > {
40+ const connectionManagerInstrumentation = new InstrumentationNodeModuleFile < any > (
41+ 'sequelize/lib/dialects/abstract/connection-manager.js' ,
42+ [ '*' ] ,
43+ this . patchConnectionManager . bind ( this ) ,
44+ this . unpatchConnectionManager . bind ( this )
45+ ) ;
46+
3047 const module = new InstrumentationNodeModuleDefinition < typeof sequelize > (
3148 SequelizeInstrumentation . component ,
3249 [ '*' ] ,
3350 this . patch . bind ( this ) ,
34- this . unpatch . bind ( this )
51+ this . unpatch . bind ( this ) ,
52+ [ connectionManagerInstrumentation ]
3553 ) ;
3654 return module ;
3755 }
3856
57+ protected patchConnectionManager ( moduleExports : any ) : any {
58+ if ( moduleExports === undefined || moduleExports === null ) {
59+ return moduleExports ;
60+ }
61+ diag . debug ( `applying patch to sequelize ConnectionManager` ) ;
62+ this . unpatchConnectionManager ( moduleExports ) ;
63+ this . _wrap ( moduleExports . ConnectionManager . prototype , 'getConnection' , this . _getConnectionPatch . bind ( this ) ) ;
64+ return moduleExports ;
65+ }
66+
67+ protected unpatchConnectionManager ( moduleExports : any ) : any {
68+ if ( isWrapped ( moduleExports ?. ConnectionManager ?. prototype ?. getConnection ) ) {
69+ this . _unwrap ( moduleExports . ConnectionManager . prototype , 'getConnection' ) ;
70+ }
71+ return moduleExports ;
72+ }
73+
3974 protected patch ( moduleExports : typeof sequelize ) : typeof sequelize {
4075 if ( moduleExports === undefined || moduleExports === null ) {
4176 return moduleExports ;
@@ -54,6 +89,14 @@ export class SequelizeInstrumentation extends InstrumentationBase<typeof sequeli
5489 }
5590 }
5691
92+ // run getConnection with suppressInstrumentation, as it might call internally to `databaseVersion` function
93+ // which calls `query` and create internal span which we don't need to instrument
94+ private _getConnectionPatch ( original : Function ) {
95+ return function ( ...args : unknown [ ] ) {
96+ return context . with ( suppressInstrumentation ( context . active ( ) ) , ( ) => original . apply ( this , args ) ) ;
97+ } ;
98+ }
99+
57100 private _createQueryPatch ( original : Function ) {
58101 const self = this ;
59102 return function ( sql : any , option : any ) {
@@ -101,11 +144,7 @@ export class SequelizeInstrumentation extends InstrumentationBase<typeof sequeli
101144 safeExecuteInTheMiddle (
102145 ( ) => self . _config . responseHook ( newSpan , response ) ,
103146 ( e : Error ) => {
104- if ( e )
105- diag . error (
106- 'sequelize instrumentation: responseHook error' ,
107- e
108- ) ;
147+ if ( e ) diag . error ( 'sequelize instrumentation: responseHook error' , e ) ;
109148 } ,
110149 true
111150 ) ;
0 commit comments