From 7418af18b1d03faaef96062f33beb82e68dc7065 Mon Sep 17 00:00:00 2001 From: kylerohn-msft Date: Wed, 1 Jul 2026 13:42:36 -0700 Subject: [PATCH 1/3] create colorful logging --- .../activity/config/_configure_logging.py | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py b/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py index eb76594ea..a51b40ffa 100644 --- a/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py +++ b/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py @@ -20,6 +20,36 @@ } +class ColorFormatter(logging.Formatter): + """Custom logging formatter that adds color to log messages based on their severity level.""" + + BRIGHT_RED = "\033[1;31m" + RED = "\033[31m" + YELLOW = "\033[33m" + GREEN = "\033[32m" + BLUE = "\033[34m" + RESET = "\033[0m" + + log_format = ( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" + ) + + FORMATS = { + logging.CRITICAL: f"{BRIGHT_RED}{log_format}{RESET}", + logging.ERROR: f"{RED}{log_format}{RESET}", + logging.WARNING: f"{YELLOW}{log_format}{RESET}", + logging.INFO: f"{GREEN}{log_format}{RESET}", + logging.DEBUG: f"{BLUE}{log_format}{RESET}", + logging.NOTSET: f"{RESET}{log_format}{RESET}", + } + + def format(self, record): + """Formats the log record with color based on its severity level.""" + log_fmt = self.FORMATS.get(record.levelno, self.FORMATS[logging.NOTSET]) + formatter = logging.Formatter(log_fmt) + return formatter.format(record) + + def _configure_logging(logging_config: dict): """Configures logging based on the provided logging configuration dictionary. @@ -30,11 +60,7 @@ def _configure_logging(logging_config: dict): log_levels = logging_config.get("LOGLEVEL", {}) console_handler = logging.StreamHandler() - console_handler.setFormatter( - logging.Formatter( - "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" - ) - ) + console_handler.setFormatter(ColorFormatter()) for key in log_levels: level_name = log_levels[key].upper() @@ -50,6 +76,7 @@ def _configure_logging(logging_config: dict): else: logger = logging.getLogger(namespace) + logger.propagate = False # Prevent log messages from being propagated logger.handlers.clear() # Remove existing handlers to prevent duplicates logger.addHandler(console_handler) logger.setLevel(level) From c480022a7e8e0c208618f738d4375a31f7793d73 Mon Sep 17 00:00:00 2001 From: kylerohn-msft Date: Thu, 2 Jul 2026 11:30:40 -0700 Subject: [PATCH 2/3] critical logs red->purple --- .../activity/config/_configure_logging.py | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py b/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py index a51b40ffa..e5b73d598 100644 --- a/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py +++ b/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py @@ -23,24 +23,22 @@ class ColorFormatter(logging.Formatter): """Custom logging formatter that adds color to log messages based on their severity level.""" - BRIGHT_RED = "\033[1;31m" - RED = "\033[31m" - YELLOW = "\033[33m" - GREEN = "\033[32m" - BLUE = "\033[34m" + MAGENTA = "\033[1;35m" + RED = "\033[1;31m" + YELLOW = "\033[1;33m" + GREEN = "\033[1;32m" + BLUE = "\033[1;34m" RESET = "\033[0m" - log_format = ( - "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" - ) + log_format = "{levelcolor}%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d){reset}" FORMATS = { - logging.CRITICAL: f"{BRIGHT_RED}{log_format}{RESET}", - logging.ERROR: f"{RED}{log_format}{RESET}", - logging.WARNING: f"{YELLOW}{log_format}{RESET}", - logging.INFO: f"{GREEN}{log_format}{RESET}", - logging.DEBUG: f"{BLUE}{log_format}{RESET}", - logging.NOTSET: f"{RESET}{log_format}{RESET}", + logging.CRITICAL: log_format.format(levelcolor=MAGENTA, reset=RESET), + logging.ERROR: log_format.format(levelcolor=RED, reset=RESET), + logging.WARNING: log_format.format(levelcolor=YELLOW, reset=RESET), + logging.INFO: log_format.format(levelcolor=GREEN, reset=RESET), + logging.DEBUG: log_format.format(levelcolor=BLUE, reset=RESET), + logging.NOTSET: log_format.format(levelcolor=RESET, reset=RESET), } def format(self, record): From 65d9bfa10229e9a9a228e78387001431743a7fac Mon Sep 17 00:00:00 2001 From: kylerohn-msft Date: Thu, 2 Jul 2026 12:17:24 -0700 Subject: [PATCH 3/3] avoid making new logger every time format() is called --- .../activity/config/_configure_logging.py | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py b/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py index e5b73d598..37c64527a 100644 --- a/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py +++ b/libraries/microsoft-agents-activity/microsoft_agents/activity/config/_configure_logging.py @@ -21,7 +21,7 @@ class ColorFormatter(logging.Formatter): - """Custom logging formatter that adds color to log messages based on their severity level.""" + """Logging formatter that can add ANSI color based on severity.""" MAGENTA = "\033[1;35m" RED = "\033[1;31m" @@ -30,22 +30,32 @@ class ColorFormatter(logging.Formatter): BLUE = "\033[1;34m" RESET = "\033[0m" - log_format = "{levelcolor}%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d){reset}" - - FORMATS = { - logging.CRITICAL: log_format.format(levelcolor=MAGENTA, reset=RESET), - logging.ERROR: log_format.format(levelcolor=RED, reset=RESET), - logging.WARNING: log_format.format(levelcolor=YELLOW, reset=RESET), - logging.INFO: log_format.format(levelcolor=GREEN, reset=RESET), - logging.DEBUG: log_format.format(levelcolor=BLUE, reset=RESET), - logging.NOTSET: log_format.format(levelcolor=RESET, reset=RESET), - } - - def format(self, record): - """Formats the log record with color based on its severity level.""" - log_fmt = self.FORMATS.get(record.levelno, self.FORMATS[logging.NOTSET]) - formatter = logging.Formatter(log_fmt) - return formatter.format(record) + FMT = ( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" + ) + + def __init__( + self, + use_colors: bool = True, + ) -> None: + super().__init__(fmt=self.FMT) + self._plain_formatter = logging.Formatter(fmt=self.FMT) + if not use_colors: + self._formatters: dict[int, logging.Formatter] = {} + return + self._formatters = { + logging.CRITICAL: logging.Formatter( + f"{self.MAGENTA}{self.FMT}{self.RESET}" + ), + logging.ERROR: logging.Formatter(f"{self.RED}{self.FMT}{self.RESET}"), + logging.WARNING: logging.Formatter(f"{self.YELLOW}{self.FMT}{self.RESET}"), + logging.INFO: logging.Formatter(f"{self.GREEN}{self.FMT}{self.RESET}"), + logging.DEBUG: logging.Formatter(f"{self.BLUE}{self.FMT}{self.RESET}"), + } + + def format(self, record: logging.LogRecord) -> str: + formatter = self._formatters.get(record.levelno) + return (formatter or self._plain_formatter).format(record) def _configure_logging(logging_config: dict): @@ -58,7 +68,9 @@ def _configure_logging(logging_config: dict): log_levels = logging_config.get("LOGLEVEL", {}) console_handler = logging.StreamHandler() - console_handler.setFormatter(ColorFormatter()) + console_handler.setFormatter( + ColorFormatter(use_colors=console_handler.stream.isatty()) + ) for key in log_levels: level_name = log_levels[key].upper()