diff --git a/src/dialects/abstract/query.d.ts b/src/dialects/abstract/query.d.ts index 481c24bf3a9e..25f7b5a28457 100644 --- a/src/dialects/abstract/query.d.ts +++ b/src/dialects/abstract/query.d.ts @@ -22,6 +22,7 @@ export interface AbstractQueryOptions { * A function that gets executed while running the query to log the sql. */ logging?: boolean | ((sql: string, timing?: number) => void); + queryLabel?: string; include: boolean; includeNames: unknown[]; diff --git a/src/dialects/abstract/query.js b/src/dialects/abstract/query.js index 65ea533542d9..f17d966c412d 100644 --- a/src/dialects/abstract/query.js +++ b/src/dialects/abstract/query.js @@ -290,14 +290,15 @@ export class AbstractQuery { } const fmt = `(${connection.uuid || 'default'}): ${sql}${logParameter}`; - const msg = `Executing ${fmt}`; + const queryLabel = options.queryLabel ? `${options.queryLabel}\n` : ''; + const msg = `${queryLabel}Executing ${fmt}`; debugContext(msg); if (!benchmark) { - this.sequelize.log(`Executing ${fmt}`, options); + this.sequelize.log(`${queryLabel}Executing ${fmt}`, options); } return () => { - const afterMsg = `Executed ${fmt}`; + const afterMsg = `${queryLabel}Executed ${fmt}`; debugContext(afterMsg); if (benchmark) { this.sequelize.log(afterMsg, Date.now() - startTime, options); diff --git a/src/dialects/db2/query.js b/src/dialects/db2/query.js index 61c291030e6e..0f41e9f73de7 100644 --- a/src/dialects/db2/query.js +++ b/src/dialects/db2/query.js @@ -35,11 +35,12 @@ export class Db2Query extends AbstractQuery { this.sql = sql; const benchmark = this.sequelize.options.benchmark || this.options.benchmark; + const queryLabel = this.options.queryLabel ? `${this.options.queryLabel}\n` : ''; let queryBegin; if (benchmark) { queryBegin = Date.now(); } else { - this.sequelize.log(`Executing (${this.connection.uuid || 'default'}): ${this.sql}`, this.options); + this.sequelize.log(`${queryLabel}Executing (${this.connection.uuid || 'default'}): ${this.sql}`, this.options); } const errStack = new Error().stack; @@ -126,7 +127,7 @@ export class Db2Query extends AbstractQuery { } if (benchmark) { - this.sequelize.log(`Executed (${this.connection.uuid || 'default'}): ${newSql} ${parameters ? util.inspect(parameters, { compact: true, breakLength: Infinity }) : ''}`, Date.now() - queryBegin, this.options); + this.sequelize.log(`${queryLabel}Executed (${this.connection.uuid || 'default'}): ${newSql} ${parameters ? util.inspect(parameters, { compact: true, breakLength: Infinity }) : ''}`, Date.now() - queryBegin, this.options); } if (err && err.message) { diff --git a/src/sequelize.js b/src/sequelize.js index 3d5798721a6e..d34c55c371e5 100644 --- a/src/sequelize.js +++ b/src/sequelize.js @@ -159,6 +159,7 @@ export class Sequelize { * @param {boolean} [options.standardConformingStrings=true] The PostgreSQL `standard_conforming_strings` session parameter. Set to `false` to not set the option. WARNING: Setting this to false may expose vulnerabilities and is not recommended! * @param {Function} [options.logging=console.log] A function that gets executed every time Sequelize would log something. Function may receive multiple parameters but only first one is printed by `console.log`. To print all values use `(...msg) => console.log(msg)` * @param {boolean} [options.benchmark=false] Pass query execution time in milliseconds as second argument to logging function (options.logging). + * @param {string} [options.queryLabel] A label to annotate queries in log output. * @param {boolean} [options.omitNull=false] A flag that defines if null values should be passed as values to CREATE/UPDATE SQL queries or not. * @param {boolean} [options.native=false] A flag that defines if native library shall be used or not. Currently only has an effect for postgres * @param {boolean} [options.replication=false] Use read / write replication. To enable replication, pass an object, with two properties, read and write. Write should be an object (a single server for handling writes), and read an array of object (several servers to handle reads). Each read/write server can have the following properties: `host`, `port`, `username`, `password`, `database`. Connection strings can be used instead of objects. diff --git a/test/integration/sequelize/query.test.js b/test/integration/sequelize/query.test.js index c683d1ec31af..6b119e1cfb50 100644 --- a/test/integration/sequelize/query.test.js +++ b/test/integration/sequelize/query.test.js @@ -130,6 +130,46 @@ describe(Support.getTestDialectTeaser('Sequelize'), () => { expect(typeof logger.args[0][1] === 'number').to.be.true; }); + it('executes a query with queryLabel option and custom logger', async () => { + const logger = sinon.spy(); + const sequelize = Support.createSequelizeInstance({ + logging: logger, + }); + + await sequelize.query(`select 1${dialect === 'ibmi' ? ' FROM SYSIBM.SYSDUMMY1' : ''};`, { + queryLabel: 'tricky select', + }); + expect(logger.calledOnce).to.be.true; + expect(logger.args[0][0]).to.be.match(/^tricky select[\n]Executing \((\d*|default)\): select 1/); + }); + + it('executes a query with empty string, queryLabel option and custom logger', async () => { + const logger = sinon.spy(); + const sequelize = Support.createSequelizeInstance({ + logging: logger, + }); + + await sequelize.query(`select 1${dialect === 'ibmi' ? ' FROM SYSIBM.SYSDUMMY1' : ''};`, { + queryLabel: '', + }); + expect(logger.calledOnce).to.be.true; + expect(logger.args[0][0]).to.be.match(/^Executing \((\d*|default)\): select 1/); + }); + + it('executes a query with benchmarking option, queryLabel option and custom logger', async () => { + const logger = sinon.spy(); + const sequelize = Support.createSequelizeInstance({ + logging: logger, + benchmark: true, + }); + + await sequelize.query(`select 1${dialect === 'ibmi' ? ' FROM SYSIBM.SYSDUMMY1' : ''};`, { + queryLabel: 'tricky select', + }); + expect(logger.calledOnce).to.be.true; + expect(logger.args[0][0]).to.be.match(/^tricky select[\n]Executed \((\d*|default)\): select 1/); + }); + describe('with logQueryParameters', () => { beforeEach(async function () { this.sequelize = Support.createSequelizeInstance({