How to make a logging script that works globally for an entire python program. I want it to use OOP, have decorators, and is refactored. Make sure that I can call the same instance of the logger across multiple scripts, and that I can input a message type and message into the decorator and it all logs into the same log file. Add an option so I can also time the execution functions as well. Make the logging decorator a child class of the Logger class, make sure that I can call LoggerDecorator into any script and it will all refer to the same instance
Certainly! Here's an updated version where the logging decorator is implemented as a child class of the Logger
class, and you can call LoggerDecorator
into any script, and it will refer to the same instance of the logger:
import logging
import timeit
from functools import wraps
class Logger:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.logger = logging.getLogger(__name__)
cls._instance.logger.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
# Define the log file name and create a file handler
file_handler = logging.FileHandler("app.log")
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
cls._instance.logger.addHandler(file_handler)
# Create a stream handler to print log messages to the console
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
stream_handler.setFormatter(formatter)
cls._instance.logger.addHandler(stream_handler)
return cls._instance
def log(self, level, message):
self.logger.log(level, message)
def debug(self, message):
self.log(logging.DEBUG, message)
def info(self, message):
self.log(logging.INFO, message)
def warning(self, message):
self.log(logging.WARNING, message)
def error(self, message):
self.log(logging.ERROR, message)
def critical(self, message):
self.log(logging.CRITICAL, message)
class LoggerDecorator(Logger):
def log_execution(self, message_type, message, time_execution=False):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
function_name = func.__name__
args_string = ", ".join(repr(arg) for arg in args)
kwargs_string = ", ".join(f"{key}={repr(value)}" for key, value in kwargs.items())
all_args = ", ".join(filter(None, [args_string, kwargs_string]))
self.log(logging.INFO, f"{message_type}: {message}")
self.log(logging.INFO, f"Executing {function_name}({all_args})")
if time_execution:
start_time = timeit.default_timer()
result = func(*args, **kwargs)
if time_execution:
end_time = timeit.default_timer()
elapsed_time = end_time - start_time
self.log(logging.INFO, f"{function_name} executed in {elapsed_time:.6f} seconds")
return result
return wrapper
return decorator
In this updated version, the LoggerDecorator
class is a child class of Logger
, and it includes the log_execution
method as the decorator. By inheriting from Logger
, LoggerDecorator
has access to the logging functionality provided by the Logger
class.
You can now use LoggerDecorator
as follows in any script:
from logger import LoggerDecorator
logger = LoggerDecorator()
@logger.log_execution("Custom", "Custom log message", time_execution=True)
def my_function():
logger.info("This is a log message from my_function.")
# Usage in other scripts
# ...
In any script where you import and create an instance of LoggerDecorator
as logger
, it will refer to the same logging instance as other scripts. Therefore, all log messages logged through the LoggerDecorator
instance will be directed to the same log file ("app.log" in this case).