123 lines
3.1 KiB
Python
123 lines
3.1 KiB
Python
"""
|
|
Global logger for nano-vllm with colored output.
|
|
|
|
Usage:
|
|
from nanovllm.utils.logger import logger
|
|
|
|
logger.debug("Debug message") # Gray
|
|
logger.info("Info message") # Blue
|
|
logger.warning("Warning message") # Yellow
|
|
logger.error("Error message") # Red
|
|
|
|
Control log level via environment variable:
|
|
NANOVLLM_LOG_LEVEL=DEBUG python your_script.py
|
|
NANOVLLM_LOG_LEVEL=INFO python your_script.py (default)
|
|
NANOVLLM_LOG_LEVEL=WARNING python your_script.py
|
|
"""
|
|
import os
|
|
import sys
|
|
import logging
|
|
from typing import Optional
|
|
|
|
|
|
# ANSI color codes
|
|
class Colors:
|
|
RESET = "\033[0m"
|
|
GRAY = "\033[90m"
|
|
BLUE = "\033[94m"
|
|
YELLOW = "\033[93m"
|
|
RED = "\033[91m"
|
|
BOLD = "\033[1m"
|
|
|
|
|
|
# Level -> Color mapping
|
|
LEVEL_COLORS = {
|
|
logging.DEBUG: Colors.GRAY,
|
|
logging.INFO: Colors.BLUE,
|
|
logging.WARNING: Colors.YELLOW,
|
|
logging.ERROR: Colors.RED,
|
|
logging.CRITICAL: Colors.RED + Colors.BOLD,
|
|
}
|
|
|
|
|
|
class ColoredFormatter(logging.Formatter):
|
|
"""Formatter that adds colors to log levels."""
|
|
|
|
def __init__(self, fmt: str, datefmt: str = None, use_colors: bool = True):
|
|
super().__init__(fmt, datefmt)
|
|
self.use_colors = use_colors
|
|
|
|
def format(self, record: logging.LogRecord) -> str:
|
|
if self.use_colors:
|
|
color = LEVEL_COLORS.get(record.levelno, Colors.RESET)
|
|
# Color the level name
|
|
record.levelname = f"{color}{record.levelname}{Colors.RESET}"
|
|
# Color the message
|
|
record.msg = f"{color}{record.msg}{Colors.RESET}"
|
|
return super().format(record)
|
|
|
|
|
|
# Log level from environment variable
|
|
_LOG_LEVEL = os.environ.get("NANOVLLM_LOG_LEVEL", "INFO").upper()
|
|
|
|
# Global logger instance
|
|
_logger: Optional[logging.Logger] = None
|
|
|
|
|
|
def _setup_logger() -> logging.Logger:
|
|
"""Setup and return the global logger."""
|
|
log = logging.getLogger("nanovllm")
|
|
|
|
# Avoid duplicate handlers if called multiple times
|
|
if log.handlers:
|
|
return log
|
|
|
|
# Set level from environment
|
|
level = getattr(logging, _LOG_LEVEL, logging.INFO)
|
|
log.setLevel(level)
|
|
|
|
# Create handler (stderr)
|
|
handler = logging.StreamHandler(sys.stderr)
|
|
handler.setLevel(level)
|
|
|
|
# Check if terminal supports colors
|
|
use_colors = hasattr(sys.stderr, "isatty") and sys.stderr.isatty()
|
|
|
|
# Format: [TIME] [LEVEL] [MODULE] message
|
|
formatter = ColoredFormatter(
|
|
fmt="[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s",
|
|
datefmt="%H:%M:%S",
|
|
use_colors=use_colors,
|
|
)
|
|
handler.setFormatter(formatter)
|
|
|
|
log.addHandler(handler)
|
|
|
|
# Don't propagate to root logger
|
|
log.propagate = False
|
|
|
|
return log
|
|
|
|
|
|
def get_logger(name: Optional[str] = None) -> logging.Logger:
|
|
"""
|
|
Get a logger instance.
|
|
|
|
Args:
|
|
name: Optional sub-logger name. If provided, creates a child logger
|
|
like 'nanovllm.attention'. If None, returns the root nanovllm logger.
|
|
|
|
Returns:
|
|
Logger instance
|
|
"""
|
|
global _logger
|
|
if _logger is None:
|
|
_logger = _setup_logger()
|
|
|
|
if name:
|
|
return _logger.getChild(name)
|
|
return _logger
|
|
|
|
|
|
# Convenience: direct access to the root logger
|
|
logger = get_logger() |