From f82df2921846332d7916ca2d867735cdca419963 Mon Sep 17 00:00:00 2001 From: John Ruckstuhl Date: Tue, 30 Aug 2022 14:05:10 -0700 Subject: [PATCH] implement raiseExceptions aka throwExceptions If the package attribute raiseExceptions is False, exceptions get silently ignored. This is what is mostly wanted for a logging system - most users will not care about errors in the logging system, they are more interested in application errors. ... (The default value of raiseExceptions is True, as that is more useful during development). --- Mcode/+logger/Logger.m | 50 ++++++++++++++++++++++++++------- Mcode/+logger/raiseExceptions.m | 46 ++++++++++++++++++++++++++++++ Mcode/+logger/throwExceptions.m | 12 ++++++++ 3 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 Mcode/+logger/raiseExceptions.m create mode 100644 Mcode/+logger/throwExceptions.m diff --git a/Mcode/+logger/Logger.m b/Mcode/+logger/Logger.m index fcc2ae83..3e29c4bc 100644 --- a/Mcode/+logger/Logger.m +++ b/Mcode/+logger/Logger.m @@ -106,8 +106,14 @@ function error(this, msg, varargin) if ~this.jLogger.isErrorEnabled() return end - msgStr = formatMessage(msg, varargin{:}); - this.jLogger.error(msgStr); + try + msgStr = formatMessage(msg, varargin{:}); + this.jLogger.error(msgStr); + catch ME + if logger.raiseExceptions + throw(ME) + end + end end function warn(this, msg, varargin) @@ -115,8 +121,14 @@ function warn(this, msg, varargin) if ~this.jLogger.isWarnEnabled() return end - msgStr = formatMessage(msg, varargin{:}); - this.jLogger.warn(msgStr); + try + msgStr = formatMessage(msg, varargin{:}); + this.jLogger.warn(msgStr); + catch ME + if logger.raiseExceptions + throw(ME) + end + end end function info(this, msg, varargin) @@ -124,8 +136,14 @@ function info(this, msg, varargin) if ~this.jLogger.isInfoEnabled() return end - msgStr = formatMessage(msg, varargin{:}); - this.jLogger.info(msgStr); + try + msgStr = formatMessage(msg, varargin{:}); + this.jLogger.info(msgStr); + catch ME + if logger.raiseExceptions + throw(ME) + end + end end function debug(this, msg, varargin) @@ -133,8 +151,14 @@ function debug(this, msg, varargin) if ~this.jLogger.isDebugEnabled() return end - msgStr = formatMessage(msg, varargin{:}); - this.jLogger.debug(msgStr); + try + msgStr = formatMessage(msg, varargin{:}); + this.jLogger.debug(msgStr); + catch ME + if logger.raiseExceptions + throw(ME) + end + end end function trace(this, msg, varargin) @@ -142,8 +166,14 @@ function trace(this, msg, varargin) if ~this.jLogger.isTraceEnabled() return end - msgStr = formatMessage(msg, varargin{:}); - this.jLogger.trace(msgStr); + try + msgStr = formatMessage(msg, varargin{:}); + this.jLogger.trace(msgStr); + catch ME + if logger.raiseExceptions + throw(ME) + end + end end function errorj(this, msg, varargin) diff --git a/Mcode/+logger/raiseExceptions.m b/Mcode/+logger/raiseExceptions.m new file mode 100644 index 00000000..5aa1ca6c --- /dev/null +++ b/Mcode/+logger/raiseExceptions.m @@ -0,0 +1,46 @@ +function varargout = raiseExceptions(newval) +%RAISEEXCEPTIONS gets/sets a flag for handling exceptions during logging +% RAISEEXCEPTIONS gets or sets a flag that is used by the logic that +% controls the handling of exceptions raised/thrown during logging. +% The default flag value is true. +% +% Usage +% % suppress exceptions during logging framework message handling +% logger.raiseExceptions(false) + +%{ +This mechanism is inspired by a comment from Martijn Pieters in +https://stackoverflow.com/questions/66587941/what-happens-if-a-python-logging-handler-raises-an-exception + +"The Python standard-library handlers have been build with robustness in +mind. If an exception is raised ..., all standard library +implementations catch the exception and ... +By default, ... re-raises the exception. In production systems you want +to set logging.raiseExceptions = False, at which point the exceptions +are silently ignored, and logging continues as if nothing happened. + +From the documentation: ... If the module-level attribute +raiseExceptions is False, exceptions get silently ignored. This is what +is mostly wanted for a logging system - most users will not care about +errors in the logging system, they are more interested in application +errors. ... (The default value of raiseExceptions is True, as that is +more useful during development)." +%} + +persistent flag + +if isempty(flag) + flag = true; +end + +switch nargin + case 0 % get + varargout{1} = flag; + case 1 % set + assert(isscalar(newval) & islogical(newval), 'bad usage') + flag = newval; + otherwise + assert(false, 'impossible') +end + +end diff --git a/Mcode/+logger/throwExceptions.m b/Mcode/+logger/throwExceptions.m new file mode 100644 index 00000000..383bfc42 --- /dev/null +++ b/Mcode/+logger/throwExceptions.m @@ -0,0 +1,12 @@ +function varargout = throwExceptions(varargin) +%THROWEXCEPTIONS is an alias for RAISEEXCEPTIONS +% RAISEEXCEPTIONS is inspired by the Python standard library +% framework. +% In MATLAB, exceptions are 'thrown' rather than 'raised', so +% THROWEXCEPTIONS is provided as a more MATLAB-consistent alias. +% +% Usage +% % suppress exceptions during logging framework message handling +% logger.throwExceptions(false) + +[varargout{1:nargout}] = logger.raiseExceptions(varargin{:});