File size: 3,993 Bytes
26b9faa
 
 
 
79df050
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26b9faa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79df050
26b9faa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79df050
 
 
 
 
 
 
 
 
 
 
26b9faa
 
 
 
79df050
 
 
 
 
 
 
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
import os
import logging
from typing import Optional

# ANSI 轉義序列
class LogColor:
    DEBUG = "\x1b[38;20m"    # 灰色
    INFO = "\x1b[32;20m"     # 綠色
    WARNING = "\x1b[33;20m"  # 黃色
    ERROR = "\x1b[31;20m"    # 紅色
    CRITICAL = "\x1b[31;1m"   # 粗體紅
    RESET = "\x1b[0m"
    GRAY = "\x1b[90m"        # 淺灰色
    CYAN = "\x1b[36;20m"     # 青色
    BLUE = "\x1b[34;20m"     # 藍色
    MAGENTA = "\x1b[35;20m"  # 品紅

class ColoredFormatter(logging.Formatter):
    """自定義彩色日誌格式化器"""
    
    LEVEL_COLORS = {
        logging.DEBUG: LogColor.GRAY,
        logging.INFO: LogColor.INFO,
        logging.WARNING: LogColor.WARNING,
        logging.ERROR: LogColor.ERROR,
        logging.CRITICAL: LogColor.CRITICAL
    }

    def format(self, record):
        level_color = self.LEVEL_COLORS.get(record.levelno, LogColor.RESET)
        
        # 格式化時間(淡灰色)
        asctime = self.formatTime(record, self.datefmt)
        asctime_colored = f"{LogColor.GRAY}{asctime}{LogColor.RESET}"
        
        # 格式化名稱(青色)
        name_colored = f"{LogColor.CYAN}{record.name}{LogColor.RESET}"
        
        # 格式化等級(根據等級變色)
        levelname_colored = f"{level_color}{record.levelname:8}{LogColor.RESET}"
        
        # 格式化訊息
        message = record.getMessage()
        
        # 自動截斷過長的訊息(如工具調用的完整原始數據)
        if len(message) > 500:
            message = message[:500] + f"{LogColor.GRAY}... [已截斷,共 {len(message)} 字元]{LogColor.RESET}"

        if "✅" in message:
            message = f"{LogColor.INFO}{message}{LogColor.RESET}"
        elif "❌" in message or "⚠️" in message:
            message = f"{LogColor.ERROR}{message}{LogColor.RESET}"
        elif "🎙️" in message or "🔊" in message:
            message = f"{LogColor.BLUE}{message}{LogColor.RESET}"
        elif "🌐" in message or "MCP" in message:
            message = f"{LogColor.MAGENTA}{message}{LogColor.RESET}"
        else:
            message = f"{level_color}{message}{LogColor.RESET}"
            
        return f"{asctime_colored} | {name_colored} | {levelname_colored} | {message}"

# 全域日誌等級
_LOG_LEVEL_NAME = os.getenv("BLOOMWARE_LOG_LEVEL", "INFO").upper()
_LOG_LEVEL = getattr(logging, _LOG_LEVEL_NAME, logging.INFO)

def get_log_level() -> int:
    return _LOG_LEVEL

def setup_logging(
    name: Optional[str] = None,
    level: Optional[int] = None,
) -> logging.Logger:
    if level is None:
        level = _LOG_LEVEL

    logger = logging.getLogger(name)
    logger.setLevel(level)

    if not logger.handlers:
        console_handler = logging.StreamHandler()
        console_handler.setLevel(level)
        console_handler.setFormatter(ColoredFormatter())
        logger.addHandler(console_handler)

    logger.propagate = False
    return logger

def get_logger(name: str) -> logging.Logger:
    return setup_logging(name)

def get_level_name() -> str:
    return _LOG_LEVEL_NAME

# 預設配置 root logger
_root_configured = False

def configure_root_logger():
    global _root_configured
    if not _root_configured:
        root = logging.getLogger()
        root.setLevel(get_log_level())
        
        # 清除現有的 handlers
        for handler in root.handlers[:]:
            root.removeHandler(handler)
            
        console_handler = logging.StreamHandler()
        console_handler.setFormatter(ColoredFormatter())
        root.addHandler(console_handler)
        
        _root_configured = True

# 自動配置
configure_root_logger()

# 關閉 Speechbrain 等吵雜的日誌
logging.getLogger("speechbrain").setLevel(logging.WARNING)
logging.getLogger("werkzeug").setLevel(logging.WARNING)
logging.getLogger("urllib3").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING)
logging.getLogger("httpx").setLevel(logging.WARNING)