diff --git a/lib/constants.ts b/lib/constants.ts index 81824cd..916e9bc 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -19,6 +19,7 @@ export const defaultDispatcherOptions: PDOptions = { healthcheckInterval: 5000, healthcheckTimeout: 700, suppressStatusLogs: false, + suppressHealthcheckStatusLogs: false, beforeTerminate: () => Promise.resolve(), topologyMode: 'primary-replica', }; diff --git a/lib/core.ts b/lib/core.ts index a363b99..523d3ca 100644 --- a/lib/core.ts +++ b/lib/core.ts @@ -21,6 +21,7 @@ export interface CoreDBDispatcherOptions { healthcheckInterval?: number; healthcheckTimeout?: number; suppressStatusLogs?: boolean; + suppressHealthcheckStatusLogs?: boolean; beforeTerminate?: () => Promise; topologyMode?: TopologyMode; } diff --git a/lib/dispatcher.ts b/lib/dispatcher.ts index a1b8221..13a5e38 100644 --- a/lib/dispatcher.ts +++ b/lib/dispatcher.ts @@ -229,18 +229,20 @@ export class PGDispatcher { Promise.all(checkups).then(() => { // Connections hold shared current state; this is not an isolated per-cycle result. const status = this.getHealthcheckStatus(); - this.logger.info({ - message: 'Database current status', - data: { - ...(this.isProxyMode ? {topologyMode: this.options.topologyMode} : {}), - connections: this.connections.map((connection) => ({ - host: connection.host, - ...(this.isProxyMode ? {} : {primary: connection.primary}), - healthy: connection.healthy, - latency: connection.latency, - })), - }, - }); + if (!this.options.suppressHealthcheckStatusLogs) { + this.logger.info({ + message: 'Database current status', + data: { + ...(this.isProxyMode ? {topologyMode: this.options.topologyMode} : {}), + connections: this.connections.map((connection) => ({ + host: connection.host, + ...(this.isProxyMode ? {} : {primary: connection.primary}), + healthy: connection.healthy, + latency: connection.latency, + })), + }, + }); + } this.notifyHealthcheck(status); }); }; diff --git a/lib/types.ts b/lib/types.ts index 99becfc..cec05a8 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -33,6 +33,10 @@ export interface PDOptions { healthcheckInterval: number; healthcheckTimeout: number; suppressStatusLogs: boolean; + /** + * suppresses only [Database current status] logs, preserving dispatcher errors and other logs + */ + suppressHealthcheckStatusLogs?: boolean; beforeTerminate: () => Promise; topologyMode: TopologyMode; } diff --git a/tests/dispatcher.test.js b/tests/dispatcher.test.js index c90ebe4..eacd0df 100644 --- a/tests/dispatcher.test.js +++ b/tests/dispatcher.test.js @@ -147,6 +147,35 @@ describe('PGDispatcher topology modes', () => { }); }); +describe('PGDispatcher healthcheck status logging', () => { + test('logs database status by default', async () => { + const {dispatcher, logger} = createDispatcher([ + createKnex(successfulCheckup({pg_is_in_recovery: false})), + ]); + + await dispatcher.ready(); + await new Promise((resolve) => setImmediate(resolve)); + + expect(defaultDispatcherOptions.suppressHealthcheckStatusLogs).toBe(false); + expect(logger.info).toHaveBeenCalledWith( + 'Database current status', + expect.objectContaining({connections: expect.any(Array)}), + ); + }); + + test('suppresses database status while preserving healthcheck errors', async () => { + const {dispatcher, logger} = createDispatcher([createKnex(failedCheckup)], { + suppressHealthcheckStatusLogs: true, + }); + + await dispatcher.ready(); + await new Promise((resolve) => setImmediate(resolve)); + + expect(logger.info).not.toHaveBeenCalled(); + expect(loggedErrorMessages(logger)).toContain('Proxy unavailable'); + }); +}); + describe('PGDispatcher healthcheck callback', () => { test('reports a snapshot for every primary and replica connection', async () => { const onHealthcheck = jest.fn();