Skip to content

Commit

Permalink
Merge pull request #15 from MEHRSHAD-MIRSHEKARY/feature/colorized-con…
Browse files Browse the repository at this point in the history
…sole-logs

Feature/colorized console logs
  • Loading branch information
ARYAN-NIKNEZHAD authored Aug 18, 2024
2 parents 4a42240 + a48af82 commit 550e0c8
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 2 deletions.
2 changes: 2 additions & 0 deletions django_logging/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def ready(self):
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")
colorize_console = log_settings.get("LOG_CONSOLE_COLORIZE", True)
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)
Expand All @@ -37,6 +38,7 @@ def ready(self):
log_file_formats,
console_level,
console_format,
colorize_console,
log_date_format,
log_email_notifier_enable,
log_email_notifier_log_levels,
Expand Down
38 changes: 38 additions & 0 deletions django_logging/constants/ansi_colors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
class AnsiColors:
BLACK = "\033[0;30m"
RED = "\033[0;31m"
RED_BACKGROUND = "\033[1;41m"
GREEN = "\033[0;32m"
YELLOW = "\033[0;33m"
BLUE = "\033[0;34m"
MAGENTA = "\033[0;35m"
CYAN = "\033[0;36m"
GRAY = "\033[0;37m"
WHITE = "\033[0;38m"
RESET = "\033[0m"
BRIGHT_BLACK = "\033[0;90m"
BRIGHT_RED = "\033[0;91m"
BRIGHT_GREEN = "\033[0;92m"
BRIGHT_YELLOW = "\033[0;93m"
BRIGHT_BLUE = "\033[0;94m"
BRIGHT_MAGENTA = "\033[0;95m"
BRIGHT_CYAN = "\033[0;96m"
BRIGHT_WHITE = "\033[0;97m"
BLACK_BACKGROUND = "\033[40m"
RED_BACKGROUND = "\033[41m"
GREEN_BACKGROUND = "\033[42m"
YELLOW_BACKGROUND = "\033[43m"
BLUE_BACKGROUND = "\033[44m"
MAGENTA_BACKGROUND = "\033[45m"
CYAN_BACKGROUND = "\033[46m"
WHITE_BACKGROUND = "\033[47m"


# Mapping log levels to ANSI colors
LOG_LEVEL_COLORS = {
"DEBUG": AnsiColors.BLUE,
"INFO": AnsiColors.GREEN,
"WARNING": AnsiColors.YELLOW,
"ERROR": AnsiColors.RED,
"CRITICAL": AnsiColors.RED_BACKGROUND,
}
1 change: 1 addition & 0 deletions django_logging/formatters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .colorized_formatter import ColorizedFormatter
20 changes: 20 additions & 0 deletions django_logging/formatters/colorized_formatter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import logging
from django_logging.settings.conf import LogConfig
from django_logging.utils.colorizer import colorize_log_format


class ColorizedFormatter(logging.Formatter):
def format(self, record):
original_format = self._style._fmt

# checks that the format does not have any color it's self
if LogConfig.remove_ansi_escape_sequences(original_format) == original_format:
colorized_format = colorize_log_format(original_format, record.levelname)
self._style._fmt = colorized_format

formatted_output = super().format(record)

# Reset to the original format string
self._style._fmt = original_format

return formatted_output
29 changes: 27 additions & 2 deletions django_logging/settings/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def __init__(
log_file_formats: Dict[str, Union[int, str]],
console_level: str,
console_format: Optional[Union[int, str]],
colorize_console: bool,
log_date_format: str,
log_email_notifier_enable: bool,
log_email_notifier_log_levels: List[str],
Expand All @@ -34,7 +35,10 @@ def __init__(
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.colorize_console = colorize_console
self.console_format = self.resolve_format(
console_format, use_colors=self.colorize_console
)
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(
Expand All @@ -55,10 +59,23 @@ def _resolve_file_formats(self, log_file_formats: Dict[str, Union[int, str]]) ->
else:
resolved_formats[level] = FORMAT_OPTIONS[1]

colored_format = resolved_formats[level]
resolved_formats[level] = self.remove_ansi_escape_sequences(colored_format)

return resolved_formats

@staticmethod
def resolve_format(_format: Union[int, str]) -> str:
def remove_ansi_escape_sequences(log_message: str) -> str:
"""
Remove ANSI escape sequences from log messages.
"""
import re

ansi_escape = re.compile(r"(?:\x1B[@-_][0-?]*[ -/]*[@-~])")
return ansi_escape.sub("", log_message)

@staticmethod
def resolve_format(_format: Union[int, str], use_colors: bool = False) -> str:
if _format:
if isinstance(_format, int):
resolved_format = FORMAT_OPTIONS.get(_format, FORMAT_OPTIONS[1])
Expand All @@ -67,6 +84,10 @@ def resolve_format(_format: Union[int, str]) -> str:
else:
resolved_format = FORMAT_OPTIONS[1]

# If colors are not enabled, strip out color codes, if provided in formats
if not use_colors:
resolved_format = LogConfig.remove_ansi_escape_sequences(resolved_format)

return resolved_format


Expand Down Expand Up @@ -156,6 +177,10 @@ def set_conf(self) -> None:
"format": self.log_config.console_format,
"datefmt": self.log_config.log_date_format,
}
if self.log_config.colorize_console:
formatters["console"].update(
{"()": "django_logging.formatters.ColorizedFormatter"}
)

formatters["email"] = {
"format": self.log_config.email_notifier_log_format,
Expand Down
27 changes: 27 additions & 0 deletions django_logging/utils/colorizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from django_logging.constants.ansi_colors import LOG_LEVEL_COLORS, AnsiColors


def colorize_log_format(log_format, levelname):
color_mapping = {
"%(asctime)s": f"{AnsiColors.CYAN}%(asctime)s{AnsiColors.RESET}",
"%(created)f": f"{AnsiColors.BRIGHT_BLUE}%(created)f{AnsiColors.RESET}",
"%(relativeCreated)d": f"{AnsiColors.MAGENTA}%(relativeCreated)d{AnsiColors.RESET}",
"%(msecs)d": f"{AnsiColors.YELLOW}%(msecs)d{AnsiColors.RESET}",
"%(levelname)s": f"{LOG_LEVEL_COLORS.get(levelname, '')}%(levelname)s{AnsiColors.RESET}",
"%(levelno)d": f"{AnsiColors.RED}%(levelno)d{AnsiColors.RESET}",
"%(name)s": f"{AnsiColors.BRIGHT_MAGENTA}%(name)s{AnsiColors.RESET}",
"%(module)s": f"{AnsiColors.BRIGHT_GREEN}%(module)s{AnsiColors.RESET}",
"%(filename)s": f"{AnsiColors.YELLOW}%(filename)s{AnsiColors.RESET}",
"%(pathname)s": f"{AnsiColors.CYAN}%(pathname)s{AnsiColors.RESET}",
"%(lineno)d": f"{AnsiColors.RED}%(lineno)d{AnsiColors.RESET}",
"%(funcName)s": f"{AnsiColors.BRIGHT_BLUE}%(funcName)s{AnsiColors.RESET}",
"%(process)d": f"{AnsiColors.MAGENTA}%(process)d{AnsiColors.RESET}",
"%(thread)d": f"{AnsiColors.CYAN}%(thread)d{AnsiColors.RESET}",
"%(threadName)s": f"{AnsiColors.BRIGHT_MAGENTA}%(threadName)s{AnsiColors.RESET}",
"%(message)s": f"{AnsiColors.GRAY}%(message)s{AnsiColors.RESET}",
}

for placeholder, colorized in color_mapping.items():
log_format = log_format.replace(placeholder, colorized)

return log_format
2 changes: 2 additions & 0 deletions django_logging/utils/setup_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def set_logging(
log_file_formats: Dict[str, Union[int, str]],
console_level: str,
console_format: Optional[Union[int, str]],
colorize_console: bool,
log_date_format: str,
log_email_notifier_enable: bool,
log_email_notifier_log_levels: List[str],
Expand All @@ -27,6 +28,7 @@ def set_logging(
log_file_formats,
console_level,
console_format,
colorize_console,
log_date_format,
log_email_notifier_enable,
log_email_notifier_log_levels,
Expand Down

0 comments on commit 550e0c8

Please sign in to comment.