From b3e29ebe634add9b387a9147a39d918454f8bebc Mon Sep 17 00:00:00 2001 From: Naseem Date: Tue, 25 Aug 2020 00:15:18 -0400 Subject: [PATCH] feat: implement mysql semantic conventions Signed-off-by: Naseem --- .../opentelemetry-plugin-mysql/package.json | 1 + .../opentelemetry-plugin-mysql/src/enums.ts | 36 ---- .../opentelemetry-plugin-mysql/src/mysql.ts | 41 ++-- .../opentelemetry-plugin-mysql/src/types.ts | 19 -- .../opentelemetry-plugin-mysql/src/utils.ts | 75 ++++--- .../test/mysql.test.ts | 202 +++++++++--------- 6 files changed, 156 insertions(+), 218 deletions(-) delete mode 100644 plugins/node/opentelemetry-plugin-mysql/src/enums.ts delete mode 100644 plugins/node/opentelemetry-plugin-mysql/src/types.ts diff --git a/plugins/node/opentelemetry-plugin-mysql/package.json b/plugins/node/opentelemetry-plugin-mysql/package.json index 0d2d90b936..a20b27ef64 100644 --- a/plugins/node/opentelemetry-plugin-mysql/package.json +++ b/plugins/node/opentelemetry-plugin-mysql/package.json @@ -43,6 +43,7 @@ "devDependencies": { "@opentelemetry/context-async-hooks": "0.10.2", "@opentelemetry/node": "0.10.2", + "@opentelemetry/semantic-conventions": "^0.10.2", "@opentelemetry/test-utils": "^0.9.0", "@opentelemetry/tracing": "0.10.2", "@types/mocha": "7.0.2", diff --git a/plugins/node/opentelemetry-plugin-mysql/src/enums.ts b/plugins/node/opentelemetry-plugin-mysql/src/enums.ts deleted file mode 100644 index 8424e7ea19..0000000000 --- a/plugins/node/opentelemetry-plugin-mysql/src/enums.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export enum AttributeNames { - // required by https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-database.md - COMPONENT = 'component', - DB_TYPE = 'db.type', - DB_INSTANCE = 'db.instance', - DB_STATEMENT = 'db.statement', - - PEER_ADDRESS = 'peer.address', - PEER_HOSTNAME = 'peer.hostname', - - // optional - DB_USER = 'db.user', - - PEER_PORT = 'peer.port', - PEER_IPV4 = 'peer.ipv4', - PEER_IPV6 = 'peer.ipv6', - PEER_SERVICE = 'peer.service', - - MYSQL_VALUES = 'mysql.values', -} diff --git a/plugins/node/opentelemetry-plugin-mysql/src/mysql.ts b/plugins/node/opentelemetry-plugin-mysql/src/mysql.ts index b99369c9ec..d03a76e1ac 100644 --- a/plugins/node/opentelemetry-plugin-mysql/src/mysql.ts +++ b/plugins/node/opentelemetry-plugin-mysql/src/mysql.ts @@ -16,22 +16,19 @@ import { BasePlugin, isWrapped } from '@opentelemetry/core'; import { CanonicalCode, Span, SpanKind } from '@opentelemetry/api'; -import * as mysqlTypes from 'mysql'; +import type * as mysqlTypes from 'mysql'; import * as shimmer from 'shimmer'; -import { AttributeNames } from './enums'; -import { getConnectionAttributes, getSpanName } from './utils'; +import { getConnectionAttributes, getDbStatement } from './utils'; import { VERSION } from './version'; +import { DatabaseAttribute } from '@opentelemetry/semantic-conventions'; export class MysqlPlugin extends BasePlugin { readonly supportedVersions = ['2.*']; static readonly COMPONENT = 'mysql'; - static readonly DB_TYPE = 'sql'; static readonly COMMON_ATTRIBUTES = { - [AttributeNames.COMPONENT]: MysqlPlugin.COMPONENT, - [AttributeNames.DB_TYPE]: MysqlPlugin.DB_TYPE, - [AttributeNames.PEER_SERVICE]: MysqlPlugin.COMPONENT, + [DatabaseAttribute.DB_SYSTEM]: MysqlPlugin.COMPONENT, }; private _enabled = false; @@ -198,6 +195,8 @@ export class MysqlPlugin extends BasePlugin { const thisPlugin = this; thisPlugin._logger.debug('MysqlPlugin: patched mysql query'); + const format = this._moduleExports.format; + return function query( query: string | mysqlTypes.Query | mysqlTypes.QueryOptions, _valuesOrCallback?: unknown[] | mysqlTypes.queryCallback, @@ -208,9 +207,7 @@ export class MysqlPlugin extends BasePlugin { return originalQuery.apply(connection, arguments); } - const spanName = getSpanName(query); - - const span = thisPlugin._tracer.startSpan(spanName, { + const span = thisPlugin._tracer.startSpan(`${query}`, { kind: SpanKind.CLIENT, attributes: { ...MysqlPlugin.COMMON_ATTRIBUTES, @@ -218,18 +215,19 @@ export class MysqlPlugin extends BasePlugin { }, }); - if (typeof query === 'string') { - span.setAttribute(AttributeNames.DB_STATEMENT, query); - } else if (typeof query === 'object') { - if (query.sql) { - span.setAttribute(AttributeNames.DB_STATEMENT, query.sql); - } + let values; - if (query.values) { - span.setAttribute(AttributeNames.MYSQL_VALUES, query.values); - } + if (Array.isArray(_valuesOrCallback)) { + values = _valuesOrCallback; + } else if (arguments[2]) { + values = [_valuesOrCallback]; } + span.setAttribute( + DatabaseAttribute.DB_STATEMENT, + getDbStatement(query, format, values) + ); + if (arguments.length === 1) { const streamableQuery: mysqlTypes.Query = originalQuery.apply( connection, @@ -251,11 +249,6 @@ export class MysqlPlugin extends BasePlugin { if (typeof arguments[1] === 'function') { shimmer.wrap(arguments, 1, thisPlugin._patchCallbackQuery(span)); } else if (typeof arguments[2] === 'function') { - if (Array.isArray(_valuesOrCallback)) { - span.setAttribute(AttributeNames.MYSQL_VALUES, _valuesOrCallback); - } else if (arguments[2]) { - span.setAttribute(AttributeNames.MYSQL_VALUES, [_valuesOrCallback]); - } shimmer.wrap(arguments, 2, thisPlugin._patchCallbackQuery(span)); } diff --git a/plugins/node/opentelemetry-plugin-mysql/src/types.ts b/plugins/node/opentelemetry-plugin-mysql/src/types.ts deleted file mode 100644 index 349fadd58a..0000000000 --- a/plugins/node/opentelemetry-plugin-mysql/src/types.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export type Query = Partial<{ - sql: string; -}>; diff --git a/plugins/node/opentelemetry-plugin-mysql/src/utils.ts b/plugins/node/opentelemetry-plugin-mysql/src/utils.ts index f1036abcc4..d289b32c47 100644 --- a/plugins/node/opentelemetry-plugin-mysql/src/utils.ts +++ b/plugins/node/opentelemetry-plugin-mysql/src/utils.ts @@ -15,35 +15,16 @@ */ import { Attributes } from '@opentelemetry/api'; -import { AttributeNames } from './enums'; -import { Query } from './types'; -import type { ConnectionConfig, PoolActualConfig } from 'mysql'; - -/** - * Get a span name from a mysql query - * - * @param query mysql Query or string - */ -export function getSpanName(query: string | Query) { - return `mysql.query:${getCommand(query)}`; -} - -/** - * Get the low cardinality command name from a query. - * - * @param query mysql Query or string - */ -function getCommand(query: string | Query) { - const queryString = typeof query === 'string' ? query : query.sql; - - if (!queryString) { - return 'UNKNOWN_COMMAND'; - } - - // Command is the first non-whitespace token in the query - const match = queryString.match(/^\s*(\w+)/); - return (match && match[1]) || 'UNKNOWN_COMMAND'; -} +import { + DatabaseAttribute, + GeneralAttribute, +} from '@opentelemetry/semantic-conventions'; +import type { + ConnectionConfig, + PoolActualConfig, + Query, + QueryOptions, +} from 'mysql'; /** * Get an Attributes map from a mysql connection config object @@ -56,11 +37,11 @@ export function getConnectionAttributes( const { host, port, database, user } = getConfig(config); return { - [AttributeNames.PEER_ADDRESS]: getJDBCString(host, port, database), - [AttributeNames.DB_INSTANCE]: database, - [AttributeNames.PEER_HOSTNAME]: host, - [AttributeNames.PEER_PORT]: port, - [AttributeNames.DB_USER]: user, + [GeneralAttribute.NET_PEER_HOSTNAME]: host, + [GeneralAttribute.NET_PEER_PORT]: port, + [GeneralAttribute.NET_PEER_ADDRESS]: getJDBCString(host, port, database), + [DatabaseAttribute.DB_NAME]: database, + [DatabaseAttribute.DB_USER]: user, }; } @@ -87,3 +68,29 @@ function getJDBCString( return jdbcString; } + +/** + * Conjures up the value for the db.statement attribute by formatting a SQL query. + * + * @returns the database statement being executed. + */ +export function getDbStatement( + query: string | Query | QueryOptions, + format: ( + sql: string, + values: any[], + stringifyObjects?: boolean, + timeZone?: string + ) => string, + values?: any[] +): string { + if (typeof query === 'string') { + return values ? format(query, values) : query; + } else { + // According to https://github.com/mysqljs/mysql#performing-queries + // The values argument will override the values in the option object. + return values || query.values + ? format(query.sql, values || query.values) + : query.sql; + } +} diff --git a/plugins/node/opentelemetry-plugin-mysql/test/mysql.test.ts b/plugins/node/opentelemetry-plugin-mysql/test/mysql.test.ts index be1f85b533..71b67187b2 100644 --- a/plugins/node/opentelemetry-plugin-mysql/test/mysql.test.ts +++ b/plugins/node/opentelemetry-plugin-mysql/test/mysql.test.ts @@ -27,9 +27,12 @@ import { import * as assert from 'assert'; import * as mysql from 'mysql'; import { MysqlPlugin, plugin } from '../src'; -import { AttributeNames } from '../src/enums'; +import { + DatabaseAttribute, + GeneralAttribute, +} from '@opentelemetry/semantic-conventions'; -const port = parseInt(process.env.MYSQL_PORT || '33306', 10); +const port = Number(process.env.MYSQL_PORT) || 33306; const database = process.env.MYSQL_DATABASE || 'test_db'; const host = process.env.MYSQL_HOST || '127.0.0.1'; const user = process.env.MYSQL_USER || 'otel'; @@ -125,8 +128,8 @@ describe('mysql@2.x', () => { it('should intercept connection.query(text: string)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+1 as solution'; - const query = connection.query(statement); + const sql = 'SELECT 1+1 as solution'; + const query = connection.query(sql); let rows = 0; query.on('result', row => { @@ -138,7 +141,7 @@ describe('mysql@2.x', () => { assert.strictEqual(rows, 1); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement); + assertSpan(spans[0], sql); done(); }); }); @@ -147,14 +150,14 @@ describe('mysql@2.x', () => { it('should intercept connection.query(text: string, callback)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+1 as solution'; - connection.query(statement, (err, res) => { + const sql = 'SELECT 1+1 as solution'; + connection.query(sql, (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 2); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement); + assertSpan(spans[0], sql); done(); }); }); @@ -163,14 +166,14 @@ describe('mysql@2.x', () => { it('should intercept connection.query(text: options, callback)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+? as solution'; - connection.query({ sql: statement, values: [1] }, (err, res) => { + const sql = 'SELECT 1+? as solution'; + connection.query({ sql, values: [1] }, (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 2); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); + assertSpan(spans[0], sql, [1]); done(); }); }); @@ -179,16 +182,14 @@ describe('mysql@2.x', () => { it('should intercept connection.query(text: options, values: [], callback)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+? as solution'; - // @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries - // but does not match the typings - connection.query({ sql: statement }, [1], (err, res) => { + const sql = 'SELECT 1+? as solution'; + connection.query({ sql }, [1], (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 2); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); + assertSpan(spans[0], sql, [1]); done(); }); }); @@ -197,14 +198,14 @@ describe('mysql@2.x', () => { it('should intercept connection.query(text: string, values: [], callback)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT ? as solution'; - connection.query(statement, [1], (err, res) => { + const sql = 'SELECT ? as solution'; + connection.query(sql, [1], (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 1); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); + assertSpan(spans[0], sql, [1]); done(); }); }); @@ -213,14 +214,14 @@ describe('mysql@2.x', () => { it('should intercept connection.query(text: string, value: any, callback)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT ? as solution'; - connection.query(statement, 1, (err, res) => { + const sql = 'SELECT ? as solution'; + connection.query(sql, 1, (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 1); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); + assertSpan(spans[0], sql, [1]); done(); }); }); @@ -229,12 +230,12 @@ describe('mysql@2.x', () => { it('should attach error messages to spans', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT ? as solution'; - connection.query(statement, (err, res) => { + const sql = 'SELECT ? as solution'; + connection.query(sql, (err, res) => { assert.ok(err); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, undefined, err!.message); + assertSpan(spans[0], sql, undefined, err!.message); done(); }); }); @@ -245,8 +246,8 @@ describe('mysql@2.x', () => { it('should intercept pool.query(text: string)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+1 as solution'; - const query = pool.query(statement); + const sql = 'SELECT 1+1 as solution'; + const query = pool.query(sql); let rows = 0; query.on('result', row => { @@ -258,7 +259,7 @@ describe('mysql@2.x', () => { assert.strictEqual(rows, 1); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement); + assertSpan(spans[0], sql); done(); }); }); @@ -267,9 +268,9 @@ describe('mysql@2.x', () => { it('should intercept pool.getConnection().query(text: string)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+1 as solution'; + const sql = 'SELECT 1+1 as solution'; pool.getConnection((err, conn) => { - const query = conn.query(statement); + const query = conn.query(sql); let rows = 0; query.on('result', row => { @@ -281,7 +282,7 @@ describe('mysql@2.x', () => { assert.strictEqual(rows, 1); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement); + assertSpan(spans[0], sql); done(); }); }); @@ -291,14 +292,14 @@ describe('mysql@2.x', () => { it('should intercept pool.query(text: string, callback)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+1 as solution'; - pool.query(statement, (err, res) => { + const sql = 'SELECT 1+1 as solution'; + pool.query(sql, (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 2); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement); + assertSpan(spans[0], sql); done(); }); }); @@ -307,15 +308,15 @@ describe('mysql@2.x', () => { it('should intercept pool.getConnection().query(text: string, callback)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+1 as solution'; + const sql = 'SELECT 1+1 as solution'; pool.getConnection((err, conn) => { - conn.query(statement, (err, res) => { + conn.query(sql, (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 2); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement); + assertSpan(spans[0], sql); done(); }); }); @@ -325,14 +326,14 @@ describe('mysql@2.x', () => { it('should intercept pool.query(text: options, callback)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+? as solution'; - pool.query({ sql: statement, values: [1] }, (err, res) => { + const sql = 'SELECT 1+? as solution'; + pool.query({ sql, values: [1] }, (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 2); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); + assertSpan(spans[0], sql, [1]); done(); }); }); @@ -341,16 +342,14 @@ describe('mysql@2.x', () => { it('should intercept pool.query(text: options, values: [], callback)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+? as solution'; - // @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries - // but does not match the typings - pool.query({ sql: statement }, [1], (err, res) => { + const sql = 'SELECT 1+? as solution'; + pool.query({ sql }, [1], (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 2); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); + assertSpan(spans[0], sql, [1]); done(); }); }); @@ -359,14 +358,14 @@ describe('mysql@2.x', () => { it('should intercept pool.query(text: string, values: [], callback)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT ? as solution'; - pool.query(statement, [1], (err, res) => { + const sql = 'SELECT ? as solution'; + pool.query(sql, [1], (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 1); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); + assertSpan(spans[0], sql, [1]); done(); }); }); @@ -375,14 +374,14 @@ describe('mysql@2.x', () => { it('should intercept pool.query(text: string, value: any, callback)', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT ? as solution'; - pool.query(statement, 1, (err, res) => { + const sql = 'SELECT ? as solution'; + pool.query(sql, 1, (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 1); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); + assertSpan(spans[0], sql, [1]); done(); }); }); @@ -391,12 +390,12 @@ describe('mysql@2.x', () => { it('should attach error messages to spans', done => { const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT ? as solution'; - pool.query(statement, (err, res) => { + const sql = 'SELECT ? as solution'; + pool.query(sql, (err, res) => { assert.ok(err); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, undefined, err!.message); + assertSpan(spans[0], sql, undefined, err!.message); done(); }); }); @@ -409,8 +408,8 @@ describe('mysql@2.x', () => { assert.ifError(err); const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+1 as solution'; - const query = poolClusterConnection.query(statement); + const sql = 'SELECT 1+1 as solution'; + const query = poolClusterConnection.query(sql); let rows = 0; query.on('result', row => { @@ -422,7 +421,7 @@ describe('mysql@2.x', () => { assert.strictEqual(rows, 1); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement); + assertSpan(spans[0], sql); done(); }); }); @@ -434,14 +433,14 @@ describe('mysql@2.x', () => { assert.ifError(err); const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+1 as solution'; - poolClusterConnection.query(statement, (err, res) => { + const sql = 'SELECT 1+1 as solution'; + poolClusterConnection.query(sql, (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 2); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement); + assertSpan(spans[0], sql); done(); }); }); @@ -453,19 +452,16 @@ describe('mysql@2.x', () => { assert.ifError(err); const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+? as solution'; - poolClusterConnection.query( - { sql: statement, values: [1] }, - (err, res) => { - assert.ifError(err); - assert.ok(res); - assert.strictEqual(res[0].solution, 2); - const spans = memoryExporter.getFinishedSpans(); - assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); - done(); - } - ); + const sql = 'SELECT 1+? as solution'; + poolClusterConnection.query({ sql, values: [1] }, (err, res) => { + 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(); + }); }); }); }); @@ -475,16 +471,16 @@ describe('mysql@2.x', () => { assert.ifError(err); const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1+? as solution'; + const sql = 'SELECT 1+? as solution'; // @ts-ignore this is documented https://github.com/mysqljs/mysql#performing-queries // but does not match the typings - poolClusterConnection.query({ sql: statement }, [1], (err, res) => { + poolClusterConnection.query({ sql }, [1], (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 2); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); + assertSpan(spans[0], sql, [1]); done(); }); }); @@ -496,14 +492,14 @@ describe('mysql@2.x', () => { assert.ifError(err); const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT ? as solution'; - poolClusterConnection.query(statement, [1], (err, res) => { + const sql = 'SELECT ? as solution'; + poolClusterConnection.query(sql, [1], (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 1); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); + assertSpan(spans[0], sql, [1]); done(); }); }); @@ -515,14 +511,14 @@ describe('mysql@2.x', () => { assert.ifError(err); const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT ? as solution'; - poolClusterConnection.query(statement, 1, (err, res) => { + const sql = 'SELECT ? as solution'; + poolClusterConnection.query(sql, 1, (err, res) => { assert.ifError(err); assert.ok(res); assert.strictEqual(res[0].solution, 1); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, [1]); + assertSpan(spans[0], sql, [1]); done(); }); }); @@ -534,12 +530,12 @@ describe('mysql@2.x', () => { assert.ifError(err); const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT ? as solution'; - poolClusterConnection.query(statement, (err, res) => { + const sql = 'SELECT ? as solution'; + poolClusterConnection.query(sql, (err, res) => { assert.ok(err); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement, undefined, err!.message); + assertSpan(spans[0], sql, undefined, err!.message); done(); }); }); @@ -551,12 +547,12 @@ describe('mysql@2.x', () => { assert.ifError(err); const span = provider.getTracer('default').startSpan('test span'); provider.getTracer('default').withSpan(span, () => { - const statement = 'SELECT 1 as solution'; - poolClusterConnection.query(statement, (err, res) => { + const sql = 'SELECT 1 as solution'; + poolClusterConnection.query(sql, (err, res) => { assert.ifError(err); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement); + assertSpan(spans[0], sql); done(); }); }); @@ -569,12 +565,12 @@ describe('mysql@2.x', () => { 'ORDER', (err, poolClusterConnection) => { assert.ifError(err); - const statement = 'SELECT 1 as solution'; - poolClusterConnection.query(statement, (err, res) => { + const sql = 'SELECT 1 as solution'; + poolClusterConnection.query(sql, (err, res) => { assert.ifError(err); const spans = memoryExporter.getFinishedSpans(); assert.strictEqual(spans.length, 1); - assertSpan(spans[0], statement); + assertSpan(spans[0], sql); done(); }); } @@ -585,23 +581,19 @@ describe('mysql@2.x', () => { function assertSpan( span: ReadableSpan, - statement: string, + sql: string, values?: any, errorMessage?: string ) { - assert.equal(span.attributes[AttributeNames.COMPONENT], 'mysql'); - assert.equal(span.attributes[AttributeNames.DB_TYPE], 'sql'); - assert.equal(span.attributes[AttributeNames.DB_INSTANCE], database); - assert.equal(span.attributes[AttributeNames.PEER_PORT], port); - assert.equal(span.attributes[AttributeNames.PEER_HOSTNAME], host); - assert.equal(span.attributes[AttributeNames.DB_USER], user); - assert.strictEqual(span.attributes[AttributeNames.DB_STATEMENT], statement); - if (values) { - assert.deepStrictEqual( - span.attributes[AttributeNames.MYSQL_VALUES], - values - ); - } + assert.equal(span.attributes[DatabaseAttribute.DB_SYSTEM], 'mysql'); + assert.equal(span.attributes[DatabaseAttribute.DB_NAME], database); + assert.equal(span.attributes[GeneralAttribute.NET_PEER_PORT], port); + assert.equal(span.attributes[GeneralAttribute.NET_PEER_HOSTNAME], host); + assert.equal(span.attributes[DatabaseAttribute.DB_USER], user); + assert.strictEqual( + span.attributes[DatabaseAttribute.DB_STATEMENT], + mysql.format(sql, values) + ); if (errorMessage) { assert.equal(span.status.message, errorMessage); assert.equal(span.status.code, CanonicalCode.UNKNOWN);