Difficult-Rocket/Difficult_Rocket/utils/shenjack.py

384 lines
11 KiB
Python
Raw Normal View History

2022-07-04 15:12:04 +08:00
"""
@author shenjackyuanjie
@contact 3695888@qq.com
"""
2022-08-12 21:07:36 +08:00
import os
2022-08-16 13:25:44 +08:00
# os.chdir('../../')
import sys
sys.path.append(os.path.abspath('./Difficult_Rocket'))
print(sys.path)
2022-08-12 21:07:36 +08:00
# if __name__ == "__main__":
# os.chdir('../')
2022-06-27 14:42:26 +08:00
import atexit
2022-06-27 16:22:40 +08:00
import threading
2022-06-27 14:42:26 +08:00
2022-08-12 21:07:36 +08:00
from os import PathLike
2022-07-16 20:20:23 +08:00
from time import strftime
2022-07-04 15:12:04 +08:00
from logging import NOTSET, DEBUG, INFO, WARNING, ERROR, FATAL
2022-08-12 21:07:36 +08:00
from typing import Optional, Union, Dict, Iterable, Tuple, List, Callable
2022-07-04 15:12:04 +08:00
from Difficult_Rocket.utils.thread import ThreadLock
2022-06-27 16:51:14 +08:00
2022-07-16 20:20:23 +08:00
# 如果想要直接使用 logger 来 logging
# 直接调用 logger.debug() 即可
# 默认配置会有
# ----------
# 配置方式一
# 直接使用 logger.Logger()
# 将会创建一个空 logger
# 可以自行通过
# 配置方式二
2022-08-16 13:25:44 +08:00
2022-07-16 20:20:23 +08:00
2022-06-27 14:42:26 +08:00
color_reset_suffix = "\033[0m"
2022-07-25 18:28:42 +08:00
""" 只是用来重置颜色的后缀 """
2022-06-27 14:42:26 +08:00
2022-07-04 15:12:04 +08:00
"""
2022-07-25 18:28:42 +08:00
OFF > FATAL > ERROR > WARN > INFO > FINE > FINER > DEBUG > TRACE > ALL
2022-07-04 15:12:04 +08:00
logging.py
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
"""
2022-07-25 18:28:42 +08:00
ALL = NOTSET
TRACE = 5
2022-08-03 20:22:36 +08:00
FINE = 7
2022-07-07 18:28:29 +08:00
2022-08-12 21:07:36 +08:00
level_name_map = {
ALL: 'ALL', # NOTSET
TRACE: 'TRACE',
FINE: 'FINE',
DEBUG: 'DEBUG',
INFO: 'INFO',
WARNING: 'WARNING', # WARN
ERROR: 'ERROR',
FATAL: 'FATAL'
}
name_level_map = {
'NOTSET': ALL,
'ALL': ALL,
'TRACE': TRACE,
'FINE': FINE,
'DEBUG': DEBUG,
'INFO': INFO,
'WARNING': WARNING,
'WARN': WARNING,
'ERROR': ERROR,
'CRITICAL': FATAL,
'FATAL': FATAL
}
class ListCache:
"""一个线程安全的列表缓存"""
def __init__(self, lock: ThreadLock):
self._cache = []
self.with_thread_lock = lock
def append(self, value: Union[str, Iterable]):
if isinstance(value, str):
with self.with_thread_lock:
self._cache.append(value)
elif isinstance(value, Iterable):
with self.with_thread_lock:
self._cache.append(*value)
else:
raise TypeError(f"cache must be string or Iterable. not a {type(value)}")
def __getitem__(self, item):
assert isinstance(item, int)
with self.with_thread_lock:
try:
return self._cache[item]
except IndexError as exp:
print(f'cache:{self.cache}')
raise IndexError(f'there is no cache at {item}!\ncache:{self.cache}')
def __call__(self, *args, **kwargs):
return self.cache
def __iter__(self):
with self.with_thread_lock:
self._iter_cache = self._cache.copy()
self._iter_len = len(self.cache)
return self
def __next__(self):
if self._iter_cache == -1:
raise StopIteration
returns = self._iter_cache[-self._iter_len]
self._iter_cache -= 1
return returns
def __bool__(self):
with self.with_thread_lock:
return True if len(self.cache) > 0 else False
@property
def cache(self):
return self._cache
2022-07-04 15:12:04 +08:00
2022-06-27 14:42:26 +08:00
class LogFileCache:
"""日志文件缓存"""
2022-08-12 21:07:36 +08:00
def __init__(self, file_name: PathLike = 'logs//log.log', flush_time: Optional[Union[int, float]] = 1, log_cache_lens_max: int = 10):
2022-07-07 18:28:29 +08:00
"""
@param file_name: 日志文件名称
@param flush_time: 刷新日志缓存写入文件的时长间隔
@param log_cache_lens_max: 日志缓存在自动写入前的最大缓存长度
"""
2022-06-27 14:42:26 +08:00
# 配置相关
2022-06-27 16:51:14 +08:00
self._logfile_name = file_name # log 文件名称
2022-06-27 14:42:26 +08:00
self.flush_time = flush_time # 缓存刷新时长
2022-07-07 18:28:29 +08:00
self.cache_entries_num = log_cache_lens_max
2022-08-12 21:07:36 +08:00
self.started = False
self.log
2022-06-27 16:22:40 +08:00
# 同步锁
2022-07-16 20:20:23 +08:00
self.cache_lock = threading.Lock() # 主锁
self.write_lock = threading.Lock() # 写入锁
self.with_thread_lock = ThreadLock(self.cache_lock, time_out=1 / 60) # 直接用于 with 的主锁
self.threaded_write = threading.Timer(1, self._log_file_time_write) # 基于 timer 的多线程
2022-08-12 21:07:36 +08:00
# 日志缓存表
self.log_cache = ListCache(self.with_thread_lock)
2022-07-04 15:12:04 +08:00
2022-07-16 20:20:23 +08:00
def end_thread(self) -> None:
2022-07-07 18:28:29 +08:00
"""结束日志写入进程,顺手把目前的缓存写入"""
2022-07-16 20:20:23 +08:00
self.cache_lock.acquire(blocking=True)
2022-08-12 21:07:36 +08:00
self.write_lock.acquire(blocking=True)
2022-07-04 15:12:04 +08:00
self.threaded_write.cancel()
2022-08-12 21:07:36 +08:00
self.started = False
2022-07-16 20:20:23 +08:00
self._log_file_time_write()
2022-08-12 21:07:36 +08:00
atexit.unregister(self.end_thread)
2022-07-04 15:12:04 +08:00
2022-07-16 20:20:23 +08:00
def start_thread(self) -> None:
2022-07-04 15:12:04 +08:00
self.threaded_write.start()
2022-08-12 21:07:36 +08:00
self.started = True
2022-07-04 15:12:04 +08:00
atexit.register(self.end_thread)
2022-06-27 16:51:14 +08:00
@property
2022-08-12 21:07:36 +08:00
def logfile_name(self) -> PathLike:
2022-06-27 16:51:14 +08:00
return self._logfile_name
2022-06-27 14:42:26 +08:00
2022-06-27 16:51:14 +08:00
@logfile_name.setter
2022-08-12 21:07:36 +08:00
def logfile_name(self, value: PathLike) -> None:
2022-07-04 15:12:04 +08:00
with self.with_thread_lock:
self._logfile_name = value
2022-06-27 14:42:26 +08:00
def _log_file_time_write(self) -> None:
"""使用 threading.Timer 调用的定时写入日志文件的函数"""
2022-08-12 21:07:36 +08:00
if self.log_cache:
2022-07-16 20:20:23 +08:00
with self.with_thread_lock:
2022-08-12 21:07:36 +08:00
if self.log_cache:
with open(file=self.logfile_name, encoding='utf-8', mode='a') as log_file:
log_file.writelines(self.log_cache)
2022-06-27 14:42:26 +08:00
2022-06-29 13:45:25 +08:00
def write_logs(self, string: str, wait_for_cache: bool = True) -> None:
2022-08-12 21:07:36 +08:00
if not wait_for_cache:
2022-07-16 20:20:23 +08:00
with self.with_thread_lock and open(file=self.logfile_name, encoding='utf-8', mode='a') as log_file:
2022-08-12 21:07:36 +08:00
if self.log_cache:
log_file.writelines(self.log_cache)
2022-06-27 16:22:40 +08:00
log_file.write(string)
2022-06-27 14:42:26 +08:00
else:
2022-08-12 21:07:36 +08:00
self.log_cache.append(string)
2022-06-27 14:42:26 +08:00
class Logger:
"""shenjack logger"""
2022-08-12 21:07:36 +08:00
def __init__(self, name: str = None, level: int = None, file_name: PathLike = None, **kwargs) -> None:
2022-07-16 20:20:23 +08:00
"""
配置模式: 使用 kwargs 配置
2022-08-12 21:07:36 +08:00
@param name: logger 名称 默认为 root
@param level: logging 输出等级 默认为 DEBUG(10)
@param file_name: logging 写入文件名称 默认为 None(不写入)
2022-07-16 20:20:23 +08:00
"""
2022-08-12 21:07:36 +08:00
self.name = name or 'root'
self.level = level or DEBUG
2022-07-16 20:20:23 +08:00
self.colors = None
2022-08-12 21:07:36 +08:00
if file_name:
self.file_cache = LogFileCache(file_name=file_name)
2022-06-27 14:42:26 +08:00
else:
2022-08-12 21:07:36 +08:00
self.file_cache = False
2022-07-16 20:20:23 +08:00
self.warn = self.warning
def make_log(self, *values: object,
level: int,
2022-07-04 15:12:04 +08:00
sep: Optional[str] = ' ',
end: Optional[str] = '\n',
flush: Optional[bool] = False) -> None:
2022-07-16 20:20:23 +08:00
if level < self.level:
return None
2022-08-12 21:07:36 +08:00
# print(level, values, sep, end, flush, sep='|')
2022-08-03 20:22:36 +08:00
write_text = sep.join(i if type(i) is str else str(i) for i in values).__add__(end)
print(write_text, end='')
2022-08-12 21:07:36 +08:00
# self.file_cache.write_logs()
if self.file_cache:
self.file_cache: LogFileCache
if not self.file_cache.started:
self.file_cache.start_thread()
2022-06-27 14:42:26 +08:00
2022-08-03 20:22:36 +08:00
def trace(self, *values: object,
sep: Optional[str] = ' ',
end: Optional[str] = '\n',
flush: Optional[bool] = False) -> None:
return self.make_log(*values, level=TRACE, sep=sep, end=end, flush=flush)
def fine(self, *values: object,
sep: Optional[str] = ' ',
end: Optional[str] = '\n',
flush: Optional[bool] = False) -> None:
return self.make_log(*values, level=FINE, sep=sep, end=end, flush=flush)
2022-07-04 15:12:04 +08:00
def debug(self,
*values: object,
sep: Optional[str] = ' ',
end: Optional[str] = '\n',
flush: Optional[bool] = False) -> None:
2022-08-03 20:22:36 +08:00
return self.make_log(*values, level=DEBUG, sep=sep, end=end, flush=flush)
2022-06-27 14:42:26 +08:00
2022-07-04 15:12:04 +08:00
def info(self,
*values: object,
sep: Optional[str] = ' ',
end: Optional[str] = '\n',
flush: Optional[bool] = False) -> None:
2022-08-03 20:22:36 +08:00
return self.make_log(*values, level=INFO, sep=sep, end=end, flush=flush)
2022-06-27 14:42:26 +08:00
2022-07-04 15:12:04 +08:00
def warning(self,
*values: object,
sep: Optional[str] = ' ',
end: Optional[str] = '\n',
flush: Optional[bool] = False) -> None:
2022-08-03 20:22:36 +08:00
return self.make_log(*values, level=WARNING, sep=sep, end=end, flush=flush)
2022-07-04 15:12:04 +08:00
def error(self,
*values: object,
sep: Optional[str] = ' ',
end: Optional[str] = '\n',
flush: Optional[bool] = False) -> None:
2022-08-03 20:22:36 +08:00
return self.make_log(*values, level=ERROR, sep=sep, end=end, flush=flush)
2022-07-04 15:12:04 +08:00
def fatal(self,
*values: object,
sep: Optional[str] = ' ',
end: Optional[str] = '\n',
flush: Optional[bool] = False) -> None:
2022-08-03 20:22:36 +08:00
return self.make_log(*values, level=FATAL, sep=sep, end=end, flush=flush)
2022-06-27 14:42:26 +08:00
2022-06-29 13:45:25 +08:00
2022-07-25 18:28:42 +08:00
def color_in_033(*args) -> str:
color_text = ';'.join(args)
color_text = f'\033[{color_text}m'
return color_text
def rgb(r: int, g: int, b: int) -> Tuple[int, int, int]:
return r, g, b
def logging_color() -> Dict:
...
return {'info': ..., 'message': ...}
2022-07-07 18:28:29 +08:00
logger_configs = {
2022-07-16 20:20:23 +08:00
'Logger': {
'root': {
2022-07-25 18:28:42 +08:00
'level': TRACE,
2022-08-12 21:07:36 +08:00
'color': 'main_color',
2022-07-16 20:20:23 +08:00
'file': 'main_log_file',
2022-07-04 15:12:04 +08:00
},
2022-07-16 20:20:23 +08:00
},
'Color': {
2022-08-12 21:07:36 +08:00
'main_color': {
TRACE: {'info': '\033[34;40m', 'message': '\033[48;2;40;40;40m'},
FINE: {'info': '', 'message': '\033[35m'},
DEBUG: {'info': '', 'message': '\033[38;2;133;138;149m'},
INFO: {'info': '\033[32;40m', 'message': ''},
WARNING: {'info': '', 'mes sage': '\033[33m'},
ERROR: {'info': '', 'message': '\033[31m'},
FATAL: {'info': '', 'message': '\033[33;41'}
}
2022-07-16 20:20:23 +08:00
},
'File': {
'main_log_file': {
2022-07-04 15:12:04 +08:00
'mode': 'a',
2022-07-16 20:20:23 +08:00
'encoding': 'utf-8',
'level': DEBUG,
2022-07-25 18:28:42 +08:00
'file_name': '{file_time}_logs.md'
2022-07-04 15:12:04 +08:00
},
2022-07-16 20:20:23 +08:00
},
'Formatter': {
2022-07-25 18:28:42 +08:00
'file_time': {'strftime': '%Y-%m-%d %H-%M'},
2022-07-16 20:20:23 +08:00
'main_time': {'strftime': '%Y-%m-%d %H-%M-%S'},
'version': 'game.version',
'level': 'level',
'encoding': 'utf-8',
2022-07-04 15:12:04 +08:00
...: ...
}
}
2022-07-07 18:28:29 +08:00
2022-07-16 20:20:23 +08:00
def add_dict_config_to_global(some_dict: Union[dict, list, str], name: str) -> dict:
2022-07-07 18:28:29 +08:00
"""
2022-07-16 20:20:23 +08:00
提前声明这个函数很有可能搞坏 config
请使用 add_kwargs_to_global 来修改配置
如果你不知道你在改什么**务必不要**用这个函数来修改配置
2022-07-07 18:28:29 +08:00
@param some_dict: 一个你丢进来的 logger 设置
@param name: 这个 logger 设置的名称
@return: 修改过的 logger 配置
"""
logger_configs[name] = some_dict
2022-07-16 20:19:58 +08:00
return logger_configs # 修改过的 logger 配置
2022-07-07 18:28:29 +08:00
def add_kwargs_to_global(**kwargs) -> dict:
"""
2022-07-16 20:19:58 +08:00
@param kwargs: 你要改的 logger配置
@return: 修改过的 logger 配置
2022-07-07 18:28:29 +08:00
"""
...
2022-07-16 20:20:23 +08:00
def get_logger(name: str = 'name') -> Logger:
"""
此函数用于从 global_config 中取出对应的配置建立一个相应的 logger
@param name: logger的名称
@return: 创建好的 logger
"""
...
if __name__ == "__main__":
2022-08-16 13:25:44 +08:00
# import os
2022-08-12 21:07:36 +08:00
2022-07-16 20:20:23 +08:00
# 在这里可以使用 add_kwargs_to_global
2022-08-12 21:07:50 +08:00
logger = Logger(name="Main")
logger1 = Logger(name="RenderThread")
logger2 = Logger(name="TaskExecuter#1-1")
while True:
logger.info("Hello World!!")
logger1.error("OpenGL Error 10086")
logger2.warning("Cannot write file.")
2022-07-16 20:20:23 +08:00
some_logger = Logger(name='aaa')
2022-08-03 20:22:36 +08:00
some_logger.level = ALL
2022-07-16 20:20:23 +08:00
some_logger.warn('aaaa', 'aaaa')
2022-08-12 21:07:36 +08:00
a_lock = threading.Lock()
a_with_lock = ThreadLock(a_lock)
a_cache = ListCache(a_with_lock)
a_cache.append('123123')
print(a_cache[0])
print(a_cache)
2022-08-16 13:25:44 +08:00