% % ----------------- % Copyright © 2024 ACK Cyfronet AGH, Poland. % ----------------- % % BASE_LOGGER A singleton logger class for logging messages to a file. % % This class implements a simple logging mechanism with different log levels % (TRACE, DEBUG, INFO, WARNING, ERROR) and writes log entries to a file. % It follows the Singleton pattern to ensure that only one instance of the logger % exists throughout the application. % % Properties: % fid - (private) The file identifier for the log file. This is used to write logs. % % Methods: % % getInstance() - Retrieves the singleton instance of the logger. % % trace(message) - Logs a message with TRACE level. % @param message The message to log. % % debug(message) - Logs a message with DEBUG level. % @param message The message to log. % % info(message) - Logs a message with INFO level. % @param message The message to log. % % warning(message) - Logs a message with WARNING level. % @param message The message to log. % % error(message) - Logs a message with ERROR level. % @param message The message to log. % % delete() - Destructor method that closes the file identifier when the logger is deleted. % % Example Usage: % logger = base_logger.getInstance(); % logger.info('Some info') % % try % % some code causing exception % catch err % logger.error('An error occurred:', err); % end % % See also: fopen, fclose, dbstack, fprintf classdef base_logger < handle properties(Access=private) fid; end methods(Static, Access = public) function obj = getInstance() persistent instance; if isempty(instance) instance = base_logger(); end obj = instance; end end methods(Access=private) function this = base_logger() logFileName = getenv("APP_LOG_FILE"); if isempty(logFileName) logFileName = 'base-logger-log.log'; end this.fid = fopen(logFileName, 'a'); if this.fid == -1 error('Failed to open log file'); end end function log(this, level, varargin) current_time = datestr(now, 'yyyy-mm-dd HH:MM:SS'); stack = dbstack('-completenames'); if length(stack) > 2 script_name = stack(3).name; else script_name = 'Unknown'; end message = ""; for i = 1:numel(varargin) if isa(varargin{i}, 'MException') message = sprintf('%sError: %s\n', message, varargin{i}.message); for j = 1:length(varargin{i}.stack) message = sprintf('%s at %s (line %d)\n', message, varargin{i}.stack(j).name, varargin{i}.stack(j).line); end elseif isnumeric(varargin{i}) || isenum(varargin{i}) || islogical(varargin{i}) message = strcat(message, string(varargin{i})); elseif ischar(varargin{i}) || isstring(varargin{i}) message = strcat(message, varargin{i}); else message = strcat(message, 'Unsupported data type'); end if i < numel(varargin) message = strcat(message, ", "); end end fprintf(this.fid, '%s %s %s %s\n', current_time, level, script_name, message); end end methods(Access=public) function trace(this, varargin) this.log('TRACE', varargin{:}); end function debug(this, varargin) this.log('DEBUG', varargin{:}); end function info(this, varargin) this.log('INFO', varargin{:}); end function warning(this, varargin) this.log('WARNING', varargin{:}); end function error(this, varargin) this.log('ERROR', varargin{:}); end function delete(this) if this.fid ~= -1 fclose(this.fid); end end end end