Skip to content
This repository was archived by the owner on Oct 31, 2024. It is now read-only.

Commit 446b359

Browse files
author
Amir Blum
authored
fix(sequelize): internal version query is instrumented in mysql (#69)
1 parent 2245351 commit 446b359

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

packages/instrumentation-sequelize/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ Sequelize instrumentation has few options available to choose from. You can set
4444
| `responseHook` | `SequelizeResponseCustomAttributesFunction` | Hook called before response is returned, which allows to add custom attributes to span. |
4545
| `ignoreOrphanedSpans` | `boolean` | Set to true if you only want to trace operation which has parent spans |
4646

47+
## Semantic Behavior
48+
Internal implementation queries generated on startup from connection-manager are not instrumented.
49+
4750
---
4851

4952
This extension (and many others) was developed by [Aspecto](https://www.aspecto.io/) with ❤️

packages/instrumentation-sequelize/src/sequelize.ts

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
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';
211
import { DatabaseAttribute, GeneralAttribute } from '@opentelemetry/semantic-conventions';
312
import * as sequelize from 'sequelize';
413
import { 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

Comments
 (0)