I have developed an implementation of a logger in Python. I know that Python already has a built-in logger, my goal with this is to get feedback and suggestions for improvement, particularly about code structure.
Code is here:
from .helpers import write_txt
from enum import Enum
from datetime import datetime
# Define type formats of messages
class LogFormats(Enum):
TITLE = 'title'
SUBTITLE = 'subtitle'
ERROR = 'error'
TAB = 'tab'
DEFAULT = 'default'
# Handler functions for output messages with different formats
def format_title(message: str, time: str) -> str:
to_print = f"\n[{time}] ### ### {message.upper()} ### ###\n"
return to_print
def format_subtitle(message: str, time: str) -> str:
to_print = f"[{time}] *** *** {message.upper()} *** ***"
return to_print
def format_error(message: str, time: str) -> str:
to_print = f"[{time}]\t ERROR: {message}"
return to_print
def format_tab(message: str, time: str) -> str:
to_print = f"[{time}]\t {message}"
return to_print
def format_default(message: str, time: str) -> str:
to_print = f"[{time}] - {message}"
return to_print
# Handler functions dispatcher
FORMATTER_DISPATCH = {
LogFormats.TITLE: format_title,
LogFormats.SUBTITLE: format_subtitle,
LogFormats.ERROR: format_error,
LogFormats.TAB: format_tab,
LogFormats.DEFAULT: format_default
}
class txtFileLogger():
"""Provides functionality for logging to a txt file"""
registry: str = ''
@classmethod
def register_log(cls, msg: str) -> None:
cls.registry = cls.registry + '\n' + msg
@classmethod
def output_log_to_txt(cls, filename = 'txt_log') -> None:
write_txt(cls.registry, filename)
# ===================
# MAIN CLASS
#====================
class Logger():
"""Format log messages and outputs it to the console. Also, provide methods for dumping the log session to a txt file."""
txt_logger = txtFileLogger
silenced = False
@classmethod
def log(cls,
message: str,
format: LogFormats = LogFormats.DEFAULT,
hidden: bool = False
) -> None:
"""
Logs a log message.
This function logs a message and prints it to the console. The log type can be specified for different message formats. Also the console output can be toggled.
Args:
message (str): The message to be logged.
type (LogTypes, optional): The log type.
hidden (bool, optional): If set to True, hides the log in the console for this message. The message will be registered and dumped in txt file regardless of this option.
"""
current_time = datetime.now().strftime("%H:%M:%S")
msg = str(message)
# Format log message according to selected type format
log_type = LogFormats(format)
formatter = FORMATTER_DISPATCH[log_type]
formated_msg = formatter(msg, current_time)
# Registers log for txt file output
cls.txt_logger.register_log(formated_msg)
# Print log to console
if not hidden and not cls.silenced:
print(formated_msg)
@classmethod
def dump_log_to_txt(cls, filename: str) -> None:
"""Writes log to a txt file"""
cls.txt_logger.output_log_to_txt(filename)
@classmethod
def mute(cls) -> None:
"""Disables console output."""
cls.silenced = True
print('[Logger] - *** Output to console is currently silenced ***')
@classmethod
def unmute(cls) -> None:
"""Enables console output."""
cls.silenced = False
print('[Logger] - *** Enabling logging to console ***')
I implemented this using the class as a kind of "singleton". Thus, I could call the logger in different files and mantain a single source of truth for the registry. Example of usage:
import Logger
log = Logger.log
log('message 1', format='title')
log('message 2', format='subtitle')
log('error message', format='error')
Logger.dump_log_to_txt('foo_filename')
Some general questions:
- Is there any way to improve the efficiency of my logger implementation?
- How can I make my code more readable and well-structured?
I appreciate any feedback and suggestions. Thank you!
helpers.write_txtfunction should also be described in this post to make the module usable. \$\endgroup\$