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

Commit 8751164

Browse files
author
Nir Hadassi
authored
feat: add table name to sequelize spans (#132)
1 parent 675fb33 commit 8751164

File tree

7 files changed

+228
-94
lines changed

7 files changed

+228
-94
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,7 @@ yarn.lock
2323

2424
# aspecto
2525
aspecto.json
26-
aspecto.log
26+
aspecto.log
27+
28+
# created from sequelize unit tests
29+
memory

packages/instrumentation-sequelize/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ 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
| `moduleVersionAttributeName` | `string` | If passed, a span attribute will be added to all spans with key of the provided `moduleVersionAttributeName` and value of the patched module version |
47+
| `suppressInternalInstrumentation` | `boolean` | Sequelize operation use db libs under the hood. Setting this to true will hide the underlying spans (if instrumented). |
48+
4749

4850
## Semantic Behavior
4951
Internal implementation queries generated on startup from connection-manager are not instrumented.

packages/instrumentation-sequelize/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"opentelemetry-instrumentation-testing-utils": "^0.5.0",
5555
"pg": "^8.4.2",
5656
"sequelize": "^5.22.0",
57+
"sqlite3": "^5.0.2",
5758
"ts-node": "^9.1.1",
5859
"typescript": "^4.0.3"
5960
},

packages/instrumentation-sequelize/src/sequelize.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { NetTransportValues, SemanticAttributes } from '@opentelemetry/semantic-
44
import * as sequelize from 'sequelize';
55
import { SequelizeInstrumentationConfig } from './types';
66
import { VERSION } from './version';
7+
import { extractTableFromQuery } from './utils';
78
import {
89
InstrumentationBase,
910
InstrumentationModuleDefinition,
@@ -106,6 +107,13 @@ export class SequelizeInstrumentation extends InstrumentationBase<typeof sequeli
106107
const sequelizeInstance: sequelize.Sequelize = this;
107108
const config = sequelizeInstance?.config;
108109

110+
let tableName = option?.instance?.constructor?.tableName;
111+
if (!tableName) {
112+
if (Array.isArray(option?.tableNames) && option.tableNames.length > 0)
113+
tableName = option?.tableNames.sort().join(',');
114+
else tableName = extractTableFromQuery(statement);
115+
}
116+
109117
const attributes = {
110118
[SemanticAttributes.DB_SYSTEM]: sequelizeInstance.getDialect(),
111119
[SemanticAttributes.DB_USER]: config?.username,
@@ -115,7 +123,7 @@ export class SequelizeInstrumentation extends InstrumentationBase<typeof sequeli
115123
[SemanticAttributes.DB_NAME]: config?.database,
116124
[SemanticAttributes.DB_OPERATION]: operation,
117125
[SemanticAttributes.DB_STATEMENT]: statement,
118-
component: 'sequelize',
126+
[SemanticAttributes.DB_SQL_TABLE]: tableName,
119127
// [SemanticAttributes.NET_PEER_IP]: '?', // Part of protocol
120128
};
121129

@@ -132,8 +140,15 @@ export class SequelizeInstrumentation extends InstrumentationBase<typeof sequeli
132140
attributes,
133141
});
134142

143+
const activeContextWithSpan = trace.setSpan(context.active(), newSpan);
144+
135145
return context
136-
.with(trace.setSpan(context.active(), newSpan), () => original.apply(this, arguments))
146+
.with(
147+
self._config.suppressInternalInstrumentation
148+
? suppressTracing(activeContextWithSpan)
149+
: activeContextWithSpan,
150+
() => original.apply(this, arguments)
151+
)
137152
.then((response: any) => {
138153
if (self._config?.responseHook) {
139154
safeExecuteInTheMiddle(

packages/instrumentation-sequelize/src/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,12 @@ export interface SequelizeInstrumentationConfig extends InstrumentationConfig {
1313
* and value of the module version.
1414
*/
1515
moduleVersionAttributeName?: string;
16+
/**
17+
* Sequelize operation use postgres/mysql/mariadb/etc. under the hood.
18+
* If, for example, postgres instrumentation is enabled, a postgres operation will also create
19+
* a postgres span describing the communication.
20+
* Setting the `suppressInternalInstrumentation` config value to `true` will
21+
* cause the instrumentation to suppress instrumentation of underlying operations.
22+
*/
23+
suppressInternalInstrumentation?: boolean;
1624
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export const extractTableFromQuery = (query: string) => {
2+
try {
3+
const result = query?.match(/(?<=from|join|truncate)\s+\"?\`?(\w+)\"?\`?/gi);
4+
if (!Array.isArray(result)) return;
5+
6+
return result
7+
.map((table) =>
8+
table
9+
.trim()
10+
.replace(/^"(.*)"$/, '$1')
11+
.replace(/^`(.*)`$/, '$1')
12+
)
13+
.sort()
14+
.join(',');
15+
} catch {
16+
return;
17+
}
18+
};

0 commit comments

Comments
 (0)