feat(config): add logLevel option to suppress ionic warnings and errors (#30015)

resolves #29814

---------

- Developers can assign a value to `logLevel` in the Ionic config to control the log level that Ionic Framework will produce logs for.
  - `OFF` will completely disable all warnings and errors from Ionic
  - `WARN` will log warnings and errors
  - `ERROR` will log only errors
- Default behavior is that developers receive both Ionic warnings and errors
- Configuration only applies to usages of `printIonWarning` and `printIonError`

---------

Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
This commit is contained in:
Sean Perkins
2025-01-20 15:15:02 -06:00
committed by GitHub
parent 3f8346e718
commit efd3e0fd2b
3 changed files with 142 additions and 4 deletions

View File

@@ -2,6 +2,7 @@ import type { SpinnerTypes } from '../components/spinner/spinner-configs';
import type { TabButtonLayout } from '../components/tab-bar/tab-bar-interface';
import type { AnimationBuilder, Mode } from '../interface';
import type { LogLevel } from './logging';
import type { PlatformConfig } from './platform';
export interface IonicConfig {
@@ -220,6 +221,15 @@ export interface IonicConfig {
*/
experimentalCloseWatcher?: boolean;
/**
* Configures the logging level for Ionic Framework:
*
* - `'OFF'`: No errors or warnings are logged.
* - `'ERROR'`: Logs only errors.
* - `'WARN'`: Logs errors and warnings.
*/
logLevel?: LogLevel;
// PRIVATE configs
keyboardHeight?: number;
inputShims?: boolean;

View File

@@ -1,3 +1,11 @@
import { config } from '@global/config';
export const enum LogLevel {
OFF = 'OFF',
ERROR = 'ERROR',
WARN = 'WARN',
}
/**
* Logs a warning to the console with an Ionic prefix
* to indicate the library that is warning the developer.
@@ -5,18 +13,24 @@
* @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', LogLevel.WARN);
if ([LogLevel.WARN].includes(logLevel)) {
return console.warn(`[Ionic Warning]: ${message}`, ...params);
}
};
/*
/**
* Logs an error to the console with an Ionic prefix
* to indicate the library that is warning the developer.
*
* @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', LogLevel.ERROR);
if ([LogLevel.ERROR, LogLevel.WARN].includes(logLevel)) {
return console.error(`[Ionic Error]: ${message}`, ...params);
}
};
/**

View File

@@ -0,0 +1,114 @@
import { config } from '@global/config';
import { LogLevel } from '../index';
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', 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', 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', 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', 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', 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', LogLevel.OFF);
printIonError('This is an error message');
expect(consoleErrorSpy).not.toHaveBeenCalled();
});
});
});
});