mirror of
https://github.com/kvcache-ai/ktransformers.git
synced 2025-09-07 21:19:51 +00:00
176 lines
5.4 KiB
Python
176 lines
5.4 KiB
Python
#!/usr/bin/env python
|
|
# coding=utf-8
|
|
'''
|
|
Description :
|
|
Author : unicornchan
|
|
Date : 2024-06-12 02:48:39
|
|
Version : 1.0.0
|
|
LastEditors : chenxl
|
|
LastEditTime : 2024-07-27 01:55:50
|
|
'''
|
|
|
|
import codecs
|
|
import logging
|
|
import os
|
|
import re
|
|
import locale
|
|
from pathlib import Path
|
|
from logging.handlers import BaseRotatingHandler
|
|
import time
|
|
import colorlog
|
|
|
|
from ktransformers.server.config.config import Config
|
|
|
|
|
|
class DailyRotatingFileHandler(BaseRotatingHandler):
|
|
"""
|
|
such as 'logging.TimeRotatingFileHandler', Additional features:
|
|
- support multiprocess
|
|
- support rotating daily
|
|
"""
|
|
|
|
def __init__(self, filename, backupCount=0, encoding=None, delay=False, utc=False, **kwargs): # pylint: disable=unused-argument
|
|
self.backup_count = backupCount
|
|
self.utc = utc
|
|
self.suffix = "%Y-%m-%d"
|
|
self.base_log_path = Path(filename)
|
|
if not os.path.exists(self.base_log_path.parent):
|
|
os.makedirs(self.base_log_path.parent)
|
|
self.base_filename = self.base_log_path.name
|
|
self.current_filename = self._compute_fn()
|
|
self.current_log_path = self.base_log_path.with_name(
|
|
self.current_filename)
|
|
BaseRotatingHandler.__init__(self, filename, 'a', encoding, delay)
|
|
|
|
# pylint: disable=unused-argument, invalid-name
|
|
def shouldRollover(self, record):
|
|
"""
|
|
Determine whether to rotate the log. If the log filename corresponding to the current
|
|
time is not consistent with the currently opened log filename, then it is necessary
|
|
to rotate the log
|
|
Args:
|
|
record: record is not used, as we are just comparing times, but it is needed so
|
|
the method signatures are the same
|
|
"""
|
|
if self.current_filename != self._compute_fn():
|
|
return True
|
|
return False
|
|
|
|
def doRollover(self):
|
|
"""
|
|
roll over
|
|
"""
|
|
# close last log file
|
|
if self.stream:
|
|
self.stream.close()
|
|
self.stream = None # type: ignore
|
|
|
|
# gen new log file name
|
|
self.current_filename = self._compute_fn()
|
|
self.current_log_path = self.base_log_path.with_name(
|
|
self.current_filename)
|
|
|
|
if not self.delay:
|
|
self.stream = self._open() # type: ignore
|
|
|
|
self.delete_expired_files()
|
|
|
|
def _compute_fn(self):
|
|
"""
|
|
gen log file name
|
|
"""
|
|
return self.base_filename + "." + time.strftime(self.suffix, time.localtime())
|
|
|
|
def _open(self):
|
|
"""
|
|
open a new log file, create soft link
|
|
"""
|
|
if self.encoding is None:
|
|
stream = open(str(self.current_log_path), self.mode, encoding=locale.getpreferredencoding())
|
|
else:
|
|
stream = codecs.open(str(self.current_log_path), self.mode, self.encoding)
|
|
|
|
if self.base_log_path.exists():
|
|
try:
|
|
if not self.base_log_path.is_symlink() or os.readlink(self.base_log_path) != self.current_filename:
|
|
os.remove(self.base_log_path)
|
|
except OSError:
|
|
pass
|
|
|
|
try:
|
|
os.symlink(self.current_filename, str(self.base_log_path))
|
|
except OSError:
|
|
pass
|
|
return stream
|
|
|
|
def delete_expired_files(self):
|
|
"""
|
|
delete expired files every day
|
|
"""
|
|
if self.backup_count <= 0:
|
|
return
|
|
|
|
file_names = os.listdir(str(self.base_log_path.parent))
|
|
result = []
|
|
prefix = self.base_filename + "."
|
|
plen = len(prefix)
|
|
for file_name in file_names:
|
|
if file_name[:plen] == prefix:
|
|
suffix = file_name[plen:]
|
|
if re.match(r"^\d{4}-\d{2}-\d{2}(\.\w+)?$", suffix):
|
|
result.append(file_name)
|
|
if len(result) < self.backup_count:
|
|
result = []
|
|
else:
|
|
result.sort()
|
|
result = result[:len(result) - self.backup_count]
|
|
|
|
for file_name in result:
|
|
os.remove(str(self.base_log_path.with_name(file_name)))
|
|
|
|
|
|
class Logger(object):
|
|
"""
|
|
logger class
|
|
"""
|
|
level_relations = {
|
|
'debug': logging.DEBUG,
|
|
'info': logging.INFO,
|
|
'warn': logging.WARNING,
|
|
'error': logging.ERROR,
|
|
'crit': logging.CRITICAL
|
|
}
|
|
|
|
def __init__(self, level: str = 'info'):
|
|
fmt = '%(asctime)s %(levelname)s %(pathname)s[%(lineno)d] %(funcName)s: %(message)s'
|
|
cfg: Config = Config()
|
|
filename: str = os.path.join(cfg.log_dir, cfg.log_file)
|
|
backup_count: int = cfg.backup_count
|
|
th = DailyRotatingFileHandler(filename=filename, when='MIDNIGHT', backupCount=backup_count, encoding="utf-8")
|
|
th.setFormatter(logging.Formatter(fmt))
|
|
|
|
|
|
color_fmt = (
|
|
'%(log_color)s%(asctime)s %(levelname)s %(pathname)s[%(lineno)d]: %(message)s'
|
|
)
|
|
color_formatter = colorlog.ColoredFormatter(
|
|
color_fmt,
|
|
log_colors={
|
|
'DEBUG': 'cyan',
|
|
'INFO': 'green',
|
|
'WARNING': 'yellow',
|
|
'ERROR': 'red',
|
|
'CRITICAL': 'bold_red'
|
|
}
|
|
)
|
|
|
|
sh = logging.StreamHandler()
|
|
sh.setFormatter(color_formatter)
|
|
|
|
self.logger = logging.getLogger(filename)
|
|
self.logger.setLevel(self.level_relations.get(level)) # type: ignore
|
|
self.logger.addHandler(th)
|
|
self.logger.addHandler(sh)
|
|
|
|
|
|
logger = Logger(level=Config().log_level).logger
|