Skip to content

Commit a1934b4

Browse files
kamilogoreklobsterkatieHazAT
authored
feat: MySQL Tracing Support (#3088)
* feat: node-mysql tracing integration * Use // instead of /** */ * fix: Require mysql.Connection directly through mysql/lib/Connection.js * ref: Align span description Co-authored-by: Katie Byers <[email protected]> Co-authored-by: Daniel Griesser <[email protected]>
1 parent f7fc733 commit a1934b4

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { Express } from './express';
2+
export { Mysql } from './mysql';
23
export { Mongo } from './mongo';
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { Hub } from '@sentry/hub';
2+
import { EventProcessor, Integration } from '@sentry/types';
3+
import { dynamicRequire, fill, logger } from '@sentry/utils';
4+
5+
interface MysqlConnection {
6+
prototype: {
7+
query: () => void;
8+
};
9+
}
10+
11+
/** Tracing integration for node-mysql package */
12+
export class Mysql implements Integration {
13+
/**
14+
* @inheritDoc
15+
*/
16+
public static id: string = 'Mysql';
17+
18+
/**
19+
* @inheritDoc
20+
*/
21+
public name: string = Mysql.id;
22+
23+
/**
24+
* @inheritDoc
25+
*/
26+
public setupOnce(_: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void {
27+
let connection: MysqlConnection;
28+
29+
try {
30+
// Unfortunatelly mysql is using some custom loading system and `Connection` is not exported directly.
31+
connection = dynamicRequire(module, 'mysql/lib/Connection.js');
32+
} catch (e) {
33+
logger.error('Mysql Integration was unable to require `mysql` package.');
34+
return;
35+
}
36+
37+
// The original function will have one of these signatures:
38+
// function (callback) => void
39+
// function (options, callback) => void
40+
// function (options, values, callback) => void
41+
fill(connection.prototype, 'query', function(orig: () => void) {
42+
return function(this: unknown, options: unknown, values: unknown, callback: unknown) {
43+
const scope = getCurrentHub().getScope();
44+
const parentSpan = scope?.getSpan();
45+
const span = parentSpan?.startChild({
46+
description: typeof options === 'string' ? options : (options as { sql: string }).sql,
47+
op: `db`,
48+
});
49+
50+
if (typeof callback === 'function') {
51+
return orig.call(this, options, values, function(err: Error, result: unknown, fields: unknown) {
52+
span?.finish();
53+
callback(err, result, fields);
54+
});
55+
}
56+
57+
if (typeof values === 'function') {
58+
return orig.call(this, options, function(err: Error, result: unknown, fields: unknown) {
59+
span?.finish();
60+
values(err, result, fields);
61+
});
62+
}
63+
64+
return orig.call(this, options, values, callback);
65+
};
66+
});
67+
}
68+
}

0 commit comments

Comments
 (0)