import logging from pathlib import Path from typing import Any import colorlog from graphql import GraphQLError graphql_logger = logging.getLogger("graphql") graphql_logger.setLevel(logging.WARNING) ariadne_logger = logging.getLogger("ariadne") ariadne_logger.setLevel(logging.WARNING) _lib_path = Path(__file__).parents[1] _leng_path = len(_lib_path.as_posix()) def filter(record: logging.LogRecord) -> bool: # Define `package` attribute with the relative path. record.package = record.pathname[_leng_path + 1 :].replace(".py", "") record.emoji = ( "πŸ”" if record.levelno == logging.DEBUG else "β„ΉοΈŽ" if record.levelno == logging.INFO else "🚧" if record.levelno == logging.WARNING else "❌" if record.levelno == logging.ERROR else "🧨" if record.levelno == logging.CRITICAL else "" ) # ПодавляСм Π»ΠΎΠ³ΠΈ ошибок Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΈ GraphQL трСйсбСки if record.levelno >= logging.ERROR and record.getMessage(): message = record.getMessage() # ПодавляСм ошибки Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ if any( phrase in message for phrase in [ "ВрСбуСтся авторизация", "AuthorizationError", "GraphQL request:", "Traceback (most recent call last):", "graphql.error.graphql_error.GraphQLError: ВрСбуСтся авторизация", ] ): return False # НС Π»ΠΎΠ³ΠΈΡ€ΡƒΠ΅ΠΌ ошибки Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΈ ΠΈΡ… трСйсбСки # ПодавляСм ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡΡŽΡ‰ΠΈΠ΅ΡΡ Ariadne Π»ΠΎΠ³ΠΈ if record.name in ["ariadne", "graphql"] and record.levelno == logging.ERROR: message = record.getMessage() if "ВрСбуСтся авторизация" in message: return False return True # Define the color scheme color_scheme = { "DEBUG": "light_black", "INFO": "green", "WARNING": "yellow", "ERROR": "red", "CRITICAL": "red,bg_white", } # Define secondary log colors secondary_colors = { "log_name": {"DEBUG": "blue"}, "asctime": {"DEBUG": "cyan"}, "process": {"DEBUG": "purple"}, "module": {"DEBUG": "light_black,bg_blue"}, "funcName": {"DEBUG": "light_white,bg_blue"}, # Add this line } # Define the log format string fmt_string = "%(emoji)s%(log_color)s%(package)s.%(funcName)s%(reset)s %(white)s%(message)s" # Define formatting configuration fmt_config = { "log_colors": color_scheme, "secondary_log_colors": secondary_colors, "style": "%", "reset": True, } class MultilineColoredFormatter(colorlog.ColoredFormatter): def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) self.log_colors = kwargs.pop("log_colors", {}) self.secondary_log_colors = kwargs.pop("secondary_log_colors", {}) def format(self, record: logging.LogRecord) -> str: # Add default emoji if not present if not hasattr(record, "emoji"): record.emoji = "πŸ“" # Add default package if not present if not hasattr(record, "package"): record.package = getattr(record, "name", "unknown") # Format the first line normally formatted_first_line = super().format(record) # Check if the message has multiple lines lines = formatted_first_line.split("\n") if len(lines) > 1: # For multiple lines, only apply colors to the first line # Keep subsequent lines without color formatting formatted_lines = [formatted_first_line] formatted_lines.extend(lines[1:]) return "\n".join(formatted_lines) return super().format(record) # Create a MultilineColoredFormatter object for colorized logging formatter = MultilineColoredFormatter(fmt_string, **fmt_config) # Create a stream handler for logging output stream = logging.StreamHandler() stream.setFormatter(formatter) def get_colorful_logger(name: str = "main") -> logging.Logger: # Create and configure the logger logger = logging.getLogger(name) logger.setLevel(logging.DEBUG) logger.addHandler(stream) logger.addFilter(filter) return logger # Set up the root logger with the same formatting root_logger = logging.getLogger() root_logger.setLevel(logging.DEBUG) root_logger.addHandler(stream) root_logger.addFilter(filter) ignore_logs = ["_trace", "httpx", "_client", "atrace", "aiohttp", "_client", "ariadne", "graphql"] for lgr in ignore_logs: loggr = logging.getLogger(lgr) loggr.setLevel(logging.CRITICAL) # ПодавляСм всС ΠΊΡ€ΠΎΠΌΠ΅ критичСских ошибок # Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ подавляСм Π»ΠΎΠ³ΠΈ GraphQL ΠΈ Ariadne для ошибок Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ graphql_logger = logging.getLogger("graphql") graphql_logger.setLevel(logging.CRITICAL) # ПодавляСм ERROR ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ для Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ ariadne_logger = logging.getLogger("ariadne") ariadne_logger.setLevel(logging.CRITICAL) # ПодавляСм ERROR ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ для Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ # Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ для Ariadne class AriadneAuthFilter(logging.Filter): def filter(self, record: logging.LogRecord) -> bool: message = record.getMessage() # ΠŸΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ Π±Π»ΠΎΠΊΠΈΡ€ΡƒΠ΅ΠΌ Π»ΠΎΠ³ΠΈ связанныС с Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠ΅ΠΉ Π² Ariadne return not any( phrase in message for phrase in ["ВрСбуСтся авторизация", "AuthorizationError", "GraphQL request:", "decorated_function"] ) # ΠŸΡ€ΠΈΠΌΠ΅Π½ΡΠ΅ΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ ΠΊ Ariadne ΠΈ GraphQL Π»ΠΎΠ³Π³Π΅Ρ€Π°ΠΌ ariadne_logger.addFilter(AriadneAuthFilter()) graphql_logger.addFilter(AriadneAuthFilter()) def custom_error_formatter(error: GraphQLError, debug: bool = False) -> dict[Any, Any]: """ ΠšΠ°ΡΡ‚ΠΎΠΌΠ½Ρ‹ΠΉ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Ρ‚Π΅Ρ€ ошибок для подавлСния трСйсбСков Ρƒ ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΡ‹Ρ… ошибок Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ. πŸ” Π›ΠΎΠ³ΠΈΡ€ΡƒΠ΅Ρ‚ AuthorizationError ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Π΅ события, Π½Π΅ ΠΊΠ°ΠΊ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ """ # ΠŸΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅ΠΌ Π² ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π½ΠΈΠΌ formatted_error: dict[str, Any] = { "message": error.message, "locations": getattr(error.formatted, "locations", []), "path": getattr(error.formatted, "path", []), "extensions": getattr(error.formatted, "extensions", {}), } # Для ошибок Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ Π½Π΅ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ трСйсбСк ΠΈ НЕ Π»ΠΎΠ³ΠΈΡ€ΡƒΠ΅ΠΌ Π²ΠΎΠΎΠ±Ρ‰Π΅ # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ ΠΏΠΎ ΠΈΠΌΠ΅Π½ΠΈ класса для избСТания цикличСских ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΎΠ² if ( error.original_error and hasattr(error.original_error, "__class__") and error.original_error.__class__.__name__ == "AuthorizationError" ): # Π£Π±ΠΈΡ€Π°Π΅ΠΌ extensions.exception Ссли Π΅ΡΡ‚ΡŒ if "extensions" in formatted_error and "exception" in formatted_error["extensions"]: del formatted_error["extensions"]["exception"] # НЕ Π»ΠΎΠ³ΠΈΡ€ΡƒΠ΅ΠΌ ошибки Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ - ΠΎΠ½ΠΈ ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΡ‹ ΠΈ Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½Ρ‹ # Для ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Ρ… ошибок ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ стандартноС Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ elif debug and error.original_error: root_logger.error(f"GraphQL error: {error.message}", exc_info=error.original_error) else: root_logger.warning(f"GraphQL error: {error.message}") return formatted_error