Spaces:
Running
Running
File size: 4,423 Bytes
2e99c77 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
import logging
import sys
from pathlib import Path
from datetime import datetime
import colorama
from colorama import Fore, Back, Style
from typing import Optional, Union
import re
import traceback
import copy
import os
# Initialize colorama
colorama.init()
class ColoredFormatter(logging.Formatter):
"""Colored formatter for structured log output.
This formatter adds color-coding, icons, timestamps, and file location
information to log messages. It supports different color schemes for
different log levels and includes special formatting for exceptions.
Attributes:
COLORS (dict): Color schemes for different log levels, including:
- color: Foreground color
- style: Text style (dim, normal, bright)
- icon: Emoji icon for the log level
- bg: Background color (for critical logs)
"""
COLORS = {
'DEBUG': {
'color': Fore.CYAN,
'style': Style.DIM,
'icon': '🔍'
},
'INFO': {
'color': Fore.GREEN,
'style': Style.NORMAL,
'icon': 'ℹ️'
},
'WARNING': {
'color': Fore.YELLOW,
'style': Style.BRIGHT,
'icon': '⚠️'
},
'ERROR': {
'color': Fore.RED,
'style': Style.BRIGHT,
'icon': '❌'
},
'CRITICAL': {
'color': Fore.WHITE,
'style': Style.BRIGHT,
'bg': Back.RED,
'icon': '💀'
}
}
def format(self, record: logging.LogRecord) -> str:
"""Format a log record with color and structure.
This method formats log records with:
- Timestamp in HH:MM:SS.mmm format
- File location (filename:line)
- Color-coded level name with icon
- Color-coded message
- Formatted exception traceback if present
Args:
record (logging.LogRecord): Log record to format.
Returns:
str: Formatted log message with color and structure.
"""
colored_record = copy.copy(record)
# Get color scheme
scheme = self.COLORS.get(record.levelname, {
'color': Fore.WHITE,
'style': Style.NORMAL,
'icon': '•'
})
# Format timestamp
timestamp = datetime.fromtimestamp(record.created).strftime('%H:%M:%S.%f')[:-3]
# Get file location
file_location = f"{os.path.basename(record.pathname)}:{record.lineno}"
# Build components
components = []
# log formatting
components.extend([
f"{Fore.BLUE}{timestamp}{Style.RESET_ALL}",
f"{Fore.WHITE}{Style.DIM}{file_location}{Style.RESET_ALL}",
f"{scheme['color']}{scheme['style']}{scheme['icon']} {record.levelname:8}{Style.RESET_ALL}",
f"{scheme['color']}{record.msg}{Style.RESET_ALL}"
])
# Add exception info
if record.exc_info:
components.append(
f"\n{Fore.RED}{Style.BRIGHT}"
f"{''.join(traceback.format_exception(*record.exc_info))}"
f"{Style.RESET_ALL}"
)
return " | ".join(components)
def setup_logger(
name: Optional[Union[str, Path]] = None,
level: int = logging.INFO
) -> logging.Logger:
"""Set up a colored logger
This function creates or retrieves a logger with colored output and
automatic log interception. If a file path is provided as the name,
it will use the filename (without extension) as the logger name.
Args:
name (Optional[Union[str, Path]], optional): Logger name or __file__ for
module name. Defaults to None.
level (int, optional): Logging level. Defaults to logging.INFO.
Returns:
logging.Logger: Configured logger instance.
"""
# Get logger name from file path
if isinstance(name, (str, Path)) and Path(name).suffix == '.py':
name = Path(name).stem
# Get or create logger
logger = logging.getLogger(name)
logger.setLevel(level)
# Only add handler if none exists
if not logger.handlers:
# Create console handler
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(ColoredFormatter())
logger.addHandler(console_handler)
return logger
|