Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as Sentry from '@sentry/node';
import mysql from 'mysql';

const connection = mysql.createConnection({
user: 'root',
password: 'docker',
});

connection.connect(function (err) {
if (err) {
return;
}
});

Sentry.startSpanManual(
{
op: 'transaction',
name: 'Test Transaction',
},
span => {
const query = connection.query('SELECT 1 + 1 AS solution');

query.on('end', () => {
// A span started from inside a stream listener should be a child of the parent context that was
// active when the query was issued (the transaction here), not of the query span itself. This
// verifies the instrumentation re-binds the streamed query's events to the parent context.
Sentry.startSpan({ name: 'listener-child' }, () => {
// noop
});

setTimeout(() => {
span.end();
connection.end();
}, 500);
});
},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as Sentry from '@sentry/node';
import mysql from 'mysql';

const connection = mysql.createConnection({
user: 'root',
password: 'docker',
});

connection.connect(function (err) {
if (err) {
return;
}
});

Sentry.startSpanManual(
{
op: 'transaction',
name: 'Test Transaction',
},
span => {
// Query without a callback returns a streamable `Query`. A failing query emits an `error` event
// (which sets the span status) followed by `end` (which ends the span).
const query = connection.query('SELECT * FROM does_not_exist');

// Swallow the error so it doesn't crash the process
query.on('error', () => {
// noop
});

query.on('end', () => {
// Wait a bit to ensure the query span has been finished
setTimeout(() => {
span.end();
connection.end();
}, 500);
});
},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as Sentry from '@sentry/node';
import mysql from 'mysql';

const pool = mysql.createPool({
user: 'root',
password: 'docker',
});

Sentry.startSpanManual(
{
op: 'transaction',
name: 'Test Transaction',
},
span => {
pool.query('SELECT 1 + 1 AS solution', function () {
pool.query('SELECT NOW()', ['1', '2'], () => {
span.end();
pool.end();
});
});
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
expect.objectContaining({
description: 'SELECT 1 + 1 AS solution',
op: 'db',
origin: 'auto.db.otel.mysql',
data: expect.objectContaining({
'sentry.origin': 'auto.db.otel.mysql',
'db.system': 'mysql',
'net.peer.name': 'localhost',
'net.peer.port': 3306,
Expand All @@ -22,7 +24,9 @@
expect.objectContaining({
description: 'SELECT NOW()',
op: 'db',
origin: 'auto.db.otel.mysql',
data: expect.objectContaining({
'sentry.origin': 'auto.db.otel.mysql',
'db.system': 'mysql',
'net.peer.name': 'localhost',
'net.peer.port': 3306,
Expand Down Expand Up @@ -73,4 +77,83 @@
{ failsOnEsm: true },
);
});

describe('with createPool()', () => {
createEsmAndCjsTests(
__dirname,
'scenario-withPool.mjs',
'instrument.mjs',
(createTestRunner, test) => {
test('should auto-instrument `mysql` package when querying through a pool', async () => {
await createTestRunner().expect({ transaction: EXPECTED_TRANSACTION }).start().completed();
});
},
{ failsOnEsm: true },
);
});

describe('streamed query error', () => {
const EXPECTED_ERROR_TRANSACTION = {
transaction: 'Test Transaction',
spans: expect.arrayContaining([
expect.objectContaining({
description: 'SELECT * FROM does_not_exist',
op: 'db',
origin: 'auto.db.otel.mysql',
// A failing streamed query emits `error`, which marks the span as errored
status: 'internal_error',
data: expect.objectContaining({
'sentry.origin': 'auto.db.otel.mysql',
'db.system': 'mysql',
'db.user': 'root',
}),
}),
]),
};

createEsmAndCjsTests(
__dirname,
'scenario-streamError.mjs',
'instrument.mjs',
(createTestRunner, test) => {
test('should mark the span as errored when a streamed query fails', async () => {
await createTestRunner().expect({ transaction: EXPECTED_ERROR_TRANSACTION }).start().completed();
});
},
{ failsOnEsm: true },
);
});

describe('streamed query listener context', () => {
createEsmAndCjsTests(
__dirname,
'scenario-streamContext.mjs',
'instrument.mjs',
(createTestRunner, test) => {
test('should run streamed query listeners with the parent context active', async () => {
await createTestRunner()
.expect({
transaction: (transaction): void => {
const transactionSpanId = transaction.contexts?.trace?.span_id;
const spans = transaction.spans ?? [];
const mysqlSpan = spans.find(span => span.description === 'SELECT 1 + 1 AS solution');
const listenerSpan = spans.find(span => span.description === 'listener-child');

expect(transactionSpanId).toBeDefined();
expect(mysqlSpan).toBeDefined();

Check failure on line 143 in dev-packages/node-integration-tests/suites/tracing/mysql/test.ts

View workflow job for this annotation

GitHub Actions / Node (24) Integration Tests

suites/tracing/mysql/test.ts > mysql auto instrumentation > streamed query listener context > esm/cjs > cjs > should run streamed query listeners with the parent context active

AssertionError: expected undefined to be defined ❯ transaction suites/tracing/mysql/test.ts:143:35 ❯ expectTransactionEvent utils/runner.ts:797:5 ❯ newEnvelope utils/runner.ts:520:15 ❯ tryParseEnvelopeFromStdoutLine utils/runner.ts:663:15 ❯ Socket.<anonymous> utils/runner.ts:681:15

Check failure on line 143 in dev-packages/node-integration-tests/suites/tracing/mysql/test.ts

View workflow job for this annotation

GitHub Actions / Node (18) Integration Tests

suites/tracing/mysql/test.ts > mysql auto instrumentation > streamed query listener context > esm/cjs > cjs > should run streamed query listeners with the parent context active

AssertionError: expected undefined to be defined ❯ transaction suites/tracing/mysql/test.ts:143:35 ❯ expectTransactionEvent utils/runner.ts:797:5 ❯ newEnvelope utils/runner.ts:520:15 ❯ tryParseEnvelopeFromStdoutLine utils/runner.ts:663:15 ❯ Socket.<anonymous> utils/runner.ts:681:15

Check failure on line 143 in dev-packages/node-integration-tests/suites/tracing/mysql/test.ts

View workflow job for this annotation

GitHub Actions / Node (26) Integration Tests

suites/tracing/mysql/test.ts > mysql auto instrumentation > streamed query listener context > esm/cjs > cjs > should run streamed query listeners with the parent context active

AssertionError: expected undefined to be defined ❯ transaction suites/tracing/mysql/test.ts:143:35 ❯ expectTransactionEvent utils/runner.ts:797:5 ❯ newEnvelope utils/runner.ts:520:15 ❯ tryParseEnvelopeFromStdoutLine utils/runner.ts:663:15 ❯ Socket.<anonymous> utils/runner.ts:681:15

Check failure on line 143 in dev-packages/node-integration-tests/suites/tracing/mysql/test.ts

View workflow job for this annotation

GitHub Actions / Node (22) Integration Tests

suites/tracing/mysql/test.ts > mysql auto instrumentation > streamed query listener context > esm/cjs > cjs > should run streamed query listeners with the parent context active

AssertionError: expected undefined to be defined ❯ transaction suites/tracing/mysql/test.ts:143:35 ❯ expectTransactionEvent utils/runner.ts:797:5 ❯ newEnvelope utils/runner.ts:520:15 ❯ tryParseEnvelopeFromStdoutLine utils/runner.ts:663:15 ❯ Socket.<anonymous> utils/runner.ts:681:15

Check failure on line 143 in dev-packages/node-integration-tests/suites/tracing/mysql/test.ts

View workflow job for this annotation

GitHub Actions / Node (20) Integration Tests

suites/tracing/mysql/test.ts > mysql auto instrumentation > streamed query listener context > esm/cjs > cjs > should run streamed query listeners with the parent context active

AssertionError: expected undefined to be defined ❯ transaction suites/tracing/mysql/test.ts:143:35 ❯ expectTransactionEvent utils/runner.ts:797:5 ❯ newEnvelope utils/runner.ts:520:15 ❯ tryParseEnvelopeFromStdoutLine utils/runner.ts:663:15 ❯ Socket.<anonymous> utils/runner.ts:681:15

Check failure on line 143 in dev-packages/node-integration-tests/suites/tracing/mysql/test.ts

View workflow job for this annotation

GitHub Actions / Node (24) (TS 3.8) Integration Tests

suites/tracing/mysql/test.ts > mysql auto instrumentation > streamed query listener context > esm/cjs > cjs > should run streamed query listeners with the parent context active

AssertionError: expected undefined to be defined ❯ transaction suites/tracing/mysql/test.ts:143:35 ❯ expectTransactionEvent utils/runner.ts:797:5 ❯ newEnvelope utils/runner.ts:520:15 ❯ tryParseEnvelopeFromStdoutLine utils/runner.ts:663:15 ❯ Socket.<anonymous> utils/runner.ts:681:15
expect(listenerSpan).toBeDefined();

// The span created inside the stream `end` listener is parented to the transaction
// (the context active when the query was issued), not to the query span.
expect(listenerSpan?.parent_span_id).toBe(transactionSpanId);
expect(listenerSpan?.parent_span_id).not.toBe(mysqlSpan?.span_id);
},
})
.start()
.completed();
});
},
{ failsOnEsm: true },
);
});
});

This file was deleted.

Loading
Loading