135 lines
4.2 KiB
Python
135 lines
4.2 KiB
Python
from functools import partial
|
||
import logging
|
||
import os
|
||
import time
|
||
import typing as t
|
||
|
||
import loguru
|
||
import loguru._logger
|
||
from memoization import cached, CachingAlgorithmFlag
|
||
from chatchat.settings import Settings
|
||
|
||
|
||
def _filter_logs(record: dict) -> bool:
|
||
# hide debug logs if Settings.basic_settings.log_verbose=False
|
||
if record["level"].no <= 10 and not Settings.basic_settings.log_verbose:
|
||
return False
|
||
# hide traceback logs if Settings.basic_settings.log_verbose=False
|
||
if record["level"].no == 40 and not Settings.basic_settings.log_verbose:
|
||
record["exception"] = None
|
||
return True
|
||
|
||
|
||
# 默认每调用一次 build_logger 就会添加一次 hanlder,导致 chatchat.log 里重复输出
|
||
@cached(max_size=100, algorithm=CachingAlgorithmFlag.LRU)
|
||
def build_logger(log_file: str = "chatchat"):
|
||
"""
|
||
build a logger with colorized output and a log file, for example:
|
||
|
||
logger = build_logger("api")
|
||
logger.info("<green>some message</green>")
|
||
|
||
user can set basic_settings.log_verbose=True to output debug logs
|
||
use logger.exception to log errors with exceptions
|
||
"""
|
||
loguru.logger._core.handlers[0]._filter = _filter_logs
|
||
logger = loguru.logger.opt(colors=True)
|
||
logger.opt = partial(loguru.logger.opt, colors=True)
|
||
logger.warn = logger.warning
|
||
# logger.error = partial(logger.exception)
|
||
|
||
if log_file:
|
||
if not log_file.endswith(".log"):
|
||
log_file = f"{log_file}.log"
|
||
if not os.path.isabs(log_file):
|
||
log_file = str((Settings.basic_settings.LOG_PATH / log_file).resolve())
|
||
logger.add(log_file, colorize=False, filter=_filter_logs)
|
||
|
||
return logger
|
||
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class LoggerNameFilter(logging.Filter):
|
||
def filter(self, record):
|
||
# return record.name.startswith("{}_core") or record.name in "ERROR" or (
|
||
# record.name.startswith("uvicorn.error")
|
||
# and record.getMessage().startswith("Uvicorn running on")
|
||
# )
|
||
return True
|
||
|
||
|
||
def get_log_file(log_path: str, sub_dir: str):
|
||
"""
|
||
sub_dir should contain a timestamp.
|
||
"""
|
||
log_dir = os.path.join(log_path, sub_dir)
|
||
# Here should be creating a new directory each time, so `exist_ok=False`
|
||
os.makedirs(log_dir, exist_ok=False)
|
||
return os.path.join(log_dir, f"{sub_dir}.log")
|
||
|
||
|
||
def get_config_dict(
|
||
log_level: str, log_file_path: str, log_backup_count: int, log_max_bytes: int
|
||
) -> dict:
|
||
# for windows, the path should be a raw string.
|
||
log_file_path = (
|
||
log_file_path.encode("unicode-escape").decode()
|
||
if os.name == "nt"
|
||
else log_file_path
|
||
)
|
||
log_level = log_level.upper()
|
||
config_dict = {
|
||
"version": 1,
|
||
"disable_existing_loggers": False,
|
||
"formatters": {
|
||
"formatter": {
|
||
"format": (
|
||
"%(asctime)s %(name)-12s %(process)d %(levelname)-8s %(message)s"
|
||
)
|
||
},
|
||
},
|
||
"filters": {
|
||
"logger_name_filter": {
|
||
"()": __name__ + ".LoggerNameFilter",
|
||
},
|
||
},
|
||
"handlers": {
|
||
"stream_handler": {
|
||
"class": "logging.StreamHandler",
|
||
"formatter": "formatter",
|
||
"level": log_level,
|
||
# "stream": "ext://sys.stdout",
|
||
# "filters": ["logger_name_filter"],
|
||
},
|
||
"file_handler": {
|
||
"class": "logging.handlers.RotatingFileHandler",
|
||
"formatter": "formatter",
|
||
"level": log_level,
|
||
"filename": log_file_path,
|
||
"mode": "a",
|
||
"maxBytes": log_max_bytes,
|
||
"backupCount": log_backup_count,
|
||
"encoding": "utf8",
|
||
},
|
||
},
|
||
"loggers": {
|
||
"chatchat_core": {
|
||
"handlers": ["stream_handler", "file_handler"],
|
||
"level": log_level,
|
||
"propagate": False,
|
||
}
|
||
},
|
||
"root": {
|
||
"level": log_level,
|
||
"handlers": ["stream_handler", "file_handler"],
|
||
},
|
||
}
|
||
return config_dict
|
||
|
||
|
||
def get_timestamp_ms():
|
||
t = time.time()
|
||
return int(round(t * 1000))
|