From 02f835c7dc18aacdb42280a334499371875622ba Mon Sep 17 00:00:00 2001 From: MEHRSHAD MIRSHEKARY Date: Wed, 21 Aug 2024 12:28:01 +0330 Subject: [PATCH] :zap::sparkles::hammer::art: feat: add AUTO_INITIALIZATION_ENABLE flag & Refactor context_manager Added new confing 'AUTO_INITIALIZATON_ENABLE' Added now config's DEFAULT and TypeAnnotation --------- Updated get_conf module to implement is_auto_initialization_enabled method Updated setup_logging to Apply new config when is_auto_initialization_enabled() returns True, set_logging will set the configuration and DJANGO_LOGGING starts working by runnig server Refactured context_manager: if is_auto_initialization_enabled returns True, it raises ValueError, otherwise it will run DJANGO_LOGGING inside 'with' block that has been called Updated utils Structure & move email_notifier from email to parent directory --- django_logging/constants/__init__.py | 1 + django_logging/constants/default_settings.py | 11 +++- django_logging/constants/settings_types.py | 1 + django_logging/handlers/email_handler.py | 2 +- django_logging/settings/checks.py | 21 +++++-- django_logging/utils/context_manager.py | 61 +++++++++++++++---- django_logging/utils/email/__init__.py | 1 - .../{email/notifier.py => email_notifier.py} | 0 django_logging/utils/get_config.py | 30 +++++---- django_logging/utils/log_and_notify.py | 2 +- django_logging/utils/setup_logging.py | 4 ++ 11 files changed, 100 insertions(+), 34 deletions(-) delete mode 100644 django_logging/utils/email/__init__.py rename django_logging/utils/{email/notifier.py => email_notifier.py} (100%) diff --git a/django_logging/constants/__init__.py b/django_logging/constants/__init__.py index 0b7235e..ceb08cd 100644 --- a/django_logging/constants/__init__.py +++ b/django_logging/constants/__init__.py @@ -1,5 +1,6 @@ from .format_options import FORMAT_OPTIONS from .default_settings import ( + DEFAULT_AUTO_INITIALIZATION_ENABLE, DEFAULT_INITIALIZATION_MESSAGE_ENABLE, DEFAULT_LOG_FILE_FORMATS, DEFAULT_LOG_CONSOLE_COLORIZE, diff --git a/django_logging/constants/default_settings.py b/django_logging/constants/default_settings.py index 136935e..1fa8c51 100644 --- a/django_logging/constants/default_settings.py +++ b/django_logging/constants/default_settings.py @@ -15,7 +15,7 @@ # Default directory for logs DEFAULT_LOG_DIR: LOG_DIR_TYPE = os.path.join(os.getcwd(), "logs") -# Default log levels +# Default LogLevels in File Handlers DEFAULT_LOG_FILE_LEVELS: LOG_FILE_LEVELS_TYPE = [ "DEBUG", "INFO", @@ -28,8 +28,13 @@ # Default log date format DEFAULT_LOG_DATE_FORMAT: LOG_DATE_FORMAT_TYPE = "%Y-%m-%d %H:%M:%S" +# Default Auto initialization flag +DEFAULT_AUTO_INITIALIZATION_ENABLE: INITIALIZATION_MESSAGE_ENABLE_TYPE = True + +# Default initialization message flag DEFAULT_INITIALIZATION_MESSAGE_ENABLE: INITIALIZATION_MESSAGE_ENABLE_TYPE = True +# Default log formats in log files for each LogLevel DEFAULT_LOG_FILE_FORMATS: LogFileFormatsType = { "DEBUG": 1, "INFO": 1, @@ -38,12 +43,16 @@ "CRITICAL": 1, } +# Default LogLevel for console output DEFAULT_LOG_CONSOLE_LEVEL: LOG_CONSOLE_LEVEL_TYPE = "DEBUG" +# Default log format for console output DEFAULT_LOG_CONSOLE_FORMAT: LOG_CONSOLE_FORMAT_TYPE = 1 +# Default colorize logs flag for console output DEFAULT_LOG_CONSOLE_COLORIZE: LOG_CONSOLE_COLORIZE_TYPE = True +# Default Log Email Notifier Configs DEFAULT_LOG_EMAIL_NOTIFIER: LogEmailNotifierType = { "ENABLE": False, "NOTIFY_ERROR": False, diff --git a/django_logging/constants/settings_types.py b/django_logging/constants/settings_types.py index 8e668d7..a68a4ee 100644 --- a/django_logging/constants/settings_types.py +++ b/django_logging/constants/settings_types.py @@ -26,6 +26,7 @@ class LogFileFormatsType(TypedDict, total=False): LOG_DIR_TYPE = str LOG_FILE_LEVELS_TYPE = List[str] LOG_DATE_FORMAT_TYPE = str +AUTO_INITIALIZATION_ENABLE_TYPE = bool INITIALIZATION_MESSAGE_ENABLE_TYPE = bool LOG_CONSOLE_LEVEL_TYPE = LogLevel LOG_CONSOLE_FORMAT_TYPE = FormatOption diff --git a/django_logging/handlers/email_handler.py b/django_logging/handlers/email_handler.py index 3d4bfa7..9c5696d 100644 --- a/django_logging/handlers/email_handler.py +++ b/django_logging/handlers/email_handler.py @@ -3,7 +3,7 @@ from django.conf import settings from django.template import engines from django.utils.timezone import now -from django_logging.utils.email.notifier import send_email_async +from django_logging.utils.email_notifier import send_email_async from django_logging.utils.get_config import use_email_notifier_template from django_logging.middleware import RequestLogMiddleware diff --git a/django_logging/settings/checks.py b/django_logging/settings/checks.py index 597e256..81eaca5 100644 --- a/django_logging/settings/checks.py +++ b/django_logging/settings/checks.py @@ -11,6 +11,7 @@ DEFAULT_LOG_CONSOLE_FORMAT, DEFAULT_LOG_CONSOLE_COLORIZE, DEFAULT_LOG_FILE_FORMATS, + DEFAULT_AUTO_INITIALIZATION_ENABLE, DEFAULT_INITIALIZATION_MESSAGE_ENABLE, ) @@ -91,12 +92,24 @@ def check_logging_settings(app_configs: Dict[str, Any], **kwargs: Any) -> List[E log_date_format = log_settings.get("LOG_DATE_FORMAT", DEFAULT_LOG_DATE_FORMAT) errors.extend(validate_date_format(log_date_format, "LOG_DATE_FORMAT")) - # Validate INITIALIZATION_MESSAGE - initialization_message = log_settings.get( - "INITIALIZATION_MESSAGE_ENABLED", DEFAULT_INITIALIZATION_MESSAGE_ENABLE + # Validate AUTO_INITIALIZATION_ENABLE + auto_initialization_enable = log_settings.get( + "AUTO_INITIALIZATION_ENABLE", DEFAULT_AUTO_INITIALIZATION_ENABLE ) errors.extend( - validate_boolean_setting(initialization_message, "INITIALIZATION_MESSAGE") + validate_boolean_setting( + auto_initialization_enable, "AUTO_INITIALIZATION_ENABLE" + ) + ) + + # Validate INITIALIZATION_MESSAGE_ENABLE + initialization_message_enable = log_settings.get( + "INITIALIZATION_MESSAGE_ENABLE", DEFAULT_INITIALIZATION_MESSAGE_ENABLE + ) + errors.extend( + validate_boolean_setting( + initialization_message_enable, "INITIALIZATION_MESSAGE_ENABLE" + ) ) # Validate LOG_EMAIL_NOTIFIER diff --git a/django_logging/utils/context_manager.py b/django_logging/utils/context_manager.py index 960e53d..e993b89 100644 --- a/django_logging/utils/context_manager.py +++ b/django_logging/utils/context_manager.py @@ -1,29 +1,64 @@ from contextlib import contextmanager +from logging import getLogger, Logger +from typing import Dict +from django.conf import settings from django_logging.settings.conf import LogConfig, LogManager -from django_logging.utils.get_config import get_conf -import logging +from django_logging.utils.get_config import get_conf, is_auto_initialization_enabled @contextmanager -def config_context() -> None: +def config_context() -> LogManager: + """ + Context manager to temporarily apply a custom logging configuration. - # Store the current logging configuration to restore it later - original_logging_config = logging.getLogger().manager.loggerDict.copy() + Raises: + ValueError: If 'django_logging' is in INSTALLED_APPS. - conf = get_conf() - try: + Yields: + LogManager: The log manager instance with the custom configuration. + """ + if is_auto_initialization_enabled(): + raise ValueError( + "you most set 'AUTO_INITIALIZATION_ENABLE' to False in DJANGO_LOGGING in your settings" + ) + + logger = getLogger() + original_config = logger.manager.loggerDict.copy() + original_level = logger.level + original_handlers = logger.handlers.copy() - # Apply the new logging configuration + try: + conf = get_conf() log_config = LogConfig(*conf) log_manager = LogManager(log_config) - log_manager.create_log_files() log_manager.set_conf() yield log_manager - finally: - # Revert back to the original logging configuration - logging.getLogger().manager.loggerDict.clear() - logging.getLogger().manager.loggerDict.update(original_logging_config) + _restore_logging_config( + logger, original_config, original_level, original_handlers + ) + + +def _restore_logging_config( + logger: Logger, + original_config: Dict[str, Logger], + original_level: int, + original_handlers: list, +) -> None: + """ + Restore the original logging configuration. + + Args: + logger (Logger): The root logger instance. + original_config (Dict[str, Logger]): The original logger dictionary. + original_level (int): The original root logger level. + original_handlers (list): The original root logger handlers. + """ + logger.manager.loggerDict.clear() + logger.manager.loggerDict.update(original_config) + logger.level = original_level + logger.handlers.clear() + logger.handlers.extend(original_handlers) diff --git a/django_logging/utils/email/__init__.py b/django_logging/utils/email/__init__.py deleted file mode 100644 index 3e9b62e..0000000 --- a/django_logging/utils/email/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .notifier import send_email_async diff --git a/django_logging/utils/email/notifier.py b/django_logging/utils/email_notifier.py similarity index 100% rename from django_logging/utils/email/notifier.py rename to django_logging/utils/email_notifier.py diff --git a/django_logging/utils/get_config.py b/django_logging/utils/get_config.py index cfaf214..d55dd7e 100644 --- a/django_logging/utils/get_config.py +++ b/django_logging/utils/get_config.py @@ -12,17 +12,7 @@ DEFAULT_LOG_CONSOLE_COLORIZE, DEFAULT_LOG_FILE_FORMATS, DEFAULT_INITIALIZATION_MESSAGE_ENABLE, -) -from django_logging.constants.settings_types import ( - LogLevel, - LOG_DIR_TYPE, - LogFileFormatsType, - LOG_CONSOLE_FORMAT_TYPE, - LOG_CONSOLE_LEVEL_TYPE, - LOG_DATE_FORMAT_TYPE, - LOG_CONSOLE_COLORIZE_TYPE, - FormatOption, - LogEmailNotifierType, + DEFAULT_AUTO_INITIALIZATION_ENABLE, ) @@ -84,12 +74,26 @@ def use_email_notifier_template() -> bool: return log_email_notifier.get("USE_TEMPLATE", False) +def is_auto_initialization_enabled() -> bool: + """ + Check if the AUTO_INITIALIZATION_ENABLE for the logging system is set to True in Django settings. + + Returns: + bool: True if AUTO_INITIALIZATION_ENABLE, False otherwise. + Defaults to True if not specified. + """ + log_settings = getattr(settings, "DJANGO_LOGGING", {}) + return log_settings.get( + "AUTO_INITIALIZATION_ENABLE", DEFAULT_AUTO_INITIALIZATION_ENABLE + ) + + def is_initialization_message_enabled() -> bool: """ - Check if the initialization message for the logging system is enabled in Django settings. + Check if the INITIALIZATION_MESSAGE_ENABLE is set to True in Django settings. Returns: - bool: True if an initialization message is specified, False otherwise. + bool: True if INITIALIZATION_MESSAGE_ENABLE is True, False otherwise. Defaults to True if not specified. """ log_settings = getattr(settings, "DJANGO_LOGGING", {}) diff --git a/django_logging/utils/log_and_notify.py b/django_logging/utils/log_and_notify.py index f1732a7..7ef4011 100644 --- a/django_logging/utils/log_and_notify.py +++ b/django_logging/utils/log_and_notify.py @@ -5,7 +5,7 @@ from django.conf import settings from django_logging.constants.format_options import FORMAT_OPTIONS -from django_logging.utils.email import send_email_async +from django_logging.utils.email_notifier import send_email_async from django_logging.handlers import EmailHandler from django_logging.settings.conf import LogConfig diff --git a/django_logging/utils/setup_logging.py b/django_logging/utils/setup_logging.py index 7374df4..2b3d452 100644 --- a/django_logging/utils/setup_logging.py +++ b/django_logging/utils/setup_logging.py @@ -6,6 +6,7 @@ from typing import List, Optional, Union, Dict from django_logging.constants.ansi_colors import AnsiColors +from django_logging.utils.get_config import is_auto_initialization_enabled def set_logging( @@ -27,6 +28,9 @@ def set_logging( log_levels (List[str]): A list of log levels to configure. log_dir (str): The directory where log files will be stored. """ + if not is_auto_initialization_enabled(): + return + try: log_config = LogConfig( log_levels,