diff --git a/core/src/utils/config.ts b/core/src/utils/config.ts index e38d43beb4e..4be29061dae 100644 --- a/core/src/utils/config.ts +++ b/core/src/utils/config.ts @@ -220,6 +220,15 @@ export interface IonicConfig { */ experimentalCloseWatcher?: boolean; + /** + * Developers may configure the logging level for Ionic Framework. + * + * - `OFF` will not log any errors or warnings. + * - `WARN` will log all errors and warnings. + * - `ERROR` will log only errors. + */ + logLevel?: 'OFF' | 'ERROR' | 'WARN'; + // PRIVATE configs keyboardHeight?: number; inputShims?: boolean; diff --git a/core/src/utils/logging/index.ts b/core/src/utils/logging/index.ts index ee4234cb6a5..f5ff24c6949 100644 --- a/core/src/utils/logging/index.ts +++ b/core/src/utils/logging/index.ts @@ -1,3 +1,5 @@ +import { config } from '@global/config'; + /** * Logs a warning to the console with an Ionic prefix * to indicate the library that is warning the developer. @@ -5,7 +7,10 @@ * @param message - The string message to be logged to the console. */ export const printIonWarning = (message: string, ...params: any[]) => { - return console.warn(`[Ionic Warning]: ${message}`, ...params); + const logLevel = config.get('logLevel', 'WARN'); + if (['WARN'].includes(logLevel)) { + return console.warn(`[Ionic Warning]: ${message}`, ...params); + } }; /* @@ -15,8 +20,11 @@ export const printIonWarning = (message: string, ...params: any[]) => { * @param message - The string message to be logged to the console. * @param params - Additional arguments to supply to the console.error. */ -export const printIonError = (message: string, ...params: any) => { - return console.error(`[Ionic Error]: ${message}`, ...params); +export const printIonError = (message: string, ...params: any[]) => { + const logLevel = config.get('logLevel', 'ERROR'); + if (['ERROR', 'WARN'].includes(logLevel)) { + return console.error(`[Ionic Error]: ${message}`, ...params); + } }; /** diff --git a/core/src/utils/logging/test/logging.spec.ts b/core/src/utils/logging/test/logging.spec.ts new file mode 100644 index 00000000000..815a6c6720f --- /dev/null +++ b/core/src/utils/logging/test/logging.spec.ts @@ -0,0 +1,113 @@ +import { config } from '@global/config'; + +import { printIonError, printIonWarning } from '../index'; + +describe('Logging', () => { + describe('#printIonWarning', () => { + let consoleWarnSpy: jest.SpyInstance; + + beforeEach(() => { + consoleWarnSpy = jest.spyOn(console, 'warn'); + // Suppress console.warn output from polluting the test output + consoleWarnSpy.mockImplementation(() => {}); + }); + + afterEach(() => { + consoleWarnSpy.mockRestore(); + }); + + describe('when the logLevel configuration is not set', () => { + it('logs a warning to the console', () => { + config.set('logLevel', undefined); + + printIonWarning('This is a warning message'); + + expect(consoleWarnSpy).toHaveBeenCalledWith('[Ionic Warning]: This is a warning message'); + }); + }); + + describe("when the logLevel configuration is set to 'WARN'", () => { + it('logs a warning to the console', () => { + config.set('logLevel', 'WARN'); + + printIonWarning('This is a warning message'); + + expect(consoleWarnSpy).toHaveBeenCalledWith('[Ionic Warning]: This is a warning message'); + }); + }); + + describe("when the logLevel configuration is set to 'ERROR'", () => { + it('does not log a warning to the console', () => { + config.set('logLevel', 'ERROR'); + + printIonWarning('This is a warning message'); + + expect(consoleWarnSpy).not.toHaveBeenCalled(); + }); + }); + + describe("when the logLevel configuration is set to 'OFF'", () => { + it('does not log a warning to the console', () => { + config.set('logLevel', 'OFF'); + + printIonWarning('This is a warning message'); + + expect(consoleWarnSpy).not.toHaveBeenCalled(); + }); + }); + }); + + describe('#printIonError', () => { + let consoleErrorSpy: jest.SpyInstance; + + beforeEach(() => { + consoleErrorSpy = jest.spyOn(console, 'error'); + // Suppress console.error output from polluting the test output + consoleErrorSpy.mockImplementation(() => {}); + }); + + afterEach(() => { + consoleErrorSpy.mockRestore(); + }); + + describe('when the logLevel configuration is not set', () => { + it('logs an error to the console', () => { + config.set('logLevel', undefined); + + printIonError('This is an error message'); + + expect(consoleErrorSpy).toHaveBeenCalledWith('[Ionic Error]: This is an error message'); + }); + }); + + describe("when the logLevel configuration is set to 'ERROR'", () => { + it('logs an error to the console', () => { + config.set('logLevel', 'ERROR'); + + printIonError('This is an error message'); + + expect(consoleErrorSpy).toHaveBeenCalledWith('[Ionic Error]: This is an error message'); + }); + }); + + describe("when the logLevel configuration is set to 'WARN'", () => { + it('logs an error to the console', () => { + config.set('logLevel', 'WARN'); + + printIonError('This is an error message'); + + expect(consoleErrorSpy).toHaveBeenCalledWith('[Ionic Error]: This is an error message'); + }); + }); + + describe("when the logLevel configuration is set to 'OFF'", () => { + it('does not log an error to the console', () => { + config.set('logLevel', 'OFF'); + + printIonError('This is an error message'); + + expect(consoleErrorSpy).not.toHaveBeenCalled(); + }); + }); + }); +});