From b3ba48492e8027bed631ecca56de77f8c94f55c6 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Thu, 29 Aug 2024 11:23:25 -0400 Subject: [PATCH 1/8] feat(node): Add knexIntegration to Node Set up initial code and dependencies. Enable integration by default. Signed-off-by: Kaung Zin Hein --- .../node-integration-tests/package.json | 1 + packages/node/package.json | 1 + packages/node/src/index.ts | 1 + .../node/src/integrations/tracing/index.ts | 3 + .../node/src/integrations/tracing/knex.ts | 35 ++++++++++ yarn.lock | 69 ++++++++++++++++++- 6 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 packages/node/src/integrations/tracing/knex.ts diff --git a/dev-packages/node-integration-tests/package.json b/dev-packages/node-integration-tests/package.json index fc8577a06ca0..e3bbd89e5930 100644 --- a/dev-packages/node-integration-tests/package.json +++ b/dev-packages/node-integration-tests/package.json @@ -47,6 +47,7 @@ "graphql": "^16.3.0", "http-terminator": "^3.2.0", "ioredis": "^5.4.1", + "knex": "^2.5.1", "mongodb": "^3.7.3", "mongodb-memory-server-global": "^7.6.3", "mongoose": "^5.13.22", diff --git a/packages/node/package.json b/packages/node/package.json index e6a1b0a7feec..7e5568aff01c 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -77,6 +77,7 @@ "@opentelemetry/instrumentation-hapi": "0.40.0", "@opentelemetry/instrumentation-http": "0.52.1", "@opentelemetry/instrumentation-ioredis": "0.42.0", + "@opentelemetry/instrumentation-knex": "0.39.0", "@opentelemetry/instrumentation-koa": "0.42.0", "@opentelemetry/instrumentation-mongodb": "0.46.0", "@opentelemetry/instrumentation-mongoose": "0.40.0", diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 9ef89ab42fb7..31b7fac1967c 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -26,6 +26,7 @@ export { hapiIntegration, setupHapiErrorHandler } from './integrations/tracing/h export { koaIntegration, setupKoaErrorHandler } from './integrations/tracing/koa'; export { connectIntegration, setupConnectErrorHandler } from './integrations/tracing/connect'; export { spotlightIntegration } from './integrations/spotlight'; +export { knexIntegration } from './integrations/tracing/knex'; export { SentryContextManager } from './otel/contextManager'; export { generateInstrumentOnce } from './otel/instrument'; diff --git a/packages/node/src/integrations/tracing/index.ts b/packages/node/src/integrations/tracing/index.ts index 886c11683674..08bae65132fe 100644 --- a/packages/node/src/integrations/tracing/index.ts +++ b/packages/node/src/integrations/tracing/index.ts @@ -6,6 +6,7 @@ import { expressIntegration, instrumentExpress } from './express'; import { fastifyIntegration, instrumentFastify } from './fastify'; import { graphqlIntegration, instrumentGraphql } from './graphql'; import { hapiIntegration, instrumentHapi } from './hapi'; +import { instrumentKnex, knexIntegration } from './knex'; import { instrumentKoa, koaIntegration } from './koa'; import { instrumentMongo, mongoIntegration } from './mongo'; import { instrumentMongoose, mongooseIntegration } from './mongoose'; @@ -37,6 +38,7 @@ export function getAutoPerformanceIntegrations(): Integration[] { hapiIntegration(), koaIntegration(), connectIntegration(), + knexIntegration(), ]; } @@ -61,5 +63,6 @@ export function getOpenTelemetryInstrumentationToPreload(): (((options?: any) => instrumentHapi, instrumentGraphql, instrumentRedis, + instrumentKnex, ]; } diff --git a/packages/node/src/integrations/tracing/knex.ts b/packages/node/src/integrations/tracing/knex.ts new file mode 100644 index 000000000000..310f4682b258 --- /dev/null +++ b/packages/node/src/integrations/tracing/knex.ts @@ -0,0 +1,35 @@ +import { KnexInstrumentation } from '@opentelemetry/instrumentation-knex'; +import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, spanToJSON } from '@sentry/core'; +import type { IntegrationFn } from '@sentry/types'; +import { generateInstrumentOnce } from '../../otel/instrument'; + +const INTEGRATION_NAME = 'Knex'; + +export const instrumentKnex = generateInstrumentOnce(INTEGRATION_NAME, () => new KnexInstrumentation({})); + +const _knexIntegration = (() => { + return { + name: INTEGRATION_NAME, + setupOnce() { + instrumentKnex(); + }, + + setup(client) { + client.on('spanStart', span => { + const spanJSON = spanToJSON(span); + + const spanDescription = spanJSON.description; + console.log('[Knex]: span description: ', spanDescription); + + span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.knex'); + }); + }, + }; +}) satisfies IntegrationFn; + +/** + * Knex integration + * + * Capture tracing data for Knex. + */ +export const knexIntegration = defineIntegration(_knexIntegration); diff --git a/yarn.lock b/yarn.lock index a1a060119a64..2fa66c85d38f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7148,6 +7148,14 @@ "@opentelemetry/redis-common" "^0.36.2" "@opentelemetry/semantic-conventions" "^1.23.0" +"@opentelemetry/instrumentation-knex@0.39.0": + version "0.39.0" + resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.39.0.tgz#1650615221056676f2ecb6c1654ae7977f0b24cc" + integrity sha512-lRwTqIKQecPWDkH1KEcAUcFhCaNssbKSpxf4sxRTAROCwrCEnYkjOuqJHV+q1/CApjMTaKu0Er4LBv/6bDpoxA== + dependencies: + "@opentelemetry/instrumentation" "^0.52.0" + "@opentelemetry/semantic-conventions" "^1.22.0" + "@opentelemetry/instrumentation-koa@0.42.0": version "0.42.0" resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.42.0.tgz#1c180f3605448c2e57a4ba073b69ffba7b2970b3" @@ -14472,6 +14480,11 @@ colord@^2.9.3: resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== +colorette@2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== + colorette@^2.0.10: version "2.0.20" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" @@ -14519,7 +14532,7 @@ commander@7.2.0, commander@^7.2.0: resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== -commander@^10.0.1: +commander@^10.0.0, commander@^10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== @@ -17977,7 +17990,7 @@ esm-env@^1.0.0: resolved "https://registry.yarnpkg.com/esm-env/-/esm-env-1.0.0.tgz#b124b40b180711690a4cb9b00d16573391950413" integrity sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA== -esm@^3.2.4: +esm@^3.2.25, esm@^3.2.4: version "3.2.25" resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== @@ -19314,6 +19327,11 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= +getopts@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4" + integrity sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA== + giget@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/giget/-/giget-1.2.3.tgz#ef6845d1140e89adad595f7f3bb60aa31c672cb6" @@ -20996,6 +21014,11 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== +interpret@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" + integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== + into-stream@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" @@ -22651,6 +22674,26 @@ klona@^2.0.4, klona@^2.0.5, klona@^2.0.6: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== +knex@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/knex/-/knex-2.5.1.tgz#a6c6b449866cf4229f070c17411f23871ba52ef9" + integrity sha512-z78DgGKUr4SE/6cm7ku+jHvFT0X97aERh/f0MUKAKgFnwCYBEW4TFBqtHWFYiJFid7fMrtpZ/gxJthvz5mEByA== + dependencies: + colorette "2.0.19" + commander "^10.0.0" + debug "4.3.4" + escalade "^3.1.1" + esm "^3.2.25" + get-package-type "^0.1.0" + getopts "2.3.0" + interpret "^2.2.0" + lodash "^4.17.21" + pg-connection-string "2.6.1" + rechoir "^0.8.0" + resolve-from "^5.0.0" + tarn "^3.0.2" + tildify "2.0.0" + knitwork@^1.0.0, knitwork@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/knitwork/-/knitwork-1.1.0.tgz#d8c9feafadd7ee744ff64340b216a52c7199c417" @@ -27048,6 +27091,11 @@ periscopic@^3.1.0: estree-walker "^3.0.0" is-reference "^3.0.0" +pg-connection-string@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.1.tgz#78c23c21a35dd116f48e12e23c0965e8d9e2cbfb" + integrity sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg== + pg-connection-string@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" @@ -28869,6 +28917,13 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" + redent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -31682,6 +31737,11 @@ tar@^6.2.0: mkdirp "^1.0.3" yallist "^4.0.0" +tarn@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.2.tgz#73b6140fbb881b71559c4f8bfde3d9a4b3d27693" + integrity sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ== + teeny-request@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-7.0.1.tgz#bdd41fdffea5f8fbc0d29392cb47bec4f66b2b4c" @@ -31886,6 +31946,11 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== +tildify@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tildify/-/tildify-2.0.0.tgz#f205f3674d677ce698b7067a99e949ce03b4754a" + integrity sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw== + timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" From e679a21a8b411c138e1cd44a73ccd2c4b7333bca Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Thu, 29 Aug 2024 13:14:36 -0400 Subject: [PATCH 2/8] test(node): Add tests for knexIntegration Set up postgres for testing. Update span attributes to be named under 'knex'. Signed-off-by: Kaung Zin Hein --- .../suites/tracing/knex/docker-compose.yml | 13 ++++ .../suites/tracing/knex/scenario.js | 63 +++++++++++++++ .../suites/tracing/knex/test.ts | 77 +++++++++++++++++++ .../node/src/integrations/tracing/knex.ts | 8 +- 4 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/knex/docker-compose.yml create mode 100644 dev-packages/node-integration-tests/suites/tracing/knex/scenario.js create mode 100644 dev-packages/node-integration-tests/suites/tracing/knex/test.ts diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/docker-compose.yml b/dev-packages/node-integration-tests/suites/tracing/knex/docker-compose.yml new file mode 100644 index 000000000000..b586c8c6175a --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/knex/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3.9' + +services: + db: + image: postgres:13 + restart: always + container_name: integration-tests-knex + ports: + - '5445:5432' + environment: + POSTGRES_USER: test + POSTGRES_PASSWORD: test + POSTGRES_DB: tests diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/scenario.js b/dev-packages/node-integration-tests/suites/tracing/knex/scenario.js new file mode 100644 index 000000000000..03ad8e7e5f27 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/knex/scenario.js @@ -0,0 +1,63 @@ +const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +const Sentry = require('@sentry/node'); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); + +// Stop the process from exiting before the transaction is sent +setInterval(() => {}, 1000); + +const knex = require('knex').default; + +async function run() { + await Sentry.startSpan( + { + name: 'Test Transaction', + op: 'transaction', + }, + async () => { + try { + const pgKnex = knex({ + client: 'pg', + connection: { + host: 'localhost', + port: 5445, + user: 'test', + password: 'test', + database: 'tests', + }, + }); + + await pgKnex.schema.createTable('User', table => { + table.increments('id').notNullable().primary({ constraintName: 'User_pkey' }); + table.timestamp('createdAt', { precision: 3 }).notNullable().defaultTo(pgKnex.fn.now(3)); + table.text('email').notNullable(); + table.text('name').notNullable(); + }); + + await pgKnex('User').insert({ name: 'bob', email: 'bob@domain.com' }); + await pgKnex('User').select('*'); + // await client + // .query( + // 'CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id"));', + // ) + // .catch(() => { + // // if this is not a fresh database, the table might already exist + // }); + + // await client.query(''); + // await client.query('INSERT INTO "User" ("email", "name") VALUES ($1, $2)', ['tim', 'tim@domain.com']); + // await client.query('SELECT * FROM "User"'); + } finally { + // await client.end(); + } + }, + ); +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/test.ts b/dev-packages/node-integration-tests/suites/tracing/knex/test.ts new file mode 100644 index 000000000000..9f4892a28311 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/knex/test.ts @@ -0,0 +1,77 @@ +import { createRunner } from '../../../utils/runner'; + +jest.setTimeout(75000); + +describe('knex auto instrumentation', () => { + test('should auto-instrument `knex` package', done => { + const EXPECTED_TRANSACTION = { + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'knex', + 'db.name': 'tests', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + 'net.peer.name': 'localhost', + 'net.peer.port': 5445, + }), + status: 'ok', + description: 'pg.connect', + origin: 'auto.db.otel.knex', + }), + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'knex', + 'db.name': 'tests', + 'db.statement': + 'create table "User" ("id" serial primary key, "createdAt" timestamptz(3) not null default CURRENT_TIMESTAMP(3), "email" text not null, "name" text not null)', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + 'net.peer.name': 'localhost', + 'net.peer.port': 5445, + }), + status: 'ok', + description: + 'create table "User" ("id" serial primary key, "createdAt" timestamptz(3) not null default CURRENT_TIMESTAMP(3), "email" text not null, "name" text not null)', + origin: 'auto.db.otel.knex', + }), + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'knex', + 'db.name': 'tests', + 'db.statement': 'insert into "User" ("email", "name") values (?, ?)', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + 'net.peer.name': 'localhost', + 'net.peer.port': 5445, + }), + status: 'ok', + // In the otel spans, the placeholders (e.g., `$1`) are replaced by a `?`. + description: 'insert into "User" ("email", "name") values (?, ?)', + origin: 'auto.db.otel.knex', + }), + + expect.objectContaining({ + data: expect.objectContaining({ + 'db.operation': 'select', + 'db.sql.table': 'User', + 'db.system': 'knex', + 'db.name': 'tests', + 'db.statement': 'select * from "User"', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + }), + status: 'ok', + description: 'select * from "User"', + origin: 'auto.db.otel.knex', + }), + ]), + }; + + createRunner(__dirname, 'scenario.js') + .withDockerCompose({ workingDirectory: [__dirname], readyMatches: ['port 5432'] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start(done); + }); +}); diff --git a/packages/node/src/integrations/tracing/knex.ts b/packages/node/src/integrations/tracing/knex.ts index 310f4682b258..247bd3b20ea1 100644 --- a/packages/node/src/integrations/tracing/knex.ts +++ b/packages/node/src/integrations/tracing/knex.ts @@ -1,5 +1,5 @@ import { KnexInstrumentation } from '@opentelemetry/instrumentation-knex'; -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, spanToJSON } from '@sentry/core'; +import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration } from '@sentry/core'; import type { IntegrationFn } from '@sentry/types'; import { generateInstrumentOnce } from '../../otel/instrument'; @@ -16,12 +16,8 @@ const _knexIntegration = (() => { setup(client) { client.on('spanStart', span => { - const spanJSON = spanToJSON(span); - - const spanDescription = spanJSON.description; - console.log('[Knex]: span description: ', spanDescription); - span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.knex'); + span.setAttribute('db.system', 'knex'); }); }, }; From 36d425fcb55ebcdb6f4fbd2c29c19fe43a8e0bcb Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Thu, 29 Aug 2024 21:00:55 -0400 Subject: [PATCH 3/8] fix(node): Update integration to identify knex spans Differentiate knex spans from other database spans. Signed-off-by: Kaung Zin Hein --- .../suites/tracing/knex/scenario.js | 43 +++++++------------ .../suites/tracing/knex/test.ts | 13 ------ .../node/src/integrations/tracing/knex.ts | 16 +++++-- 3 files changed, 28 insertions(+), 44 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/scenario.js b/dev-packages/node-integration-tests/suites/tracing/knex/scenario.js index 03ad8e7e5f27..2041554a0fdd 100644 --- a/dev-packages/node-integration-tests/suites/tracing/knex/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/knex/scenario.js @@ -13,6 +13,17 @@ setInterval(() => {}, 1000); const knex = require('knex').default; +const pgClient = knex({ + client: 'pg', + connection: { + host: 'localhost', + port: 5445, + user: 'test', + password: 'test', + database: 'tests', + }, +}); + async function run() { await Sentry.startSpan( { @@ -21,39 +32,17 @@ async function run() { }, async () => { try { - const pgKnex = knex({ - client: 'pg', - connection: { - host: 'localhost', - port: 5445, - user: 'test', - password: 'test', - database: 'tests', - }, - }); - - await pgKnex.schema.createTable('User', table => { + await pgClient.schema.createTable('User', table => { table.increments('id').notNullable().primary({ constraintName: 'User_pkey' }); - table.timestamp('createdAt', { precision: 3 }).notNullable().defaultTo(pgKnex.fn.now(3)); + table.timestamp('createdAt', { precision: 3 }).notNullable().defaultTo(pgClient.fn.now(3)); table.text('email').notNullable(); table.text('name').notNullable(); }); - await pgKnex('User').insert({ name: 'bob', email: 'bob@domain.com' }); - await pgKnex('User').select('*'); - // await client - // .query( - // 'CREATE TABLE "User" ("id" SERIAL NOT NULL,"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,"email" TEXT NOT NULL,"name" TEXT,CONSTRAINT "User_pkey" PRIMARY KEY ("id"));', - // ) - // .catch(() => { - // // if this is not a fresh database, the table might already exist - // }); - - // await client.query(''); - // await client.query('INSERT INTO "User" ("email", "name") VALUES ($1, $2)', ['tim', 'tim@domain.com']); - // await client.query('SELECT * FROM "User"'); + await pgClient('User').insert({ name: 'bob', email: 'bob@domain.com' }); + await pgClient('User').select('*'); } finally { - // await client.end(); + await pgClient.destroy(); } }, ); diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/test.ts b/dev-packages/node-integration-tests/suites/tracing/knex/test.ts index 9f4892a28311..fe1c55046d64 100644 --- a/dev-packages/node-integration-tests/suites/tracing/knex/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/knex/test.ts @@ -7,19 +7,6 @@ describe('knex auto instrumentation', () => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction', spans: expect.arrayContaining([ - expect.objectContaining({ - data: expect.objectContaining({ - 'db.system': 'knex', - 'db.name': 'tests', - 'sentry.origin': 'auto.db.otel.knex', - 'sentry.op': 'db', - 'net.peer.name': 'localhost', - 'net.peer.port': 5445, - }), - status: 'ok', - description: 'pg.connect', - origin: 'auto.db.otel.knex', - }), expect.objectContaining({ data: expect.objectContaining({ 'db.system': 'knex', diff --git a/packages/node/src/integrations/tracing/knex.ts b/packages/node/src/integrations/tracing/knex.ts index 247bd3b20ea1..8311e9c84e79 100644 --- a/packages/node/src/integrations/tracing/knex.ts +++ b/packages/node/src/integrations/tracing/knex.ts @@ -1,11 +1,14 @@ import { KnexInstrumentation } from '@opentelemetry/instrumentation-knex'; -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration } from '@sentry/core'; +import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, spanToJSON } from '@sentry/core'; import type { IntegrationFn } from '@sentry/types'; import { generateInstrumentOnce } from '../../otel/instrument'; const INTEGRATION_NAME = 'Knex'; -export const instrumentKnex = generateInstrumentOnce(INTEGRATION_NAME, () => new KnexInstrumentation({})); +export const instrumentKnex = generateInstrumentOnce( + INTEGRATION_NAME, + () => new KnexInstrumentation({ requireParentSpan: true }), +); const _knexIntegration = (() => { return { @@ -16,8 +19,13 @@ const _knexIntegration = (() => { setup(client) { client.on('spanStart', span => { - span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.knex'); - span.setAttribute('db.system', 'knex'); + const spanJSON = spanToJSON(span); + const spanData = spanJSON.data; + + if (spanData && 'knex.version' in spanData) { + span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.knex'); + span.setAttribute('db.system', 'knex'); + } }); }, }; From b40cdadd211aac29c963c6fb4a270f33cf4a627a Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Thu, 29 Aug 2024 22:59:34 -0400 Subject: [PATCH 4/8] fix(e2e): Update exports for node-exports-test-app Signed-off-by: Kaung Zin Hein --- packages/astro/src/index.server.ts | 1 + packages/aws-serverless/src/index.ts | 1 + packages/bun/src/index.ts | 1 + packages/google-cloud-serverless/src/index.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/packages/astro/src/index.server.ts b/packages/astro/src/index.server.ts index be3f002dcbb8..bd4afcd4f0cc 100644 --- a/packages/astro/src/index.server.ts +++ b/packages/astro/src/index.server.ts @@ -65,6 +65,7 @@ export { initOpenTelemetry, isInitialized, koaIntegration, + knexIntegration, lastEventId, linkedErrorsIntegration, localVariablesIntegration, diff --git a/packages/aws-serverless/src/index.ts b/packages/aws-serverless/src/index.ts index 7b05f8df3a86..73de78bd931e 100644 --- a/packages/aws-serverless/src/index.ts +++ b/packages/aws-serverless/src/index.ts @@ -88,6 +88,7 @@ export { fastifyIntegration, fsIntegration, graphqlIntegration, + knexIntegration, mongoIntegration, mongooseIntegration, mysqlIntegration, diff --git a/packages/bun/src/index.ts b/packages/bun/src/index.ts index e49e4163af31..3e7200e407ff 100644 --- a/packages/bun/src/index.ts +++ b/packages/bun/src/index.ts @@ -109,6 +109,7 @@ export { connectIntegration, setupConnectErrorHandler, graphqlIntegration, + knexIntegration, mongoIntegration, mongooseIntegration, mysqlIntegration, diff --git a/packages/google-cloud-serverless/src/index.ts b/packages/google-cloud-serverless/src/index.ts index 9a501307e79f..84b86e6f8b8b 100644 --- a/packages/google-cloud-serverless/src/index.ts +++ b/packages/google-cloud-serverless/src/index.ts @@ -88,6 +88,7 @@ export { setupConnectErrorHandler, fastifyIntegration, graphqlIntegration, + knexIntegration, mongoIntegration, mongooseIntegration, mysqlIntegration, From 08a6d6d2c7ce5fa22db814634212e84eca65a2c2 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Fri, 30 Aug 2024 11:24:40 -0400 Subject: [PATCH 5/8] test(node): Add more db client tests Add mysql2 client tests using knex. Add `knexIntegration` exports in several packages. Signed-off-by: Kaung Zin Hein --- .../suites/tracing/knex/docker-compose.yml | 14 +++- .../tracing/knex/scenario-withMysql2.js | 52 ++++++++++++++ .../{scenario.js => scenario-withPostgres.js} | 0 .../suites/tracing/knex/test.ts | 70 +++++++++++++++++-- packages/remix/src/index.server.ts | 1 + packages/solidstart/src/server/index.ts | 1 + packages/sveltekit/src/server/index.ts | 1 + 7 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/tracing/knex/scenario-withMysql2.js rename dev-packages/node-integration-tests/suites/tracing/knex/{scenario.js => scenario-withPostgres.js} (100%) diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/docker-compose.yml b/dev-packages/node-integration-tests/suites/tracing/knex/docker-compose.yml index b586c8c6175a..50eb7bc94237 100644 --- a/dev-packages/node-integration-tests/suites/tracing/knex/docker-compose.yml +++ b/dev-packages/node-integration-tests/suites/tracing/knex/docker-compose.yml @@ -1,13 +1,23 @@ version: '3.9' services: - db: + db_postgres: image: postgres:13 restart: always - container_name: integration-tests-knex + container_name: integration-tests-knex-postgres ports: - '5445:5432' environment: POSTGRES_USER: test POSTGRES_PASSWORD: test POSTGRES_DB: tests + + db_mysql2: + image: mysql:8 + restart: always + container_name: integration-tests-knex-mysql2 + ports: + - '3307:3306' + environment: + MYSQL_ROOT_PASSWORD: docker + MYSQL_DATABASE: tests diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withMysql2.js b/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withMysql2.js new file mode 100644 index 000000000000..4d229c6a05b6 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withMysql2.js @@ -0,0 +1,52 @@ +const { loggingTransport } = require('@sentry-internal/node-integration-tests'); +const Sentry = require('@sentry/node'); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + tracesSampleRate: 1.0, + transport: loggingTransport, +}); + +// Stop the process from exiting before the transaction is sent +setInterval(() => {}, 1000); + +const knex = require('knex').default; + +const mysql2Client = knex({ + client: 'mysql2', + connection: { + host: 'localhost', + port: 3307, + user: 'root', + password: 'docker', + database: 'tests', + }, +}); + +async function run() { + await Sentry.startSpan( + { + name: 'Test Transaction', + op: 'transaction', + }, + async () => { + try { + await mysql2Client.schema.createTable('User', table => { + table.increments('id').notNullable().primary({ constraintName: 'User_pkey' }); + table.timestamp('createdAt', { precision: 3 }).notNullable().defaultTo(mysql2Client.fn.now(3)); + table.text('email').notNullable(); + table.text('name').notNullable(); + }); + + await mysql2Client('User').insert({ name: 'jane', email: 'jane@domain.com' }); + await mysql2Client('User').select('*'); + } finally { + await mysql2Client.destroy(); + } + }, + ); +} + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/scenario.js b/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withPostgres.js similarity index 100% rename from dev-packages/node-integration-tests/suites/tracing/knex/scenario.js rename to dev-packages/node-integration-tests/suites/tracing/knex/scenario-withPostgres.js diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/test.ts b/dev-packages/node-integration-tests/suites/tracing/knex/test.ts index fe1c55046d64..94469d13dcf1 100644 --- a/dev-packages/node-integration-tests/suites/tracing/knex/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/knex/test.ts @@ -1,9 +1,10 @@ import { createRunner } from '../../../utils/runner'; -jest.setTimeout(75000); +// When running docker compose, we need a larger timeout, as this takes some time... +jest.setTimeout(90000); describe('knex auto instrumentation', () => { - test('should auto-instrument `knex` package', done => { + test('should auto-instrument `knex` package when using `pg` client', done => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction', spans: expect.arrayContaining([ @@ -11,8 +12,6 @@ describe('knex auto instrumentation', () => { data: expect.objectContaining({ 'db.system': 'knex', 'db.name': 'tests', - 'db.statement': - 'create table "User" ("id" serial primary key, "createdAt" timestamptz(3) not null default CURRENT_TIMESTAMP(3), "email" text not null, "name" text not null)', 'sentry.origin': 'auto.db.otel.knex', 'sentry.op': 'db', 'net.peer.name': 'localhost', @@ -27,14 +26,13 @@ describe('knex auto instrumentation', () => { data: expect.objectContaining({ 'db.system': 'knex', 'db.name': 'tests', - 'db.statement': 'insert into "User" ("email", "name") values (?, ?)', 'sentry.origin': 'auto.db.otel.knex', 'sentry.op': 'db', 'net.peer.name': 'localhost', 'net.peer.port': 5445, }), status: 'ok', - // In the otel spans, the placeholders (e.g., `$1`) are replaced by a `?`. + // In the knex-otel spans, the placeholders (e.g., `$1`) are replaced by a `?`. description: 'insert into "User" ("email", "name") values (?, ?)', origin: 'auto.db.otel.knex', }), @@ -56,9 +54,67 @@ describe('knex auto instrumentation', () => { ]), }; - createRunner(__dirname, 'scenario.js') + createRunner(__dirname, 'scenario-withPostgres.js') .withDockerCompose({ workingDirectory: [__dirname], readyMatches: ['port 5432'] }) .expect({ transaction: EXPECTED_TRANSACTION }) .start(done); }); + + test('should auto-instrument `knex` package when using `mysql2` client', done => { + const EXPECTED_TRANSACTION = { + transaction: 'Test Transaction', + spans: expect.arrayContaining([ + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'knex', + 'db.name': 'tests', + 'db.user': 'root', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + 'net.peer.name': 'localhost', + 'net.peer.port': 3307, + }), + status: 'ok', + description: + 'create table `User` (`id` int unsigned not null auto_increment primary key, `createdAt` timestamp(3) not null default CURRENT_TIMESTAMP(3), `email` text not null, `name` text not null)', + origin: 'auto.db.otel.knex', + }), + expect.objectContaining({ + data: expect.objectContaining({ + 'db.system': 'knex', + 'db.name': 'tests', + 'db.user': 'root', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + 'net.peer.name': 'localhost', + 'net.peer.port': 3307, + }), + status: 'ok', + description: 'insert into `User` (`email`, `name`) values (?, ?)', + origin: 'auto.db.otel.knex', + }), + + expect.objectContaining({ + data: expect.objectContaining({ + 'db.operation': 'select', + 'db.sql.table': 'User', + 'db.system': 'knex', + 'db.name': 'tests', + 'db.statement': 'select * from `User`', + 'db.user': 'root', + 'sentry.origin': 'auto.db.otel.knex', + 'sentry.op': 'db', + }), + status: 'ok', + description: 'select * from `User`', + origin: 'auto.db.otel.knex', + }), + ]), + }; + + createRunner(__dirname, 'scenario-withMysql2.js') + .withDockerCompose({ workingDirectory: [__dirname], readyMatches: ['port: 3306'] }) + .expect({ transaction: EXPECTED_TRANSACTION }) + .start(done); + }); }); diff --git a/packages/remix/src/index.server.ts b/packages/remix/src/index.server.ts index 7ab6efb15827..9aeb75a5d96a 100644 --- a/packages/remix/src/index.server.ts +++ b/packages/remix/src/index.server.ts @@ -66,6 +66,7 @@ export { inboundFiltersIntegration, initOpenTelemetry, isInitialized, + knexIntegration, koaIntegration, lastEventId, linkedErrorsIntegration, diff --git a/packages/solidstart/src/server/index.ts b/packages/solidstart/src/server/index.ts index c3499a82459a..c4e4eb9bb893 100644 --- a/packages/solidstart/src/server/index.ts +++ b/packages/solidstart/src/server/index.ts @@ -57,6 +57,7 @@ export { inboundFiltersIntegration, initOpenTelemetry, isInitialized, + knexIntegration, koaIntegration, lastEventId, linkedErrorsIntegration, diff --git a/packages/sveltekit/src/server/index.ts b/packages/sveltekit/src/server/index.ts index 32dd6627d7a6..623e0fcec02e 100644 --- a/packages/sveltekit/src/server/index.ts +++ b/packages/sveltekit/src/server/index.ts @@ -59,6 +59,7 @@ export { inboundFiltersIntegration, initOpenTelemetry, isInitialized, + knexIntegration, koaIntegration, lastEventId, linkedErrorsIntegration, From 8c04ae83d692d2afa196b523dc88c32b0864b31b Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Thu, 7 Nov 2024 10:22:07 -0500 Subject: [PATCH 6/8] clean up integration --- .../node/src/integrations/tracing/index.ts | 1 - .../node/src/integrations/tracing/knex.ts | 20 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/node/src/integrations/tracing/index.ts b/packages/node/src/integrations/tracing/index.ts index 5ca6c3f4ff90..1a1b8835011d 100644 --- a/packages/node/src/integrations/tracing/index.ts +++ b/packages/node/src/integrations/tracing/index.ts @@ -8,7 +8,6 @@ import { fastifyIntegration, instrumentFastify } from './fastify'; import { genericPoolIntegration, instrumentGenericPool } from './genericPool'; import { graphqlIntegration, instrumentGraphql } from './graphql'; import { hapiIntegration, instrumentHapi } from './hapi'; -import { instrumentKnex, knexIntegration } from './knex'; import { instrumentKafka, kafkaIntegration } from './kafka'; import { instrumentKoa, koaIntegration } from './koa'; import { instrumentLruMemoizer, lruMemoizerIntegration } from './lrumemoizer'; diff --git a/packages/node/src/integrations/tracing/knex.ts b/packages/node/src/integrations/tracing/knex.ts index 8311e9c84e79..55457680e101 100644 --- a/packages/node/src/integrations/tracing/knex.ts +++ b/packages/node/src/integrations/tracing/knex.ts @@ -19,12 +19,11 @@ const _knexIntegration = (() => { setup(client) { client.on('spanStart', span => { - const spanJSON = spanToJSON(span); - const spanData = spanJSON.data; - - if (spanData && 'knex.version' in spanData) { + const { data } = spanToJSON(span); + // knex.version is always set in the span data + // https://github.com/open-telemetry/opentelemetry-js-contrib/blob/0309caeafc44ac9cb13a3345b790b01b76d0497d/plugins/node/opentelemetry-instrumentation-knex/src/instrumentation.ts#L138 + if (data && 'knex.version' in data) { span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.knex'); - span.setAttribute('db.system', 'knex'); } }); }, @@ -34,6 +33,15 @@ const _knexIntegration = (() => { /** * Knex integration * - * Capture tracing data for Knex. + * Capture tracing data for [Knex](https://knexjs.org/). + * + * @example + * ```javascript + * import * as Sentry from '@sentry/node'; + * + * Sentry.init({ + * integrations: [Sentry.knexIntegration()], + * }); + * ``` */ export const knexIntegration = defineIntegration(_knexIntegration); From eb3902d81742b75c219e866d1c61b4a8bdacc16b Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 11 Nov 2024 09:18:47 -0500 Subject: [PATCH 7/8] fix merge conflict in yarn.lock --- yarn.lock | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 66f965b8361d..67947a3976c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -31531,12 +31531,11 @@ tar@^6.2.0: mkdirp "^1.0.3" yallist "^4.0.0" -<<<<<<< HEAD tarn@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.2.tgz#73b6140fbb881b71559c4f8bfde3d9a4b3d27693" integrity sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ== -======= + tedious@^18.6.1: version "18.6.1" resolved "https://registry.yarnpkg.com/tedious/-/tedious-18.6.1.tgz#1c4a3f06c891be67a032117e2e25193286d44496" @@ -31552,7 +31551,6 @@ tedious@^18.6.1: js-md4 "^0.3.2" native-duplexpair "^1.0.0" sprintf-js "^1.1.3" ->>>>>>> develop teeny-request@^7.0.0: version "7.0.1" From a943bbe65dca6ddf9e06fbc7e41005b54451fc39 Mon Sep 17 00:00:00 2001 From: Kaung Zin Hein Date: Mon, 11 Nov 2024 10:55:52 -0500 Subject: [PATCH 8/8] test(node): Fix tests after latest change Signed-off-by: Kaung Zin Hein --- .../tracing/knex/scenario-withMysql2.js | 1 + .../tracing/knex/scenario-withPostgres.js | 1 + .../suites/tracing/knex/test.ts | 21 +++++++++++++------ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withMysql2.js b/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withMysql2.js index 4d229c6a05b6..5d57e38d9318 100644 --- a/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withMysql2.js +++ b/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withMysql2.js @@ -6,6 +6,7 @@ Sentry.init({ release: '1.0', tracesSampleRate: 1.0, transport: loggingTransport, + integrations: [Sentry.knexIntegration()], }); // Stop the process from exiting before the transaction is sent diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withPostgres.js b/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withPostgres.js index 2041554a0fdd..a9f2d558a618 100644 --- a/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withPostgres.js +++ b/dev-packages/node-integration-tests/suites/tracing/knex/scenario-withPostgres.js @@ -6,6 +6,7 @@ Sentry.init({ release: '1.0', tracesSampleRate: 1.0, transport: loggingTransport, + integrations: [Sentry.knexIntegration()], }); // Stop the process from exiting before the transaction is sent diff --git a/dev-packages/node-integration-tests/suites/tracing/knex/test.ts b/dev-packages/node-integration-tests/suites/tracing/knex/test.ts index 94469d13dcf1..3ededda4f162 100644 --- a/dev-packages/node-integration-tests/suites/tracing/knex/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/knex/test.ts @@ -4,13 +4,17 @@ import { createRunner } from '../../../utils/runner'; jest.setTimeout(90000); describe('knex auto instrumentation', () => { + // Update this if another knex version is installed + const KNEX_VERSION = '2.5.1'; + test('should auto-instrument `knex` package when using `pg` client', done => { const EXPECTED_TRANSACTION = { transaction: 'Test Transaction', spans: expect.arrayContaining([ expect.objectContaining({ data: expect.objectContaining({ - 'db.system': 'knex', + 'knex.version': KNEX_VERSION, + 'db.system': 'postgresql', 'db.name': 'tests', 'sentry.origin': 'auto.db.otel.knex', 'sentry.op': 'db', @@ -24,7 +28,8 @@ describe('knex auto instrumentation', () => { }), expect.objectContaining({ data: expect.objectContaining({ - 'db.system': 'knex', + 'knex.version': KNEX_VERSION, + 'db.system': 'postgresql', 'db.name': 'tests', 'sentry.origin': 'auto.db.otel.knex', 'sentry.op': 'db', @@ -39,9 +44,10 @@ describe('knex auto instrumentation', () => { expect.objectContaining({ data: expect.objectContaining({ + 'knex.version': KNEX_VERSION, 'db.operation': 'select', 'db.sql.table': 'User', - 'db.system': 'knex', + 'db.system': 'postgresql', 'db.name': 'tests', 'db.statement': 'select * from "User"', 'sentry.origin': 'auto.db.otel.knex', @@ -66,7 +72,8 @@ describe('knex auto instrumentation', () => { spans: expect.arrayContaining([ expect.objectContaining({ data: expect.objectContaining({ - 'db.system': 'knex', + 'knex.version': KNEX_VERSION, + 'db.system': 'mysql2', 'db.name': 'tests', 'db.user': 'root', 'sentry.origin': 'auto.db.otel.knex', @@ -81,7 +88,8 @@ describe('knex auto instrumentation', () => { }), expect.objectContaining({ data: expect.objectContaining({ - 'db.system': 'knex', + 'knex.version': KNEX_VERSION, + 'db.system': 'mysql2', 'db.name': 'tests', 'db.user': 'root', 'sentry.origin': 'auto.db.otel.knex', @@ -96,9 +104,10 @@ describe('knex auto instrumentation', () => { expect.objectContaining({ data: expect.objectContaining({ + 'knex.version': KNEX_VERSION, 'db.operation': 'select', 'db.sql.table': 'User', - 'db.system': 'knex', + 'db.system': 'mysql2', 'db.name': 'tests', 'db.statement': 'select * from `User`', 'db.user': 'root',