ISEPOS-2280 Added base loggers scripts #1
111
matlab/logging/base_logger.m
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
%
|
||||||
|
% -----------------
|
||||||
|
% 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('This is an info message');
|
||||||
|
% logger.error('This is an error message');
|
||||||
|
|||||||
|
%
|
||||||
|
% 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()
|
||||||
|
this.fid = fopen(getenv("DEFAULT_LOG_PATH"), 'a');
|
||||||
|
if this.fid == -1
|
||||||
|
error('Failed to open log file: application.log');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function log(this, level, message)
|
||||||
|
current_time = datetime('now', 'Format', 'yyyy-MM-dd HH:mm:ss');
|
||||||
asia marked this conversation as resolved
Outdated
asia
commented
Can we use a different name? Something that we would consider a log file at first glance ('fallbackPath' is something I wouldn't) - if we don't want to make it too simple, to avoid name collision with other things, maybe e.g. base-app-log.log or base-logger-log.log or something like that Can we use a different name? Something that we would consider a log file at first glance ('fallbackPath' is something I wouldn't) - if we don't want to make it too simple, to avoid name collision with other things, maybe e.g. base-app-log.log or base-logger-log.log or something like that
|
|||||||
|
stack = dbstack('-completenames');
|
||||||
|
if length(stack) > 2
|
||||||
|
script_name = stack(3).name;
|
||||||
|
else
|
||||||
|
script_name = 'Unknown';
|
||||||
|
end
|
||||||
|
|
||||||
|
if this.fid ~= -1
|
||||||
|
fprintf(this.fid, '%s %s %s %s\n', char(current_time), level, script_name, message);
|
||||||
|
else
|
||||||
|
error('File identifier is invalid. Cannot write to log.');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
methods(Access=public)
|
||||||
|
function trace(this, message)
|
||||||
|
this.log("TRACE", message);
|
||||||
|
end
|
||||||
|
|
||||||
|
function debug(this, message)
|
||||||
|
this.log("DEBUG", message);
|
||||||
|
end
|
||||||
|
|
||||||
|
function info(this, message)
|
||||||
|
this.log("INFO", message);
|
||||||
|
end
|
||||||
|
|
||||||
|
function warning(this, message)
|
||||||
|
this.log("WARNING", message);
|
||||||
|
end
|
||||||
|
|
||||||
|
function error(this, message)
|
||||||
|
this.log("ERROR", message);
|
||||||
|
end
|
||||||
|
|
||||||
|
function delete(this)
|
||||||
|
if this.fid ~= -1
|
||||||
|
fclose(this.fid);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
111
octave/logging/base_logger.m
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
%
|
||||||
|
% -----------------
|
||||||
|
% 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('This is an info message');
|
||||||
|
% logger.error('This is an error message');
|
||||||
|
%
|
||||||
|
% 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()
|
||||||
|
this.fid = fopen(getenv("DEFAULT_LOG_PATH"), 'a');
|
||||||
|
if this.fid == -1
|
||||||
|
error('Failed to open log file: application.log');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function log(this, level, message)
|
||||||
|
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
|
||||||
|
|
||||||
|
if this.fid ~= -1
|
||||||
|
fprintf(this.fid, '%s %s %s %s\n', char(current_time), level, script_name, message);
|
||||||
|
else
|
||||||
|
error('File identifier is invalid. Cannot write to log.');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
methods(Access=public)
|
||||||
|
function trace(this, message)
|
||||||
|
this.log("TRACE", message);
|
||||||
|
end
|
||||||
|
|
||||||
|
function debug(this, message)
|
||||||
|
this.log("DEBUG", message);
|
||||||
|
end
|
||||||
|
|
||||||
|
function info(this, message)
|
||||||
|
this.log("INFO", message);
|
||||||
|
end
|
||||||
|
|
||||||
|
function warning(this, message)
|
||||||
|
this.log("WARNING", message);
|
||||||
|
end
|
||||||
|
|
||||||
|
function error(this, message)
|
||||||
|
this.log("ERROR", message);
|
||||||
|
end
|
||||||
|
|
||||||
|
function delete(this)
|
||||||
|
if this.fid ~= -1
|
||||||
|
fclose(this.fid);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
55
python/logging/base_logger.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#
|
||||||
|
# -----------------
|
||||||
|
# Copyright © 2024 ACK Cyfronet AGH, Poland.
|
||||||
|
# -----------------
|
||||||
|
#
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
def getDefaultLogger(name):
|
||||||
|
"""
|
||||||
|
Retrieves or creates a logger with the specified name and sets it up with a file handler.
|
||||||
|
|
||||||
|
The logger is configured to write log messages to the file path specified by the
|
||||||
|
'DEFAULT_LOG_PATH' environment variable. It uses the 'INFO' level as the default
|
||||||
asia
commented
I think the name was changed to 'APP_LOG_FILE' I think the name was changed to 'APP_LOG_FILE'
|
|||||||
|
logging level and writes log entries in the following format:
|
||||||
|
|
||||||
|
'YYYY-MM-DD HH:MM:SS,ms LEVEL logger_name message'
|
||||||
|
|
||||||
|
If the logger does not already have handlers, a file handler is created, and the
|
||||||
|
logging output is appended to the file. The log format includes the timestamp with
|
||||||
|
milliseconds, log level, logger name, and the log message.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
-----------
|
||||||
|
name : str
|
||||||
|
The name of the logger. This can be the name of the module or any identifier
|
||||||
|
that you want to associate with the logger.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
--------
|
||||||
|
logger : logging.Logger
|
||||||
|
A logger instance with the specified name. The logger is configured with a
|
||||||
|
file handler that writes to the file specified by the 'DEFAULT_LOG_PATH'
|
||||||
|
environment variable.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
-------
|
||||||
|
KeyError:
|
||||||
|
If the 'DEFAULT_LOG_PATH' environment variable is not set.
|
||||||
asia
commented
Here, again, the name of the variable should be updated. But I thought also that instead of throwing an error, we might use some default file name, to allow users to run the app also outside of the platform. But, I would set the default log file name to something different than "application.log", so that we know that we could notice if something is wrong with setting the environment variable. Here, again, the name of the variable should be updated. But I thought also that instead of throwing an error, we might use some default file name, to allow users to run the app also outside of the platform. But, I would set the default log file name to something different than "application.log", so that we know that we could notice if something is wrong with setting the environment variable.
|
|||||||
|
|
||||||
|
Example:
|
||||||
|
--------
|
||||||
|
logger = getDefaultLogger(__name__)
|
||||||
|
logger.info("This is an info message.")
|
||||||
asia
commented
An example with an error with logging stack trace would be convenient here An example with an error with logging stack trace would be convenient here
ymlesni
commented
Example for error with stack trace logging has been added. Example for error with stack trace logging has been added.
|
|||||||
|
|
||||||
|
"""
|
||||||
asia
commented
Maybe just put here some placeholder meaning that this is a code that may produce an error Maybe just put here some placeholder meaning that this is a code that may produce an error
ymlesni
commented
Ok, I will do the same for Matlab and Octave versions. Ok, I will do the same for Matlab and Octave versions.
|
|||||||
|
logger = logging.getLogger(name)
|
||||||
|
if not logger.hasHandlers():
|
||||||
asia
commented
We have We have `except Exception as e` but the `e` is not used anywhere... is this correct?
h.siejkowski
commented
Maybe it is good to use here the Maybe it is good to use here the `logger.exception()` ([doc](https://docs.python.org/3/library/logging.html#logging.Logger.exception)) method as a showcase.
ymlesni
commented
`e` could be used to process exception further, but it is not necessary for example, I will remove it.
Would adding `logger.exception()` as a additional option be a good idea (to still showcase how to log exception at chosen log level)? For now I will change to `logger.exception()`.
|
|||||||
|
file_handler = logging.FileHandler(os.environ['DEFAULT_LOG_PATH'], mode='a')
|
||||||
|
formatter = logging.Formatter('%(asctime)s,%(msecs)d %(levelname)s %(name)s %(message)s')
|
||||||
|
file_handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(file_handler)
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
return logger
|
Can we put here an example with error object? So that the stack trace of the exception gets logged.
Base logger has been enchanced and example for error logging has been added.