From 2f3efc8f1ccd56cb8428475cc5a3c056bd5c476f Mon Sep 17 00:00:00 2001 From: Jason Terando Date: Thu, 26 Jan 2023 15:15:27 -0600 Subject: [PATCH 1/5] Add support for including sql query in sql subsegment for MySQL --- packages/core/README.md | 2 +- packages/mysql/lib/mysql_p.js | 8 +++++-- packages/mysql/test/unit/mysql_p.test.js | 28 ++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/packages/core/README.md b/packages/core/README.md index e9120547..5c9655bc 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -59,7 +59,7 @@ section for different usages. AWS_XRAY_DAEMON_ADDRESS For setting the daemon address and port. AWS_XRAY_CONTEXT_MISSING For setting the SDK behavior when trace context is missing. Valid values are 'RUNTIME_ERROR', 'IGNORE_ERROR' or 'LOG_ERROR'. The SDK's default behavior is 'LOG_ERROR'. AWS_XRAY_LOG_LEVEL Sets a log level for the SDK built in logger. This value is ignored if AWS_XRAY_DEBUG_MODE is set. - AWS_XRAY_COLLECT_SQL_QUERIES Enables SQL query capture (currently only Postgres supported) + AWS_XRAY_COLLECT_SQL_QUERIES Enables SQL query capture (currently only Postgres and MySQL supported) ### Daemon configuration diff --git a/packages/mysql/lib/mysql_p.js b/packages/mysql/lib/mysql_p.js index 3623772e..fb4341d5 100644 --- a/packages/mysql/lib/mysql_p.js +++ b/packages/mysql/lib/mysql_p.js @@ -254,19 +254,23 @@ function captureOperation(name) { } } - subsegment.addSqlData(createSqlData(config, command)); + subsegment.addSqlData(createSqlData(config, command, args.sql)); subsegment.namespace = 'remote'; return command; }; } -function createSqlData(config, command) { +function createSqlData(config, command, sql) { var commandType = command.values ? PREPARED : null; var data = new SqlData(DATABASE_VERS, DRIVER_VERS, config.user, config.host + ':' + config.port + '/' + config.database, commandType); + if (process.env.AWS_XRAY_COLLECT_SQL_QUERIES && sql) { + data.sanitized_query = sql; + } + return data; } diff --git a/packages/mysql/test/unit/mysql_p.test.js b/packages/mysql/test/unit/mysql_p.test.js index 028a2d29..a9f211e3 100644 --- a/packages/mysql/test/unit/mysql_p.test.js +++ b/packages/mysql/test/unit/mysql_p.test.js @@ -247,6 +247,34 @@ describe('captureMySQL', function() { done(); }, 50); }); + it('should add query to the subsegments sql data when AWS_XRAY_COLLECT_SQL_QUERIES is truthy', function () { + sandbox.stub(process, 'env').value({ ...AWSXRay, 'AWS_XRAY_COLLECT_SQL_QUERIES': true }); + var stubAddSql = sandbox.stub(subsegment, 'addSqlData'); + var stubDataInit = sandbox.stub(SqlData.prototype, 'init'); + var conParam = connectionObj.config; + + query.call(connectionObj, 'sql here'); + + stubDataInit.should.have.been.calledWithExactly(process.env.MYSQL_DATABASE_VERSION, process.env.MYSQL_DRIVER_VERSION, + conParam.user, conParam.host + ':' + conParam.port + '/' + conParam.database, 'statement'); + stubAddSql.should.have.been.calledWithExactly(sinon.match.instanceOf(SqlData)); + stubAddSql.should.have.been.calledWithExactly(sinon.match.has('sanitized_query', 'sql here')); + }); + it('should NOT add query to the subsegments sql data when AWS_XRAY_COLLECT_SQL_QUERIES is not set', function () { + sandbox.stub(process, 'env').value({ ...AWSXRay, 'AWS_XRAY_COLLECT_SQL_QUERIES': undefined }); + var stubAddSql = sandbox.stub(subsegment, 'addSqlData'); + var stubDataInit = sandbox.stub(SqlData.prototype, 'init'); + var conParam = connectionObj.config; + + query.call(connectionObj, 'sql here'); + + stubDataInit.should.have.been.calledWithExactly(process.env.MYSQL_DATABASE_VERSION, process.env.MYSQL_DRIVER_VERSION, + conParam.user, conParam.host + ':' + conParam.port + '/' + conParam.database, 'statement'); + stubAddSql.should.have.been.calledWithExactly(sinon.match.instanceOf(SqlData)); + sinon.assert.match(sinon.match, { + 'sanitized_query': undefined + }); + }); }); }); From a8228e52f88fef7fdf9bd4acae82d0a176fa65a6 Mon Sep 17 00:00:00 2001 From: Jason Terando Date: Sat, 28 Jan 2023 10:18:28 -0600 Subject: [PATCH 2/5] Update createSqlData to accept values and sql as arguments, and the call to createSqlData to send those values from the arguments made to the sql call --- packages/mysql/lib/mysql_p.js | 11 ++++------- packages/mysql/test/unit/mysql_p.test.js | 13 ++++++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/mysql/lib/mysql_p.js b/packages/mysql/lib/mysql_p.js index fb4341d5..b1e2de3e 100644 --- a/packages/mysql/lib/mysql_p.js +++ b/packages/mysql/lib/mysql_p.js @@ -242,9 +242,7 @@ function captureOperation(name) { if (isPromise(command)) { command.then(() => { subsegment.close(); - }); - - command.catch(errorCapturer); + }).catch (errorCapturer); } else { command.on('end', function() { subsegment.close(); @@ -254,16 +252,15 @@ function captureOperation(name) { } } - subsegment.addSqlData(createSqlData(config, command, args.sql)); + subsegment.addSqlData(createSqlData(config, args.values, args.sql)); subsegment.namespace = 'remote'; return command; }; } -function createSqlData(config, command, sql) { - var commandType = command.values ? PREPARED : null; - +function createSqlData(config, values, sql) { + var commandType = values ? PREPARED : null; var data = new SqlData(DATABASE_VERS, DRIVER_VERS, config.user, config.host + ':' + config.port + '/' + config.database, commandType); diff --git a/packages/mysql/test/unit/mysql_p.test.js b/packages/mysql/test/unit/mysql_p.test.js index a9f211e3..e50cf634 100644 --- a/packages/mysql/test/unit/mysql_p.test.js +++ b/packages/mysql/test/unit/mysql_p.test.js @@ -141,7 +141,7 @@ describe('captureMySQL', function() { var stubDataInit = sandbox.stub(SqlData.prototype, 'init'); var config = conn.config; - query.call(connectionObj, 'sql here'); + query.call(connectionObj, 'sql here', [1]); stubDataInit.should.have.been.calledWithExactly(undefined, undefined, config.user, config.host + ':' + config.port + '/' + config.database, 'statement'); @@ -253,7 +253,7 @@ describe('captureMySQL', function() { var stubDataInit = sandbox.stub(SqlData.prototype, 'init'); var conParam = connectionObj.config; - query.call(connectionObj, 'sql here'); + query.call(connectionObj, 'sql here', [1]); stubDataInit.should.have.been.calledWithExactly(process.env.MYSQL_DATABASE_VERSION, process.env.MYSQL_DRIVER_VERSION, conParam.user, conParam.host + ':' + conParam.port + '/' + conParam.database, 'statement'); @@ -266,7 +266,7 @@ describe('captureMySQL', function() { var stubDataInit = sandbox.stub(SqlData.prototype, 'init'); var conParam = connectionObj.config; - query.call(connectionObj, 'sql here'); + query.call(connectionObj, 'sql here', [1]); stubDataInit.should.have.been.calledWithExactly(process.env.MYSQL_DATABASE_VERSION, process.env.MYSQL_DRIVER_VERSION, conParam.user, conParam.host + ':' + conParam.port + '/' + conParam.database, 'statement'); @@ -372,7 +372,6 @@ describe('captureMySQL', function() { stubClose.should.have.been.calledWithExactly(err); }); }); - }); }); @@ -458,7 +457,7 @@ describe('captureMySQL', function() { var stubDataInit = sandbox.stub(SqlData.prototype, 'init'); var config = conn.config; - query.call(connectionObj, 'sql here'); + query.call(connectionObj, 'sql here', [1]); stubDataInit.should.have.been.calledWithExactly(undefined, undefined, config.user, config.host + ':' + config.port + '/' + config.database, 'statement'); @@ -554,7 +553,7 @@ describe('captureMySQL', function() { var stubDataInit = sandbox.stub(SqlData.prototype, 'init'); var config = conn.config; - query.call(connectionObj, 'sql here'); + query.call(connectionObj, 'sql here', [1]); stubDataInit.should.have.been.calledWithExactly(undefined, undefined, config.user, config.host + ':' + config.port + '/' + config.database, 'statement'); @@ -701,7 +700,7 @@ describe('captureMySQL', function() { var stubDataInit = sandbox.stub(SqlData.prototype, 'init'); var config = conn.config; - query.call(connectionObj, 'sql here'); + query.call(connectionObj, 'sql here', [1]); stubDataInit.should.have.been.calledWithExactly(undefined, undefined, config.user, config.host + ':' + config.port + '/' + config.database, 'statement'); From 08ad91988996ee627e9830ad2f6ade4df80b5a64 Mon Sep 17 00:00:00 2001 From: Jason Terando Date: Mon, 20 Feb 2023 18:06:29 -0600 Subject: [PATCH 3/5] Add function comments to mysqL_p.createSqlData --- packages/mysql/lib/mysql_p.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/mysql/lib/mysql_p.js b/packages/mysql/lib/mysql_p.js index b1e2de3e..c6aa589c 100644 --- a/packages/mysql/lib/mysql_p.js +++ b/packages/mysql/lib/mysql_p.js @@ -259,6 +259,16 @@ function captureOperation(name) { }; } +/** + * Generate a SQL data object. Note that this implementation differs from + * that in postgres_p.js because the posgres client structures commands + * and prepared statements differently than mysql/mysql2. + * + * @param {object} config + * @param {any} values + * @param {string} sql + * @returns SQL data object + */ function createSqlData(config, values, sql) { var commandType = values ? PREPARED : null; var data = new SqlData(DATABASE_VERS, DRIVER_VERS, config.user, From b778942f6931873fc40a2b70c7349e2e4659af9f Mon Sep 17 00:00:00 2001 From: Jason Terando Date: Wed, 24 Jan 2024 16:37:36 -0600 Subject: [PATCH 4/5] Add export for resolveManualSegmentParams to AWSXRay --- packages/core/lib/aws-xray.d.ts | 1 + packages/core/lib/aws-xray.js | 9 +++++++++ packages/core/lib/context_utils.d.ts | 2 ++ 3 files changed, 12 insertions(+) diff --git a/packages/core/lib/aws-xray.d.ts b/packages/core/lib/aws-xray.d.ts index 6a65c4ce..a7e1664c 100644 --- a/packages/core/lib/aws-xray.d.ts +++ b/packages/core/lib/aws-xray.d.ts @@ -58,6 +58,7 @@ export { middleware }; export { getNamespace, resolveSegment, + resolveManualSegmentParams, getSegment, setSegment, isAutomaticMode, diff --git a/packages/core/lib/aws-xray.js b/packages/core/lib/aws-xray.js index 100d597a..4473063c 100644 --- a/packages/core/lib/aws-xray.js +++ b/packages/core/lib/aws-xray.js @@ -276,6 +276,15 @@ var AWSXRay = { resolveSegment: contextUtils.resolveSegment, + /** + * Resolves the segment or subsegment given manual mode and params on the call required. + * @param [Segment|Subsegment] segment - The segment manually provided via params.XraySegment, if provided. + * @returns {Segment|Subsegment} + * @alias module:context_utils.resolveManualSegmentParams + */ + + resolveManualSegmentParams: contextUtils.resolveManualSegmentParams, + /** * Returns the current segment or subsegment. For use with automatic mode only. * @memberof AWSXRay diff --git a/packages/core/lib/context_utils.d.ts b/packages/core/lib/context_utils.d.ts index 49ac9364..0fa21f4f 100644 --- a/packages/core/lib/context_utils.d.ts +++ b/packages/core/lib/context_utils.d.ts @@ -6,6 +6,8 @@ export function getNamespace(): Namespace; export function resolveSegment(segment?: Segment | Subsegment | null): Segment | Subsegment | undefined; +export function resolveManualSegmentParams(segment?: Segment | Subsegment | null): Segment | Subsegment | undefined; + export function getSegment(): Segment | Subsegment | undefined; export function setSegment(segment: Segment | Subsegment): void; From 50e82f93d2e8f0f48ecfaaa1adad3a46a20b6a68 Mon Sep 17 00:00:00 2001 From: Jonathan Lee <107072447+jj22ee@users.noreply.github.com> Date: Mon, 29 Jan 2024 09:50:54 -0800 Subject: [PATCH 5/5] Update comment --- packages/core/lib/aws-xray.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/core/lib/aws-xray.js b/packages/core/lib/aws-xray.js index 4473063c..d235a1ce 100644 --- a/packages/core/lib/aws-xray.js +++ b/packages/core/lib/aws-xray.js @@ -279,8 +279,10 @@ var AWSXRay = { /** * Resolves the segment or subsegment given manual mode and params on the call required. * @param [Segment|Subsegment] segment - The segment manually provided via params.XraySegment, if provided. + * @memberof AWSXRay + * @function * @returns {Segment|Subsegment} - * @alias module:context_utils.resolveManualSegmentParams + * @see module:context_utils.resolveManualSegmentParams */ resolveManualSegmentParams: contextUtils.resolveManualSegmentParams,