Skip to content

Commit

Permalink
feat(mysql2): support Connection.execute (#1028)
Browse files Browse the repository at this point in the history
Co-authored-by: Rauno Viskus <[email protected]>
Co-authored-by: Amir Blum <[email protected]>
  • Loading branch information
3 people authored May 31, 2022
1 parent 0dc580d commit 3e2f9c5
Show file tree
Hide file tree
Showing 2 changed files with 294 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,23 @@ export class MySQL2Instrumentation extends InstrumentationBase<
this._patchQuery(moduleExports.format) as any
);

if (isWrapped(ConnectionPrototype.execute)) {
this._unwrap(ConnectionPrototype, 'execute');
}
this._wrap(
ConnectionPrototype,
'execute',
this._patchQuery(moduleExports.format) as any
);

return moduleExports;
},
(moduleExports: any) => {
if (moduleExports === undefined) return;
const ConnectionPrototype: mysqlTypes.Connection =
moduleExports.Connection.prototype;
this._unwrap(ConnectionPrototype, 'query');
this._unwrap(ConnectionPrototype, 'execute');
}
),
];
Expand All @@ -83,7 +93,7 @@ export class MySQL2Instrumentation extends InstrumentationBase<
private _patchQuery(format: formatType) {
return (originalQuery: Function): Function => {
const thisPlugin = this;
api.diag.debug('MySQL2Instrumentation: patched mysql query');
api.diag.debug('MySQL2Instrumentation: patched mysql query/execute');

return function query(
this: mysqlTypes.Connection,
Expand Down
285 changes: 283 additions & 2 deletions plugins/node/opentelemetry-instrumentation-mysql2/test/mysql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ describe('[email protected]', () => {
});
});

describe('#Connection', () => {
describe('#Connection.query', () => {
it('should intercept connection.query(text: string)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
Expand Down Expand Up @@ -301,7 +301,132 @@ describe('[email protected]', () => {
});
});

describe('#Pool', () => {
describe('#Connection.execute', () => {
it('should intercept connection.execute(text: string)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT 1+1 as solution';
const query = connection.execute<Result[]>(sql);
let rows = 0;

query.on('result', (row: mysqlTypes.RowDataPacket) => {
assert.strictEqual(row.solution, 2);
rows += 1;
});

query.on('end', () => {
assert.strictEqual(rows, 1);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql);
done();
});
});
});

it('should intercept connection.execute(text: string, callback)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT 1+1 as solution';
connection.execute(sql, (err, res: mysqlTypes.RowDataPacket[]) => {
assert.ifError(err);
assert.ok(res);
assert.strictEqual(res[0].solution, 2);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql);
done();
});
});
});

it('should intercept connection.execute(text: options, callback)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT 1+? as solution';
connection.execute(
{ sql, values: [1] },
(err, res: mysqlTypes.RowDataPacket[]) => {
assert.ifError(err);
assert.ok(res);
assert.strictEqual(res[0].solution, 2);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql, [1]);
done();
}
);
});
});

it('should intercept connection.execute(text: options, values: [], callback)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT 1+? as solution';
connection.execute(
{ sql },
[1],
(err, res: mysqlTypes.RowDataPacket[]) => {
assert.ifError(err);
assert.ok(res);
assert.strictEqual(res[0].solution, 2);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql, [1]);
done();
}
);
});
});

it('should intercept connection.execute(text: string, values: [], callback)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT ? as solution';
connection.execute(sql, [1], (err, res: mysqlTypes.RowDataPacket[]) => {
assert.ifError(err);
assert.ok(res);
assert.strictEqual(res[0].solution, 1);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql, [1]);
done();
});
});
});

it('should intercept connection.execute(text: string, value: any, callback)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT ? as solution';
connection.execute(sql, [1], (err, res: mysqlTypes.RowDataPacket[]) => {
assert.ifError(err);
assert.ok(res);
assert.strictEqual(res[0].solution, 1);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql, [1]);
done();
});
});
});

it('should attach error messages to spans', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT ? as solution';
connection.execute(sql, (err, res) => {
assert.ok(err);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql, undefined, err!.message);
done();
});
});
});
});

describe('#Pool.query', () => {
it('should intercept pool.query(text: string)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
Expand Down Expand Up @@ -464,6 +589,162 @@ describe('[email protected]', () => {
});
});

describe('#Pool.execute', () => {
it('should intercept pool.execute(text: string)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT 1+1 as solution';
pool.execute(sql, (err, row: mysqlTypes.RowDataPacket[]) => {
assert(!err);
assert.strictEqual(row[0].solution, 2);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql);
done();
});
});
});

it('should intercept pool.getConnection().execute(text: string)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT 1+1 as solution';
pool.getConnection((err, conn) => {
const query = conn.execute(sql);
let rows = 0;

query.on('result', (row: mysqlTypes.RowDataPacket) => {
assert.strictEqual(row.solution, 2);
rows += 1;
});

query.on('end', () => {
assert.strictEqual(rows, 1);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql);
done();
});
});
});
});

it('should intercept pool.execute(text: string, callback)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT 1+1 as solution';
pool.execute(sql, (err, res: mysqlTypes.RowDataPacket[]) => {
assert.ifError(err);
assert.ok(res);
assert.strictEqual(res[0].solution, 2);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql);
done();
});
});
});

it('should intercept pool.getConnection().execute(text: string, callback)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT 1+1 as solution';
pool.getConnection((err, conn) => {
conn.execute(sql, (err, res: mysqlTypes.RowDataPacket[]) => {
assert.ifError(err);
assert.ok(res);
assert.strictEqual(res[0].solution, 2);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql);
done();
});
});
});
});

it('should intercept pool.execute(text: options, callback)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT 1+? as solution';
pool.execute(
{ sql, values: [1] },
(err, res: mysqlTypes.RowDataPacket[]) => {
assert.ifError(err);
assert.ok(res);
assert.strictEqual(res[0].solution, 2);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql);
done();
}
);
});
});

it('should intercept pool.execute(text: options, values: [], callback)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT 1+? as solution';
pool.execute({ sql }, [1], (err, res: mysqlTypes.RowDataPacket[]) => {
assert.ifError(err);
assert.ok(res);
assert.strictEqual(res[0].solution, 2);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql, [1]);
done();
});
});
});

it('should intercept pool.execute(text: string, values: [], callback)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT ? as solution';
pool.execute(sql, [1], (err, res: mysqlTypes.RowDataPacket[]) => {
assert.ifError(err);
assert.ok(res);
assert.strictEqual(res[0].solution, 1);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql, [1]);
done();
});
});
});

it('should intercept pool.execute(text: string, value: any, callback)', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT ? as solution';
pool.execute(sql, [1], (err, res: mysqlTypes.RowDataPacket[]) => {
assert.ifError(err);
assert.ok(res);
assert.strictEqual(res[0].solution, 1);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql, [1]);
done();
});
});
});

it('should attach error messages to spans', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
const sql = 'SELECT ? as solution';
pool.execute(sql, (err, res) => {
assert.ok(err);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
assertSpan(spans[0], sql, undefined, err!.message);
done();
});
});
});
});

describe('#PoolCluster', () => {
it('should intercept poolClusterConnection.query(text: string)', done => {
poolCluster.getConnection((err, poolClusterConnection) => {
Expand Down

0 comments on commit 3e2f9c5

Please sign in to comment.