% % ----------------- % 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 fid; end methods(Static) function obj = getInstance() persistent instance; if isempty(instance) instance = base_logger(); end obj = instance; end end methods 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 = strftime('%Y-%m-%d %H:%M:%S', localtime(time())); stack = dbstack('-completenames'); if length(stack) > 2 script_name = stack(3).name; else script_name = 'Unknown'; end message = sprintf(''); for i = 1:numel(varargin) if isstruct(varargin{i}) && isfield(varargin{i}, 'message') && isfield(varargin{i}, 'stack') error_info = varargin{i}; message = sprintf('%sError: %s\n', message, error_info.message); for j = 1:length(error_info.stack) message = sprintf('%s at %s (line %d)\n', message, error_info.stack(j).name, error_info.stack(j).line); end elseif isnumeric(varargin{i}) || islogical(varargin{i}) message = sprintf('%s%s', message, num2str(varargin{i})); elseif ischar(varargin{i}) || isstring(varargin{i}) message = sprintf('%s%s', message, varargin{i}); else message = sprintf('%sUnsupported data type', message); end if i < numel(varargin) message = sprintf('%s, ', message); end end fprintf(this.fid, '%s %s %s %s\n', current_time, level, script_name, message); end 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