From d773ea3a60cb1b10e97c83b51e3856fc5caeb79d Mon Sep 17 00:00:00 2001 From: MEHRSHAD MIRSHEKARY Date: Sun, 18 Aug 2024 23:24:17 +0330 Subject: [PATCH] :zap::sparkles: feat: add constant format_options & Update conf settings Added constants/format_options: Format Options Constants: Added a set of predefined format options for log file formats, console logs, and email notifications. Users can now choose from these predefined formats to simplify configuration and ensure consistency. Updated LogConfig Class: New Attributes: log_file_formats: Customizable formats for log files based on log levels. console_level: Log level for console output. console_format: Format for console logs. log_date_format: Date format for log entries. log_email_notifier_log_format: Format for email notifications. New Methods: _resolve_file_formats: Resolves and applies default formats if not specified for each log level. resolve_format: Resolves format based on either an integer index or a string format. Updated LogManager Class: Formatters: Applied custom formats for file, console, and email notifications. Filters: Added LoggingLevelFilter to ensure log records are filtered based on their levels. Loggers: Configured loggers for each log level with their respective handlers and formatters. Closes #12 --- django_logging/apps.py | 17 +++++- django_logging/constants/__init__.py | 1 + django_logging/constants/format_options.py | 15 +++++ django_logging/settings/conf.py | 68 ++++++++++++++++++++-- django_logging/utils/setup_conf.py | 29 +++++++-- 5 files changed, 118 insertions(+), 12 deletions(-) create mode 100644 django_logging/constants/__init__.py create mode 100644 django_logging/constants/format_options.py diff --git a/django_logging/apps.py b/django_logging/apps.py index 9970470..f3a3b14 100644 --- a/django_logging/apps.py +++ b/django_logging/apps.py @@ -18,12 +18,27 @@ def ready(self): "LOG_FILE_LEVELS", ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] ) log_dir = log_settings.get("LOG_DIR", os.path.join(os.getcwd(), "logs")) + log_file_formats = log_settings.get("LOG_FILE_FORMATS", {}) + console_level = log_settings.get("LOG_CONSOLE_LEVEL", "DEBUG") + console_format = log_settings.get("LOG_CONSOLE_FORMAT") + log_date_format = log_settings.get("LOG_DATE_FORMAT", "%Y-%m-%d %H:%M:%S") log_email_notifier = log_settings.get("LOG_EMAIL_NOTIFIER", {}) log_email_notifier_enable = log_email_notifier.get("ENABLE", False) log_email_notifier_log_levels = [ "ERROR" if log_email_notifier.get("NOTIFY_ERROR", False) else None, "CRITICAL" if log_email_notifier.get("NOTIFY_CRITICAL", False) else None, ] + log_email_notifier_log_format = log_email_notifier.get("LOG_FORMAT") # Set the logging configuration - set_logging(log_levels, log_dir, log_email_notifier_enable, log_email_notifier_log_levels) + set_logging( + log_levels, + log_dir, + log_file_formats, + console_level, + console_format, + log_date_format, + log_email_notifier_enable, + log_email_notifier_log_levels, + log_email_notifier_log_format + ) diff --git a/django_logging/constants/__init__.py b/django_logging/constants/__init__.py new file mode 100644 index 0000000..d9bac99 --- /dev/null +++ b/django_logging/constants/__init__.py @@ -0,0 +1 @@ +from .format_options import FORMAT_OPTIONS diff --git a/django_logging/constants/format_options.py b/django_logging/constants/format_options.py new file mode 100644 index 0000000..11a8fdb --- /dev/null +++ b/django_logging/constants/format_options.py @@ -0,0 +1,15 @@ +FORMAT_OPTIONS = { + 1: "%(levelname)s | %(asctime)s | %(module)s | %(message)s", + 2: "%(levelname)s | %(asctime)s | %(message)s", + 3: "%(levelname)s | %(message)s", + 4: "%(asctime)s - %(name)s - %(levelname)s - %(message)s", + 5: "%(levelname)s | %(message)s | [in %(pathname)s:%(lineno)d]", + 6: "%(asctime)s | %(levelname)s | %(message)s", + 7: "%(levelname)s | %(asctime)s | in %(module)s: %(message)s", + 8: "%(levelname)s | %(message)s | [%(filename)s:%(lineno)d]", + 9: "[%(asctime)s] | %(levelname)s | in %(module)s: %(message)s", + 10: "%(asctime)s | %(processName)s | %(name)s | %(levelname)s | %(message)s", + 11: "%(asctime)s | %(threadName)s | %(name)s | %(levelname)s | %(message)s", + 12: "%(levelname)s | [%(asctime)s] | (%(filename)s:%(lineno)d) | %(message)s", + 13: "%(levelname)s | [%(asctime)s] | {%(name)s} | (%(filename)s:%(lineno)d): %(message)s", +} diff --git a/django_logging/settings/conf.py b/django_logging/settings/conf.py index f2eaa97..85a1d9c 100644 --- a/django_logging/settings/conf.py +++ b/django_logging/settings/conf.py @@ -1,8 +1,9 @@ import logging import logging.config import os -from typing import List, Dict, Optional +from typing import List, Dict, Optional, Union +from django_logging.constants import FORMAT_OPTIONS from django_logging.filters.level_filter import LoggingLevelFilter @@ -19,14 +20,54 @@ def __init__( self, log_levels: List[str], log_dir: str, + log_file_formats: Dict[str, Union[int, str]], + console_level: str, + console_format: Optional[Union[int, str]], + log_date_format: str, log_email_notifier_enable: bool, log_email_notifier_log_levels: List[str], + log_email_notifier_log_format: Union[int, str], ) -> None: self.log_levels = log_levels self.log_dir = log_dir + self.log_file_formats = self._resolve_file_formats(log_file_formats) + self.log_date_format = log_date_format + self.console_level = console_level + self.console_format = self.resolve_format(console_format) self.email_notifier_enable = log_email_notifier_enable self.email_notifier_log_levels = log_email_notifier_log_levels + self.email_notifier_log_format = self.resolve_format( + log_email_notifier_log_format + ) + + def _resolve_file_formats(self, log_file_formats: Dict[str, Union[int, str]]) -> Dict: + resolved_formats = {} + for level in self.log_levels: + format_option = log_file_formats.get(level, None) + if format_option: + if isinstance(format_option, int): + resolved_formats[level] = FORMAT_OPTIONS.get( + format_option, FORMAT_OPTIONS[1] + ) + else: + resolved_formats[level] = format_option + else: + resolved_formats[level] = FORMAT_OPTIONS[1] + + return resolved_formats + + @staticmethod + def resolve_format(_format: Union[int, str]) -> str: + if _format: + if isinstance(_format, int): + resolved_format = FORMAT_OPTIONS.get(_format, FORMAT_OPTIONS[1]) + else: + resolved_format = _format + else: + resolved_format = FORMAT_OPTIONS[1] + + return resolved_format class LogManager: @@ -72,7 +113,7 @@ def set_conf(self) -> None: level.lower(): { "class": "logging.FileHandler", "filename": log_file, - "formatter": "default", + "formatter": f"{level.lower()}", "level": level, "filters": [level.lower()] } @@ -81,19 +122,18 @@ def set_conf(self) -> None: handlers["console"] = { "class": "logging.StreamHandler", "formatter": "console", - "level": "DEBUG", + "level": self.log_config.console_level, } - email_handler = { f"email_{level.lower()}": { "class": "django_logging.handlers.EmailHandler", + "formatter": "email", "level": level, "filters": [level.lower()], } for level in self.log_config.email_notifier_log_levels if level } - if self.log_config.email_notifier_enable: handlers.update(email_handler) @@ -105,6 +145,23 @@ def set_conf(self) -> None: for level in self.log_config.log_levels } + formatters = { + level.lower(): { + "format": self.log_config.log_file_formats[level], + "datefmt": self.log_config.log_date_format, + } + for level in self.log_config.log_levels + } + formatters["console"] = { + "format": self.log_config.console_format, + "datefmt": self.log_config.log_date_format, + } + + formatters["email"] = { + "format": self.log_config.email_notifier_log_format, + "datefmt": self.log_config.log_date_format, + } + loggers = { level.lower(): { "level": level, @@ -116,6 +173,7 @@ def set_conf(self) -> None: config = { "version": 1, + "formatters": formatters, "handlers": handlers, "filters": filters, "loggers": loggers, diff --git a/django_logging/utils/setup_conf.py b/django_logging/utils/setup_conf.py index 2ab38cf..d81a0be 100644 --- a/django_logging/utils/setup_conf.py +++ b/django_logging/utils/setup_conf.py @@ -1,12 +1,19 @@ from django_logging.settings.conf import LogConfig, LogManager -from typing import List +from typing import List, Optional, Union, Dict -def set_logging(log_levels: List[str], - log_dir: str, - log_email_notifier_enable: bool, - log_email_notifier_log_levels: List[str]): +def set_logging( + log_levels: List[str], + log_dir: str, + log_file_formats: Dict[str, Union[int, str]], + console_level: str, + console_format: Optional[Union[int, str]], + log_date_format: str, + log_email_notifier_enable: bool, + log_email_notifier_log_levels: List[str], + log_email_notifier_log_format: Union[int, str] +): """ Sets up the logging configuration. @@ -14,7 +21,17 @@ def set_logging(log_levels: List[str], log_levels (List[str]): A list of log levels to configure. log_dir (str): The directory where log files will be stored. """ - log_config = LogConfig(log_levels, log_dir, log_email_notifier_enable, log_email_notifier_log_levels) + log_config = LogConfig( + log_levels, + log_dir, + log_file_formats, + console_level, + console_format, + log_date_format, + log_email_notifier_enable, + log_email_notifier_log_levels, + log_email_notifier_log_format + ) log_manager = LogManager(log_config) log_manager.create_log_files() log_manager.set_conf()