2023-07-04 02:31:55 +08:00
|
|
|
"""Logging configuration for vLLM."""
|
2024-04-19 07:15:12 +08:00
|
|
|
import datetime
|
2024-05-02 08:34:40 +08:00
|
|
|
import json
|
2023-05-09 14:03:35 +08:00
|
|
|
import logging
|
2024-02-06 06:26:50 +08:00
|
|
|
import os
|
2024-03-25 22:59:47 +08:00
|
|
|
import sys
|
2024-04-19 07:15:12 +08:00
|
|
|
from functools import partial
|
2024-05-02 08:34:40 +08:00
|
|
|
from logging import Logger
|
|
|
|
|
from logging.config import dictConfig
|
|
|
|
|
from os import path
|
|
|
|
|
from typing import Dict, Optional
|
2023-05-09 14:03:35 +08:00
|
|
|
|
2024-05-03 02:13:25 +08:00
|
|
|
import vllm.envs as envs
|
|
|
|
|
|
|
|
|
|
VLLM_CONFIGURE_LOGGING = envs.VLLM_CONFIGURE_LOGGING
|
|
|
|
|
VLLM_LOGGING_CONFIG_PATH = envs.VLLM_LOGGING_CONFIG_PATH
|
2024-05-25 14:49:49 +08:00
|
|
|
VLLM_LOGGING_LEVEL = envs.VLLM_LOGGING_LEVEL
|
2024-02-21 06:38:55 +08:00
|
|
|
|
2023-05-09 14:03:35 +08:00
|
|
|
_FORMAT = "%(levelname)s %(asctime)s %(filename)s:%(lineno)d] %(message)s"
|
|
|
|
|
_DATE_FORMAT = "%m-%d %H:%M:%S"
|
|
|
|
|
|
2024-05-02 08:34:40 +08:00
|
|
|
DEFAULT_LOGGING_CONFIG = {
|
|
|
|
|
"formatters": {
|
|
|
|
|
"vllm": {
|
|
|
|
|
"class": "vllm.logging.NewLineFormatter",
|
|
|
|
|
"datefmt": _DATE_FORMAT,
|
|
|
|
|
"format": _FORMAT,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"handlers": {
|
|
|
|
|
"vllm": {
|
|
|
|
|
"class": "logging.StreamHandler",
|
|
|
|
|
"formatter": "vllm",
|
2024-05-25 14:49:49 +08:00
|
|
|
"level": VLLM_LOGGING_LEVEL,
|
2024-05-02 08:34:40 +08:00
|
|
|
"stream": "ext://sys.stdout",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"loggers": {
|
|
|
|
|
"vllm": {
|
|
|
|
|
"handlers": ["vllm"],
|
|
|
|
|
"level": "DEBUG",
|
|
|
|
|
"propagate": False,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"version": 1,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _configure_vllm_root_logger() -> None:
|
|
|
|
|
logging_config: Optional[Dict] = None
|
|
|
|
|
|
|
|
|
|
if not VLLM_CONFIGURE_LOGGING and VLLM_LOGGING_CONFIG_PATH:
|
|
|
|
|
raise RuntimeError(
|
|
|
|
|
"VLLM_CONFIGURE_LOGGING evaluated to false, but "
|
|
|
|
|
"VLLM_LOGGING_CONFIG_PATH was given. VLLM_LOGGING_CONFIG_PATH "
|
|
|
|
|
"implies VLLM_CONFIGURE_LOGGING. Please enable "
|
|
|
|
|
"VLLM_CONFIGURE_LOGGING or unset VLLM_LOGGING_CONFIG_PATH.")
|
2023-05-09 14:03:35 +08:00
|
|
|
|
2024-05-02 08:34:40 +08:00
|
|
|
if VLLM_CONFIGURE_LOGGING:
|
|
|
|
|
logging_config = DEFAULT_LOGGING_CONFIG
|
2023-05-09 14:03:35 +08:00
|
|
|
|
2024-05-02 08:34:40 +08:00
|
|
|
if VLLM_LOGGING_CONFIG_PATH:
|
|
|
|
|
if not path.exists(VLLM_LOGGING_CONFIG_PATH):
|
|
|
|
|
raise RuntimeError(
|
|
|
|
|
"Could not load logging config. File does not exist: %s",
|
|
|
|
|
VLLM_LOGGING_CONFIG_PATH)
|
|
|
|
|
with open(VLLM_LOGGING_CONFIG_PATH, encoding="utf-8",
|
|
|
|
|
mode="r") as file:
|
|
|
|
|
custom_config = json.loads(file.read())
|
2023-05-09 14:03:35 +08:00
|
|
|
|
2024-05-02 08:34:40 +08:00
|
|
|
if not isinstance(custom_config, dict):
|
|
|
|
|
raise ValueError("Invalid logging config. Expected Dict, got %s.",
|
|
|
|
|
type(custom_config).__name__)
|
|
|
|
|
logging_config = custom_config
|
2023-05-09 14:03:35 +08:00
|
|
|
|
2024-05-02 08:34:40 +08:00
|
|
|
if logging_config:
|
|
|
|
|
dictConfig(logging_config)
|
2023-05-09 14:03:35 +08:00
|
|
|
|
|
|
|
|
|
2024-05-02 08:34:40 +08:00
|
|
|
def init_logger(name: str) -> Logger:
|
|
|
|
|
"""The main purpose of this function is to ensure that loggers are
|
|
|
|
|
retrieved in such a way that we can be sure the root vllm logger has
|
|
|
|
|
already been configured."""
|
2023-05-09 14:03:35 +08:00
|
|
|
|
2024-05-02 08:34:40 +08:00
|
|
|
return logging.getLogger(name)
|
2023-05-09 14:03:35 +08:00
|
|
|
|
|
|
|
|
|
2024-05-02 08:34:40 +08:00
|
|
|
# The root logger is initialized when the module is imported.
|
2023-05-09 14:03:35 +08:00
|
|
|
# This is thread-safe as the module is only imported once,
|
|
|
|
|
# guaranteed by the Python GIL.
|
2024-05-02 08:34:40 +08:00
|
|
|
_configure_vllm_root_logger()
|
2024-04-19 07:15:12 +08:00
|
|
|
|
|
|
|
|
logger = init_logger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _trace_calls(log_path, root_dir, frame, event, arg=None):
|
|
|
|
|
if event in ['call', 'return']:
|
|
|
|
|
# Extract the filename, line number, function name, and the code object
|
|
|
|
|
filename = frame.f_code.co_filename
|
|
|
|
|
lineno = frame.f_lineno
|
|
|
|
|
func_name = frame.f_code.co_name
|
|
|
|
|
if not filename.startswith(root_dir):
|
|
|
|
|
# only log the functions in the vllm root_dir
|
|
|
|
|
return
|
|
|
|
|
# Log every function call or return
|
|
|
|
|
try:
|
2024-04-24 00:45:52 +08:00
|
|
|
last_frame = frame.f_back
|
|
|
|
|
if last_frame is not None:
|
|
|
|
|
last_filename = last_frame.f_code.co_filename
|
|
|
|
|
last_lineno = last_frame.f_lineno
|
|
|
|
|
last_func_name = last_frame.f_code.co_name
|
|
|
|
|
else:
|
|
|
|
|
# initial frame
|
|
|
|
|
last_filename = ""
|
|
|
|
|
last_lineno = 0
|
|
|
|
|
last_func_name = ""
|
2024-04-19 07:15:12 +08:00
|
|
|
with open(log_path, 'a') as f:
|
|
|
|
|
if event == 'call':
|
|
|
|
|
f.write(f"{datetime.datetime.now()} Call to"
|
2024-04-24 00:45:52 +08:00
|
|
|
f" {func_name} in {filename}:{lineno}"
|
|
|
|
|
f" from {last_func_name} in {last_filename}:"
|
|
|
|
|
f"{last_lineno}\n")
|
2024-04-19 07:15:12 +08:00
|
|
|
else:
|
|
|
|
|
f.write(f"{datetime.datetime.now()} Return from"
|
2024-04-24 00:45:52 +08:00
|
|
|
f" {func_name} in {filename}:{lineno}"
|
|
|
|
|
f" to {last_func_name} in {last_filename}:"
|
|
|
|
|
f"{last_lineno}\n")
|
2024-04-19 07:15:12 +08:00
|
|
|
except NameError:
|
|
|
|
|
# modules are deleted during shutdown
|
|
|
|
|
pass
|
|
|
|
|
return partial(_trace_calls, log_path, root_dir)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def enable_trace_function_call(log_file_path: str,
|
|
|
|
|
root_dir: Optional[str] = None):
|
|
|
|
|
"""
|
|
|
|
|
Enable tracing of every function call in code under `root_dir`.
|
|
|
|
|
This is useful for debugging hangs or crashes.
|
|
|
|
|
`log_file_path` is the path to the log file.
|
|
|
|
|
`root_dir` is the root directory of the code to trace. If None, it is the
|
|
|
|
|
vllm root directory.
|
|
|
|
|
|
|
|
|
|
Note that this call is thread-level, any threads calling this function
|
|
|
|
|
will have the trace enabled. Other threads will not be affected.
|
|
|
|
|
"""
|
|
|
|
|
logger.warning(
|
|
|
|
|
"VLLM_TRACE_FUNCTION is enabled. It will record every"
|
|
|
|
|
" function executed by Python. This will slow down the code. It "
|
|
|
|
|
"is suggested to be used for debugging hang or crashes only.")
|
2024-04-26 15:16:58 +08:00
|
|
|
logger.info("Trace frame log is saved to %s", log_file_path)
|
2024-04-19 07:15:12 +08:00
|
|
|
if root_dir is None:
|
|
|
|
|
# by default, this is the vllm root directory
|
|
|
|
|
root_dir = os.path.dirname(os.path.dirname(__file__))
|
|
|
|
|
sys.settrace(partial(_trace_calls, log_file_path, root_dir))
|