Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
3dabf33
feat: add sequelize instrumentation
seemk Aug 21, 2024
9c9ff4c
Merge branch 'main' into instrumentation-sequelize
seemk Aug 21, 2024
7700a12
chore: update release please
seemk Aug 21, 2024
1e17f8a
lint
seemk Aug 21, 2024
22173ed
add readme
seemk Aug 22, 2024
2ec23e7
Merge branch 'main' into instrumentation-sequelize
seemk Aug 22, 2024
aacfe46
Merge branch 'main' into instrumentation-sequelize
seemk Aug 22, 2024
9023e2f
Merge branch 'main' into instrumentation-sequelize
seemk Aug 27, 2024
2b8b855
Merge branch 'main' into instrumentation-sequelize
seemk Sep 2, 2024
26fa4d0
Merge branch 'main' into instrumentation-sequelize
seemk Sep 3, 2024
bbca381
update dependencies
seemk Sep 3, 2024
8bfac99
Merge branch 'main' into instrumentation-sequelize
seemk Sep 10, 2024
f9efe6d
Merge branch 'main' into instrumentation-sequelize
seemk Sep 11, 2024
558ffea
Merge branch 'main' into instrumentation-sequelize
seemk Sep 18, 2024
c92fcd8
Merge branch 'main' into instrumentation-sequelize
seemk Sep 25, 2024
6bdf646
Merge branch 'main' into instrumentation-sequelize
seemk Oct 2, 2024
2766f3c
Merge branch 'main' into instrumentation-sequelize
seemk Oct 15, 2024
f1d6ea4
Merge branch 'main' into instrumentation-sequelize
seemk Oct 17, 2024
203d2c5
Merge branch 'main' into instrumentation-sequelize
seemk Oct 30, 2024
d3335dd
Merge branch 'main' into instrumentation-sequelize
seemk Mar 18, 2025
ca3a6b1
Merge branch 'main' into instrumentation-sequelize
seemk Jun 27, 2025
5fe7cf8
add component owners
seemk Jun 27, 2025
2200f33
Merge branch 'main' into instrumentation-sequelize
seemk Jun 27, 2025
60bc681
Merge branch 'main' into instrumentation-sequelize
seemk Jun 27, 2025
81881ad
update semconv
seemk Jun 30, 2025
a8b0a14
Merge branch 'main' into instrumentation-sequelize
seemk Jun 30, 2025
f6b8517
add otel core to deps
seemk Jun 30, 2025
df1bb5f
use proper types, remove unnecessary filter
seemk Jul 1, 2025
dbfc29c
use explicit exports
seemk Jul 1, 2025
91f0eb2
Merge branch 'main' into instrumentation-sequelize
seemk Jul 24, 2025
0d670c9
use newer directory structure
seemk Jul 24, 2025
f87543e
Merge branch 'main' into instrumentation-sequelize
seemk Oct 21, 2025
86d4eab
update deps
seemk Oct 21, 2025
b67ed74
update package.json
seemk Oct 21, 2025
8366442
add tav config
seemk Oct 21, 2025
b74af7d
remove unnecessary eslint files
seemk Oct 21, 2025
e10c56e
ci
seemk Oct 22, 2025
286825f
Merge branch 'main' into instrumentation-sequelize
seemk Oct 22, 2025
9018be5
Merge branch 'main' into instrumentation-sequelize
seemk Oct 23, 2025
b3618f4
update package lock
seemk Oct 23, 2025
6a44776
Merge branch 'main' into instrumentation-sequelize
seemk Oct 23, 2025
cd305fc
Merge branch 'main' into instrumentation-sequelize
seemk Oct 27, 2025
1a4e296
Merge branch 'main' into instrumentation-sequelize
seemk Oct 29, 2025
9d6e5c6
Merge branch 'main' into instrumentation-sequelize
seemk Oct 31, 2025
fb1cc5e
Merge branch 'main' into instrumentation-sequelize
pichlermarc Nov 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
update semconv
  • Loading branch information
seemk committed Jun 30, 2025
commit 81881addc1018f058fbd1bf0f080a446211a1039
22 changes: 10 additions & 12 deletions plugins/node/instrumentation-sequelize/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,19 @@ You can set the following:

## Semantic Conventions

This package uses `@opentelemetry/semantic-conventions` version `1.25+`, which implements Semantic Convention [Version 1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md)
| Attribute | Short Description |
| ---------------------| --------------------------------------------------------------------------- |
| `db.namespace` | The name of the database being accessed. |
| `db.operation.name` | The name of the operation being executed (e.g. the SQL keyword). |
| `db.collection.name` | The name of the table being accessed. |
| `db.query.text` | The database statement being executed. |
| `db.system.name` | An identifier for the database management system (DBMS) product being used. |
| `server.address` | Remote address of the database. |
| `server.port` | Peer port number of the network connection. |
| `network transport` | OSI transport layer or inter-process communication method. |

Attributes collected:

| Attribute | Short Description |
| ----------------| --------------------------------------------------------------------------- |
| `db.name` | The name of the database being accessed. |
| `db.operation` | The name of the operation being executed. |
| `db.statement` | The database statement being executed. |
| `db.sql.table` | The name of the table being used. |
| `db.system` | An identifier for the database management system (DBMS) product being used. |
| `db.user` | Username for accessing the database. |
| `net.peer.name` | Remote hostname of the database. |
| `net.peer.port` | Port of the database. |
| `net.transport` | The transport protocol being used. |

## Useful links

Expand Down
41 changes: 19 additions & 22 deletions plugins/node/instrumentation-sequelize/src/instrumentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ import {
} from '@opentelemetry/api';
import { suppressTracing } from '@opentelemetry/core';
import {
NETTRANSPORTVALUES_IP_TCP,
SEMATTRS_DB_NAME,
SEMATTRS_DB_OPERATION,
SEMATTRS_DB_SQL_TABLE,
SEMATTRS_DB_STATEMENT,
SEMATTRS_DB_SYSTEM,
SEMATTRS_DB_USER,
SEMATTRS_NET_PEER_NAME,
SEMATTRS_NET_PEER_PORT,
SEMATTRS_NET_TRANSPORT,
ATTR_DB_COLLECTION_NAME,
ATTR_DB_OPERATION_NAME,
ATTR_DB_NAMESPACE,
ATTR_DB_QUERY_TEXT,
ATTR_DB_SYSTEM_NAME,
ATTR_SERVER_ADDRESS,
ATTR_SERVER_PORT,
ATTR_NETWORK_TRANSPORT,
NETWORK_TRANSPORT_VALUE_TCP,
} from '@opentelemetry/semantic-conventions';
import type * as sequelize from 'sequelize';
import { SequelizeInstrumentationConfig } from './types';
/** @knipignore */
import { PACKAGE_NAME, PACKAGE_VERSION } from './version';
import { extractTableFromQuery } from './utils';
import {
Expand Down Expand Up @@ -164,17 +164,14 @@ export class SequelizeInstrumentation extends InstrumentationBase<SequelizeInstr

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const attributes: Record<string, any> = {
[SEMATTRS_DB_SYSTEM]: sequelizeInstance.getDialect(),
[SEMATTRS_DB_USER]: config?.username,
[SEMATTRS_NET_PEER_NAME]: config?.host,
[SEMATTRS_NET_PEER_PORT]: config?.port
? Number(config?.port)
: undefined,
[SEMATTRS_NET_TRANSPORT]: self._getNetTransport(config?.protocol),
[SEMATTRS_DB_NAME]: config?.database,
[SEMATTRS_DB_OPERATION]: operation,
[SEMATTRS_DB_STATEMENT]: statement,
[SEMATTRS_DB_SQL_TABLE]: tableName,
[ATTR_DB_SYSTEM_NAME]: sequelizeInstance.getDialect(),
[ATTR_DB_NAMESPACE]: config?.database,
[ATTR_DB_OPERATION_NAME]: operation,
[ATTR_DB_QUERY_TEXT]: statement,
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not familiar with the package so I'm not sure if this may raise PII issues. I see the statement is extracted from the params but I'm not sure if it has placeholders for the values or may contain the actual values

Copy link
Contributor Author

@seemk seemk Jul 2, 2025

Choose a reason for hiding this comment

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

Played around with it a bit, when using where clauses, sequelize seems to generate the where part without placeholders 🤦

I guess the query summary could be used here, with the where clause hidden

[ATTR_DB_COLLECTION_NAME]: tableName,
[ATTR_SERVER_ADDRESS]: config?.host,
[ATTR_SERVER_PORT]: config?.port ? Number(config?.port) : undefined,
[ATTR_NETWORK_TRANSPORT]: self._getNetTransport(config?.protocol),
};

Object.entries(attributes).forEach(([key, value]) => {
Expand Down Expand Up @@ -244,7 +241,7 @@ export class SequelizeInstrumentation extends InstrumentationBase<SequelizeInstr
private _getNetTransport(protocol: string) {
switch (protocol) {
case 'tcp':
return NETTRANSPORTVALUES_IP_TCP;
return NETWORK_TRANSPORT_VALUE_TCP;
default:
return undefined;
}
Expand Down
122 changes: 61 additions & 61 deletions plugins/node/instrumentation-sequelize/test/sequelize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@ import {
ROOT_CONTEXT,
} from '@opentelemetry/api';
import {
SEMATTRS_DB_NAME,
SEMATTRS_DB_STATEMENT,
SEMATTRS_DB_SQL_TABLE,
SEMATTRS_NET_PEER_NAME,
SEMATTRS_NET_PEER_PORT,
SEMATTRS_DB_OPERATION,
SEMATTRS_DB_SYSTEM,
SEMATTRS_DB_USER,
ATTR_DB_COLLECTION_NAME,
ATTR_DB_OPERATION_NAME,
ATTR_DB_NAMESPACE,
ATTR_DB_QUERY_TEXT,
ATTR_DB_SYSTEM_NAME,
ATTR_SERVER_ADDRESS,
ATTR_SERVER_PORT,
} from '@opentelemetry/semantic-conventions';
import {
getTestSpans,
Expand Down Expand Up @@ -65,12 +64,12 @@ describe('instrumentation-sequelize', () => {
describe('postgres', () => {
const DB_SYSTEM = 'postgres';
const DB_USER = 'some-user';
const NET_PEER_NAME = 'localhost';
const NET_PEER_PORT = 12345;
const SERVER_ADDRESS = 'localhost';
const SERVER_PORT = 12345;
const DB_NAME = 'my-db';

const instance = new sequelize.Sequelize(
`${DB_SYSTEM}://${DB_USER}@${NET_PEER_NAME}:${NET_PEER_PORT}/${DB_NAME}`,
`${DB_SYSTEM}://${DB_USER}@${SERVER_ADDRESS}:${SERVER_PORT}/${DB_NAME}`,
{ logging: false }
);
class User extends sequelize.Model {
Expand All @@ -93,15 +92,14 @@ describe('instrumentation-sequelize', () => {
assert.strictEqual(spans[0].status.code, SpanStatusCode.ERROR);
const attributes = spans[0].attributes;

assert.strictEqual(attributes[SEMATTRS_DB_SYSTEM], DB_SYSTEM);
assert.strictEqual(attributes[SEMATTRS_DB_USER], DB_USER);
assert.strictEqual(attributes[SEMATTRS_NET_PEER_NAME], NET_PEER_NAME);
assert.strictEqual(attributes[SEMATTRS_NET_PEER_PORT], NET_PEER_PORT);
assert.strictEqual(attributes[SEMATTRS_DB_NAME], DB_NAME);
assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'INSERT');
assert.strictEqual(attributes[SEMATTRS_DB_SQL_TABLE], 'Users');
assert.strictEqual(attributes[ATTR_DB_SYSTEM_NAME], DB_SYSTEM);
assert.strictEqual(attributes[ATTR_SERVER_ADDRESS], SERVER_ADDRESS);
assert.strictEqual(attributes[ATTR_SERVER_PORT], SERVER_PORT);
assert.strictEqual(attributes[ATTR_DB_NAMESPACE], DB_NAME);
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'INSERT');
assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
assert.match(
attributes[SEMATTRS_DB_STATEMENT] as string,
attributes[ATTR_DB_QUERY_TEXT] as string,
/INSERT INTO "Users" \("id","firstName","createdAt","updatedAt"\) VALUES \(DEFAULT,\$1,\$2,\$3\) RETURNING (\*|"id","firstName","createdAt","updatedAt");/
);
});
Expand All @@ -112,10 +110,10 @@ describe('instrumentation-sequelize', () => {
assert.strictEqual(spans.length, 1);
const attributes = spans[0].attributes;

assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'SELECT');
assert.strictEqual(attributes[SEMATTRS_DB_SQL_TABLE], 'Users');
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
assert.strictEqual(
attributes[SEMATTRS_DB_STATEMENT],
attributes[ATTR_DB_QUERY_TEXT],
'SELECT "id", "firstName", "createdAt", "updatedAt" FROM "Users" AS "User";'
);
});
Expand All @@ -126,9 +124,9 @@ describe('instrumentation-sequelize', () => {
assert.strictEqual(spans.length, 1);
const attributes = spans[0].attributes;

assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'BULKDELETE');
assert.strictEqual(attributes[SEMATTRS_DB_SQL_TABLE], 'Users');
assert.strictEqual(attributes[SEMATTRS_DB_STATEMENT], 'TRUNCATE "Users"');
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'BULKDELETE');
assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
assert.strictEqual(attributes[ATTR_DB_QUERY_TEXT], 'TRUNCATE "Users"');
});

it('count is instrumented', async () => {
Expand All @@ -137,10 +135,10 @@ describe('instrumentation-sequelize', () => {
assert.strictEqual(spans.length, 1);
const attributes = spans[0].attributes;

assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'SELECT');
assert.strictEqual(attributes[SEMATTRS_DB_SQL_TABLE], 'Users');
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
assert.strictEqual(
attributes[SEMATTRS_DB_STATEMENT],
attributes[ATTR_DB_QUERY_TEXT],
'SELECT count(*) AS "count" FROM "Users" AS "User";'
);
});
Expand All @@ -167,10 +165,10 @@ describe('instrumentation-sequelize', () => {
assert.strictEqual(spans.length, 1);
const attributes = spans[0].attributes;

assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'SELECT');
assert.strictEqual(attributes[SEMATTRS_DB_SQL_TABLE], 'Users');
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
assert.strictEqual(
attributes[SEMATTRS_DB_STATEMENT],
attributes[ATTR_DB_QUERY_TEXT],
'SELECT "id", "username" FROM "Users" AS "User" WHERE "User"."username" = \'Shlomi\' AND ("User"."rank" < 1000 OR "User"."rank" IS NULL) ORDER BY "User"."username" DESC LIMIT 10 OFFSET 5;'
);
});
Expand All @@ -184,7 +182,10 @@ describe('instrumentation-sequelize', () => {
const spans = getSequelizeSpans();
assert.strictEqual(spans.length, 1);
const attributes = spans[0].attributes;
assert.strictEqual(attributes[SEMATTRS_DB_SQL_TABLE], expectedTableName);
assert.strictEqual(
attributes[ATTR_DB_COLLECTION_NAME],
expectedTableName
);
});

it('handles JOIN queries', async () => {
Expand Down Expand Up @@ -217,10 +218,10 @@ describe('instrumentation-sequelize', () => {
assert.strictEqual(spans.length, 1);
const attributes = spans[0].attributes;

assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'SELECT');
assert.strictEqual(attributes[SEMATTRS_DB_SQL_TABLE], 'Dogs,Users');
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Dogs,Users');
assert.strictEqual(
attributes[SEMATTRS_DB_STATEMENT],
attributes[ATTR_DB_QUERY_TEXT],
'SELECT "Dog"."id", "Dog"."firstName", "Dog"."owner", "User"."id" AS "User.id", "User"."firstName" AS "User.firstName" FROM "Dogs" AS "Dog" INNER JOIN "Users" AS "User" ON "Dog"."firstName" = "User"."id" LIMIT 1;'
);
});
Expand All @@ -229,13 +230,13 @@ describe('instrumentation-sequelize', () => {
describe('mysql', () => {
const DB_SYSTEM = 'mysql';
const DB_USER = 'RickSanchez';
const NET_PEER_NAME = 'localhost';
const NET_PEER_PORT = 34567;
const SERVER_NAME = 'localhost';
const SERVER_PORT = 34567;
const DB_NAME = 'mysql-db';

const instance = new sequelize.Sequelize(DB_NAME, DB_USER, 'password', {
host: NET_PEER_NAME,
port: NET_PEER_PORT,
host: SERVER_NAME,
port: SERVER_PORT,
dialect: DB_SYSTEM,
});

Expand All @@ -252,15 +253,14 @@ describe('instrumentation-sequelize', () => {
assert.strictEqual(spans[0].status.code, SpanStatusCode.ERROR);
const attributes = spans[0].attributes;

assert.strictEqual(attributes[SEMATTRS_DB_SYSTEM], DB_SYSTEM);
assert.strictEqual(attributes[SEMATTRS_DB_USER], DB_USER);
assert.strictEqual(attributes[SEMATTRS_NET_PEER_NAME], NET_PEER_NAME);
assert.strictEqual(attributes[SEMATTRS_NET_PEER_PORT], NET_PEER_PORT);
assert.strictEqual(attributes[SEMATTRS_DB_NAME], DB_NAME);
assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'INSERT');
assert.strictEqual(attributes[SEMATTRS_DB_SQL_TABLE], 'Users');
assert.strictEqual(attributes[ATTR_DB_SYSTEM_NAME], DB_SYSTEM);
assert.strictEqual(attributes[ATTR_SERVER_ADDRESS], SERVER_NAME);
assert.strictEqual(attributes[ATTR_SERVER_PORT], SERVER_PORT);
assert.strictEqual(attributes[ATTR_DB_NAMESPACE], DB_NAME);
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'INSERT');
assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
assert.strictEqual(
attributes[SEMATTRS_DB_STATEMENT],
attributes[ATTR_DB_QUERY_TEXT],
'INSERT INTO `Users` (`id`,`firstName`,`createdAt`,`updatedAt`) VALUES (DEFAULT,$1,$2,$3);'
);
});
Expand All @@ -271,10 +271,10 @@ describe('instrumentation-sequelize', () => {
assert.strictEqual(spans.length, 1);
const attributes = spans[0].attributes;

assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'SELECT');
assert.strictEqual(attributes[SEMATTRS_DB_SQL_TABLE], 'Users');
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
assert.strictEqual(
attributes[SEMATTRS_DB_STATEMENT],
attributes[ATTR_DB_QUERY_TEXT],
'SELECT `id`, `firstName`, `createdAt`, `updatedAt` FROM `Users` AS `User`;'
);
});
Expand All @@ -290,8 +290,8 @@ describe('instrumentation-sequelize', () => {
assert.strictEqual(spans.length, 1);
const attributes = spans[0].attributes;

assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'SELECT');
assert.strictEqual(attributes[SEMATTRS_DB_STATEMENT], 'SELECT 1 + 1');
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
assert.strictEqual(attributes[ATTR_DB_QUERY_TEXT], 'SELECT 1 + 1');
});
it('with type not specified in options', async () => {
try {
Expand All @@ -303,8 +303,8 @@ describe('instrumentation-sequelize', () => {
assert.strictEqual(spans.length, 1);
const attributes = spans[0].attributes;

assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'SELECT');
assert.strictEqual(attributes[SEMATTRS_DB_STATEMENT], 'SELECT 1 + 1');
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'SELECT');
assert.strictEqual(attributes[ATTR_DB_QUERY_TEXT], 'SELECT 1 + 1');
});

it('with type specified in options', async () => {
Expand All @@ -319,8 +319,8 @@ describe('instrumentation-sequelize', () => {
assert.strictEqual(spans.length, 1);
const attributes = spans[0].attributes;

assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'RAW');
assert.strictEqual(attributes[SEMATTRS_DB_STATEMENT], 'SELECT 1 + 1');
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'RAW');
assert.strictEqual(attributes[ATTR_DB_QUERY_TEXT], 'SELECT 1 + 1');
});
});
});
Expand All @@ -340,12 +340,12 @@ describe('instrumentation-sequelize', () => {
const spans = getSequelizeSpans();
assert.strictEqual(spans.length, 1);
const attributes = spans[0].attributes;
assert.strictEqual(attributes[SEMATTRS_DB_SYSTEM], 'sqlite');
assert.strictEqual(attributes[SEMATTRS_NET_PEER_NAME], 'memory');
assert.strictEqual(attributes[SEMATTRS_DB_OPERATION], 'INSERT');
assert.strictEqual(attributes[SEMATTRS_DB_SQL_TABLE], 'Users');
assert.strictEqual(attributes[ATTR_DB_SYSTEM_NAME], 'sqlite');
assert.strictEqual(attributes[ATTR_SERVER_ADDRESS], 'memory');
assert.strictEqual(attributes[ATTR_DB_OPERATION_NAME], 'INSERT');
assert.strictEqual(attributes[ATTR_DB_COLLECTION_NAME], 'Users');
assert.strictEqual(
attributes[SEMATTRS_DB_STATEMENT],
attributes[ATTR_DB_QUERY_TEXT],
'INSERT INTO `Users` (`id`,`firstName`,`createdAt`,`updatedAt`) VALUES (NULL,$1,$2,$3);'
);
});
Expand Down
Loading