209 lines
6.9 KiB
Python
209 lines
6.9 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
"""Logging configuration for vLLM-Ascend.
|
|
|
|
Provides two logging mechanisms:
|
|
1. Console: A dedicated handler on the vllm_ascend logger with
|
|
[vllm-ascend] [module] prefix. No modification to vLLM's global
|
|
logging state — safe for upstream tests and multiprocessing.
|
|
2. File: A rotating file handler on both vllm and vllm_ascend loggers,
|
|
capturing all logs with Ascend formatting.
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
import sys
|
|
from datetime import datetime
|
|
|
|
from vllm import envs
|
|
from vllm.logging_utils import ColoredFormatter, NewLineFormatter
|
|
|
|
_FORMAT = "%(levelname)s %(asctime)s [%(fileinfo)s:%(lineno)d] %(message)s"
|
|
_DATE_FORMAT = "%m-%d %H:%M:%S"
|
|
|
|
_LOG_DIR = os.path.join(os.path.expanduser("~"), "ascend", "log", "vllm_ascend")
|
|
_LOG_MAX_BYTES = 20 * 1024 * 1024
|
|
|
|
|
|
def _use_color() -> bool:
|
|
"""Determine if colored output should be used."""
|
|
if envs.NO_COLOR or envs.VLLM_LOGGING_COLOR == "0":
|
|
return False
|
|
if envs.VLLM_LOGGING_COLOR == "1":
|
|
return True
|
|
if envs.VLLM_LOGGING_STREAM == "ext://sys.stdout":
|
|
return hasattr(sys.stdout, "isatty") and sys.stdout.isatty()
|
|
elif envs.VLLM_LOGGING_STREAM == "ext://sys.stderr":
|
|
return hasattr(sys.stderr, "isatty") and sys.stderr.isatty()
|
|
return False
|
|
|
|
|
|
def _is_ascend_module(pathname: str) -> bool:
|
|
if not pathname:
|
|
return False
|
|
return "vllm_ascend" in pathname.replace("\\", "/")
|
|
|
|
|
|
def _infer_module_name(pathname: str) -> str:
|
|
"""Infer module name from the file path of the log caller."""
|
|
if not pathname:
|
|
return "core"
|
|
parts = pathname.replace("\\", "/").split("/")
|
|
try:
|
|
idx = parts.index("vllm_ascend")
|
|
if idx + 1 >= len(parts):
|
|
return "core"
|
|
item = parts[idx + 1]
|
|
if idx + 2 >= len(parts):
|
|
return item[:-3] if item.endswith(".py") else item
|
|
return item
|
|
except ValueError:
|
|
return "core"
|
|
|
|
|
|
def _format_with_ascend_prefix(self, record, super_format):
|
|
if not _is_ascend_module(record.pathname):
|
|
return super_format(record)
|
|
module = _infer_module_name(record.pathname)
|
|
if record.filename == module + ".py":
|
|
prefix = "[vllm-ascend]"
|
|
else:
|
|
prefix = f"[vllm-ascend] [{module}]"
|
|
orig_msg = record.msg
|
|
orig_args = record.args
|
|
try:
|
|
record.msg = f"{prefix} - {record.getMessage()}"
|
|
record.args = ()
|
|
return super_format(record)
|
|
finally:
|
|
record.msg = orig_msg
|
|
record.args = orig_args
|
|
|
|
|
|
class AscendFormatter(NewLineFormatter):
|
|
"""Extends NewLineFormatter with [vllm-ascend] prefix and module name."""
|
|
|
|
def format(self, record):
|
|
return _format_with_ascend_prefix(self, record, super().format)
|
|
|
|
|
|
class AscendColoredFormatter(ColoredFormatter):
|
|
"""Extends ColoredFormatter with [vllm-ascend] prefix and module name."""
|
|
|
|
def format(self, record):
|
|
return _format_with_ascend_prefix(self, record, super().format)
|
|
|
|
|
|
class RotatingAscendFileHandler(logging.FileHandler):
|
|
"""FileHandler that rotates log files when they exceed a size limit.
|
|
|
|
Naming convention:
|
|
vllm_ascend_{timestamp}_{pid}.log <- first file
|
|
vllm_ascend_{timestamp}_{pid}_002.log <- second file
|
|
vllm_ascend_{timestamp}_{pid}_003.log <- third file
|
|
"""
|
|
|
|
def __init__(self, log_dir: str, max_bytes: int = _LOG_MAX_BYTES) -> None:
|
|
self._log_dir = log_dir
|
|
self._max_bytes = max_bytes
|
|
self._sequence = 1
|
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
self._base_name = f"vllm_ascend_{timestamp}_{os.getpid()}"
|
|
log_file = os.path.join(log_dir, f"{self._base_name}.log")
|
|
super().__init__(log_file, encoding="utf-8")
|
|
|
|
def emit(self, record) -> None:
|
|
try:
|
|
if self.stream is not None and os.path.isfile(self.baseFilename):
|
|
if os.path.getsize(self.baseFilename) >= self._max_bytes:
|
|
self._rotate()
|
|
except OSError:
|
|
pass
|
|
super().emit(record)
|
|
|
|
def _rotate(self) -> None:
|
|
self.stream.close()
|
|
self.stream = None # type: ignore[assignment]
|
|
self._sequence += 1
|
|
new_file = os.path.join(self._log_dir, f"{self._base_name}_{self._sequence:03d}.log")
|
|
self.baseFilename = new_file
|
|
self.stream = self._open()
|
|
|
|
|
|
_file_logging_configured = False
|
|
_file_handler: logging.Handler | None = None
|
|
|
|
|
|
def _setup_file_logging(log_dir: str | None = None) -> None:
|
|
global _file_logging_configured, _file_handler
|
|
if _file_logging_configured:
|
|
return
|
|
target_dir = log_dir or _LOG_DIR
|
|
os.makedirs(target_dir, exist_ok=True)
|
|
file_handler = RotatingAscendFileHandler(target_dir)
|
|
vllm_logger = logging.getLogger("vllm")
|
|
ascend_logger = logging.getLogger("vllm_ascend")
|
|
log_level = logging.INFO
|
|
if vllm_logger.handlers:
|
|
log_level = vllm_logger.handlers[0].level
|
|
file_handler.setLevel(log_level)
|
|
file_handler.setFormatter(AscendFormatter(fmt=_FORMAT, datefmt=_DATE_FORMAT))
|
|
vllm_logger.addHandler(file_handler)
|
|
ascend_logger.addHandler(file_handler)
|
|
_file_handler = file_handler
|
|
_file_logging_configured = True
|
|
|
|
|
|
def configure_ascend_file_logging() -> None:
|
|
global _file_logging_configured, _file_handler
|
|
log_dir = _LOG_DIR
|
|
try:
|
|
from vllm_ascend.ascend_config import get_ascend_config
|
|
|
|
ascend_config = get_ascend_config()
|
|
log_dir = ascend_config.ascend_log_path
|
|
except Exception:
|
|
pass
|
|
if log_dir != _LOG_DIR:
|
|
vllm_logger = logging.getLogger("vllm")
|
|
ascend_logger = logging.getLogger("vllm_ascend")
|
|
if _file_handler is not None:
|
|
vllm_logger.removeHandler(_file_handler)
|
|
ascend_logger.removeHandler(_file_handler)
|
|
_file_handler.close()
|
|
_file_handler = None
|
|
_file_logging_configured = False
|
|
_setup_file_logging(log_dir)
|
|
|
|
|
|
def configure_ascend_logging() -> None:
|
|
"""Configure vllm_ascend logger with Ascend formatters.
|
|
|
|
Creates a dedicated handler for the vllm_ascend logger namespace,
|
|
avoiding any modification to vLLM's global logging state.
|
|
This approach is safe for upstream tests and multiprocessing.
|
|
"""
|
|
ascend_logger = logging.getLogger("vllm_ascend")
|
|
if ascend_logger.handlers:
|
|
return
|
|
|
|
# Parse stream parameter
|
|
if envs.VLLM_LOGGING_STREAM == "ext://sys.stdout":
|
|
stream = sys.stdout
|
|
elif envs.VLLM_LOGGING_STREAM == "ext://sys.stderr":
|
|
stream = sys.stderr
|
|
else:
|
|
stream = sys.stderr
|
|
|
|
handler = logging.StreamHandler(stream)
|
|
handler.setLevel(envs.VLLM_LOGGING_LEVEL)
|
|
|
|
if _use_color():
|
|
handler.setFormatter(AscendColoredFormatter(fmt=_FORMAT, datefmt=_DATE_FORMAT))
|
|
else:
|
|
handler.setFormatter(AscendFormatter(fmt=_FORMAT, datefmt=_DATE_FORMAT))
|
|
|
|
ascend_logger.addHandler(handler)
|
|
ascend_logger.setLevel(envs.VLLM_LOGGING_LEVEL)
|
|
ascend_logger.propagate = False
|