做了两个月logger × 选了两个月颜色 √

This commit is contained in:
shenjack 2022-09-03 22:35:57 +08:00
parent babb321847
commit d3a2ea2a0c
8 changed files with 174 additions and 115 deletions

1
DR.py
View File

@ -55,7 +55,6 @@ if __name__ == '__main__':
glClearColor(0.5, 0.5, 0.5, 0)
game = main.Game() # 实例化一个游戏
print(time.perf_counter_ns() - start_time_perf_ns, (time.perf_counter_ns() - start_time_perf_ns) / (10 ** 9), 'start') # 输出一下启动用时
cprofile = False # 是否使用cprofile

View File

@ -69,6 +69,7 @@ class _DR_option(Options):
InputBox_use_TextEntry: bool = False
use_local_logging: bool = False
record_threads: bool = True
use_cProfile: bool = False
# tests
playing: bool = False

View File

@ -17,15 +17,17 @@ import time
import logging
import traceback
from typing import List, Union
from decimal import Decimal
# Difficult_Rocket function
from Difficult_Rocket import Options
from Difficult_Rocket import Options, DR_runtime
from Difficult_Rocket.command import line, tree
from Difficult_Rocket.utils import new_thread
from Difficult_Rocket.utils.translate import tr
from Difficult_Rocket.client.guis.widgets import InputBox
# from Difficult_Rocket.client.screen import DRScreen
# from Difficult_Rocket.client.screen import DRDEBUGScreen
from Difficult_Rocket.utils import tools, translate
from Difficult_Rocket.client.fps.fps_log import FpsLogger
from Difficult_Rocket.exception.command import CommandError
@ -112,6 +114,7 @@ class ClientWindow(Window):
self.frame = pyglet.gui.Frame(self, order=20)
self.M_frame = pyglet.gui.MovableFrame(self, modifier=key.LCTRL)
# self.DRscreen = DRScreen(self)
self.screen_list = []
# setup
self.setup()
# 命令显示
@ -135,14 +138,19 @@ class ClientWindow(Window):
self.logger.info(tr.lang('window', 'os.pid_is').format(os.getpid(), os.getppid()))
end_time = time.time_ns()
self.use_time = end_time - start_time
DR_runtime.client_setup_time_ns = self.use_time
self.logger.info(tr.lang('window', 'setup.use_time').format(Decimal(self.use_time) / 1000000000))
self.logger.debug(tr.lang('window', 'setup.use_time_ns').format(self.use_time))
self.count = 0
def setup(self):
self.load_fonts()
from Difficult_Rocket.client.screen import DRDEBUGScreen, DRScreen, BaseScreen
self.screen_list: List[BaseScreen]
self.screen_list.append(DRDEBUGScreen(self))
self.screen_list.append(DRScreen(self))
def load_fonts(self):
def load_fonts(self) -> None:
fonts_folder_path = self.main_config['runtime']['fonts_folder']
# 加载字体路径
# 淦,还写了个递归来处理

View File

@ -11,7 +11,8 @@ from Difficult_Rocket.command.tree import CommandTree
class BaseScreen:
def __init__(self, main_window: "ClientWindow"):
def __init__(self, main_window: ClientWindow):
self.window_pointer = main_window
self.command_tree = None
self.create_command_tree()
@ -23,5 +24,12 @@ class BaseScreen:
class DRScreen(BaseScreen):
def __init__(self, main_window: "ClientWindow"):
def __init__(self, main_window: ClientWindow):
super().__init__(main_window)
class DRDEBUGScreen(BaseScreen):
def __init__(self, main_window: ClientWindow):
super().__init__(main_window)

View File

@ -3,7 +3,7 @@
# Copyright © 2021-2022 by shenjackyuanjie 3695888@qq.com
# All rights reserved
# -------------------------------
from exception import BaseRuntimeError
from Difficult_Rocket.exception import BaseRuntimeError
__all__ = ["LockTimeOutError"]

View File

@ -2,22 +2,26 @@
@author shenjackyuanjie
@contact 3695888@qq.com
"""
import re
import os
# os.chdir('../../')
import sys
sys.path.append(os.path.abspath('./Difficult_Rocket'))
print(sys.path)
# if __name__ == "__main__":
# os.chdir('../')
import time
import atexit
import inspect
import threading
# from inspect import F
from os import PathLike
from time import strftime
from logging import NOTSET, DEBUG, INFO, WARNING, ERROR, FATAL
from types import FrameType
from typing import Optional, Union, Dict, Iterable, Tuple, List, Callable
print(os.path.abspath(os.curdir))
os.chdir('../../')
sys.path.append('D:/githubs/DR')
sys.path.append(os.path.abspath('./Difficult_Rocket'))
from Difficult_Rocket.utils.thread import ThreadLock
# 如果想要直接使用 logger 来 logging
@ -34,6 +38,8 @@ from Difficult_Rocket.utils.thread import ThreadLock
color_reset_suffix = "\033[0m"
""" 只是用来重置颜色的后缀 """
re_find_color_code = r'\033\[[^\f\n\r\t\vm]*m'
"""
OFF > FATAL > ERROR > WARN > INFO > FINE > FINER > DEBUG > TRACE > ALL
logging.py
@ -75,6 +81,45 @@ name_level_map = {
'FATAL': FATAL
}
logger_configs = {
'Logger': {
'root': {
'level': TRACE,
'color': 'main_color',
'file': 'main_log_file',
},
},
'Color': {
'main_color': {
'date': {},
TRACE: {'info': '\033[34;48;2;44;44;54m', 'message': '\033[34;48;2;40;40;40m'},
FINE: {'info': '\033[35;48;2;44;44;54m', 'message': '\033[35m'},
DEBUG: {'info': '\033[38;2;133;138;149;48;2;44;44;54m', 'message': '\033[38;2;133;138;149m'},
INFO: {'info': '\033[32;48;2;44;44;54m', 'message': '\033[32m'},
WARNING: {'info': '\033[33;48;2;44;44;54m', 'message': '\033[33m'},
ERROR: {'info': '\033[31;48;2;44;44;54m', 'message': '\033[31m'},
FATAL: {'info': '\033[38;2;255;200;72;48;2;120;10;10m', 'message': '\033[38;2;255;200;72;48;2;120;10;10m'}
}
},
'File': {
'main_log_file': {
'mode': 'a',
'encoding': 'utf-8',
'level': DEBUG,
'file_name': '{file_time}_logs.md'
},
},
'Formatter': {
'MESSAGE': {
'format': '[\033[38;2;201;222;56m{main_time}\033[0m] {level} | {file_name}:{code_line} | {message}'
},
'file_time': {'strftime': '%Y-%m-%d %H-%M'},
'main_time': {'strftime': '%Y-%m-%d %H-%M-%S:%%S'}, # %%S 三位毫秒
'encoding': 'utf-8',
...: ...
}
}
class ListCache:
"""一个线程安全的列表缓存"""
@ -113,7 +158,8 @@ class ListCache:
def __next__(self):
if self._iter_cache == -1:
raise StopIteration
del self._iter_cache
raise StopIteration('there is no more cache')
returns = self._iter_cache[-self._iter_len]
self._iter_cache -= 1
return returns
@ -142,19 +188,17 @@ class LogFileCache:
self.flush_time = flush_time # 缓存刷新时长
self.cache_entries_num = log_cache_lens_max
self.started = False
self.log
# self.log
# 同步锁
self.cache_lock = threading.Lock() # 主锁
self.write_lock = threading.Lock() # 写入锁
self.with_thread_lock = ThreadLock(self.cache_lock, time_out=1 / 60) # 直接用于 with 的主锁
self.time_limit_lock = ThreadLock(self.cache_lock, time_out=1 / 60) # 直接用于 with 的主锁
self.threaded_write = threading.Timer(1, self._log_file_time_write) # 基于 timer 的多线程
# 日志缓存表
self.log_cache = ListCache(self.with_thread_lock)
self.log_cache = ListCache(self.time_limit_lock)
def end_thread(self) -> None:
"""结束日志写入进程,顺手把目前的缓存写入"""
self.cache_lock.acquire(blocking=True)
self.write_lock.acquire(blocking=True)
self.threaded_write.cancel()
self.started = False
self._log_file_time_write()
@ -171,20 +215,20 @@ class LogFileCache:
@logfile_name.setter
def logfile_name(self, value: PathLike) -> None:
with self.with_thread_lock:
with self.time_limit_lock:
self._logfile_name = value
def _log_file_time_write(self) -> None:
"""使用 threading.Timer 调用的定时写入日志文件的函数"""
if self.log_cache:
with self.with_thread_lock:
with self.time_limit_lock:
if self.log_cache:
with open(file=self.logfile_name, encoding='utf-8', mode='a') as log_file:
log_file.writelines(self.log_cache)
def write_logs(self, string: str, wait_for_cache: bool = True) -> None:
if not wait_for_cache:
with self.with_thread_lock and open(file=self.logfile_name, encoding='utf-8', mode='a') as log_file:
with self.time_limit_lock and open(file=self.logfile_name, encoding='utf-8', mode='a') as log_file:
if self.log_cache:
log_file.writelines(self.log_cache)
log_file.write(string)
@ -195,7 +239,7 @@ class LogFileCache:
class Logger:
"""shenjack logger"""
def __init__(self, name: str = None, level: int = None, file_name: PathLike = None, **kwargs) -> None:
def __init__(self, name: str = None, level: int = None, file_name: PathLike = None, colors: Dict[int, Dict[str, str]] = None, formats=None, **kwargs) -> None:
"""
配置模式: 使用 kwargs 配置
@param name: logger 名称 默认为 root
@ -203,8 +247,9 @@ class Logger:
@param file_name: logging 写入文件名称 默认为 None(不写入)
"""
self.name = name or 'root'
self.level = level or DEBUG
self.colors = None
self.level = level if level is not None else DEBUG
self.colors = colors or logger_configs['Color']['main_color']
self.formats = formats or logger_configs['Formatter']
if file_name:
self.file_cache = LogFileCache(file_name=file_name)
else:
@ -215,17 +260,46 @@ class Logger:
level: int,
sep: Optional[str] = ' ',
end: Optional[str] = '\n',
flush: Optional[bool] = False) -> None:
flush: Optional[bool] = False,
frame: Optional[FrameType] = None) -> None:
if level < self.level:
return None
# print(level, values, sep, end, flush, sep='|')
write_text = sep.join(i if type(i) is str else str(i) for i in values).__add__(end)
print(write_text, end='')
# self.file_cache.write_logs()
if not frame:
frame = inspect.currentframe()
frame = frame.f_back.f_back
elif (frame := inspect.currentframe()) is not None:
frame = frame.f_back
text = sep.join(i if type(i) is str else str(i) for i in values)
text = f"{self.colors[level]['message']}{text}{color_reset_suffix}"
print_text = self.format_text(level=level, text=text, frame=frame)
print(print_text, end=end)
if self.file_cache:
self.file_cache: LogFileCache
if not self.file_cache.started:
self.file_cache.start_thread()
self.file_cache.write_logs(re.sub(re_find_color_code, '', print_text), wait_for_cache=flush)
return None
def format_text(self, level: int, text: str, frame: Optional[FrameType]) -> str:
from Difficult_Rocket import DR_option, DR_runtime
level_with_color = f"[{self.colors[level]['info']}{level_name_map[level]}{color_reset_suffix}]"
level_with_color = f"{level_with_color}{' ' * (9 - len_without_color_maker(level_with_color))}"
formats = self.formats.copy()
formats.pop('MESSAGE')
if frame is None:
formats['file_name'] = 'no frame'
formats['code_line'] = 'no frame'
else:
formats['file_name'] = os.path.split(frame.f_code.co_filename)[-1]
formats['code_line'] = frame.f_lineno
now_time = str(time.time())
for key, value in formats.items():
if isinstance(value, dict):
if 'strftime' in value:
value['strftime']: str
formats[key] = strftime(value['strftime'].replace('%%S', now_time[now_time.find('.') + 1:now_time.find('.') + 4]))
elif value == 'game.version':
formats[key] = DR_runtime.DR_version
print_text = self.formats['MESSAGE']['format'].format(level_with_color=level_with_color, level=level_with_color, message=text, **formats)
return print_text
def trace(self, *values: object,
sep: Optional[str] = ' ',
@ -281,6 +355,11 @@ def color_in_033(*args) -> str:
return color_text
def len_without_color_maker(text: str) -> int:
with_out_text = re.sub(re_find_color_code, '', text)
return len(with_out_text)
def rgb(r: int, g: int, b: int) -> Tuple[int, int, int]:
return r, g, b
@ -290,42 +369,8 @@ def logging_color() -> Dict:
return {'info': ..., 'message': ...}
logger_configs = {
'Logger': {
'root': {
'level': TRACE,
'color': 'main_color',
'file': 'main_log_file',
},
},
'Color': {
'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'}
}
},
'File': {
'main_log_file': {
'mode': 'a',
'encoding': 'utf-8',
'level': DEBUG,
'file_name': '{file_time}_logs.md'
},
},
'Formatter': {
'file_time': {'strftime': '%Y-%m-%d %H-%M'},
'main_time': {'strftime': '%Y-%m-%d %H-%M-%S'},
'version': 'game.version',
'level': 'level',
'encoding': 'utf-8',
...: ...
}
}
def setup_logger() -> None:
...
def add_dict_config_to_global(some_dict: Union[dict, list, str], name: str) -> dict:
@ -360,25 +405,14 @@ def get_logger(name: str = 'name') -> Logger:
if __name__ == "__main__":
# import os
# 在这里可以使用 add_kwargs_to_global
logger = Logger(name="Main")
logger1 = Logger(name="RenderThread")
logger2 = Logger(name="TaskExecuter#1-1")
while True:
logger = Logger(name="Main", level=NOTSET)
for x in range(5):
logger.trace('tracing')
logger.fine('some fine!')
logger.debug('debugging')
logger.info("Hello World!!")
logger1.error("OpenGL Error 10086")
logger2.warning("Cannot write file.")
some_logger = Logger(name='aaa')
some_logger.level = ALL
some_logger.warn('aaaa', 'aaaa')
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)
logger.warn('warning')
logger.error('error haaaa')
logger.fatal('oh no')

View File

@ -29,33 +29,42 @@ class Threads(threading.Thread):
class ThreadLock:
def __init__(self, the_lock: Lock, time_out: Union[float, int] = 1/60) -> None:
def __init__(self, the_lock: Lock, time_out: Union[float, int] = 1 / 60) -> None:
self.lock = the_lock
self.time_out = time_out
def __enter__(self):
# print('enter!')
self.lock.acquire(timeout=self.time_out)
if not self.lock.locked():
raise LockTimeOutError
raise LockTimeOutError('')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.lock.release()
if (exc_type is None) and (exc_val is None) and (exc_tb is None):
# 没有出 bug
self.lock.release()
# print('exit with no error')
return None
else:
# 出 bug 了
self.lock.release()
# print(f'exit with error {exc_type} {exc_val}')
return None
# def __del__(self):
# print('del me!')
# self.__del__()
if __name__ == "__main__":
from Difficult_Rocket.exception import TestError
thread_lock = Lock()
test_lock = ThreadLock(thread_lock)
with test_lock:
print('do some thing')
...
with test_lock:
print('do some error')
raise TestError('ah lock test')

View File

@ -1,31 +1,31 @@
{
'Editor': {
'runtime': {
'toolbar.dark': 'ToolbarDark.png',
'toolbar.light': 'ToolbarLight.png',
'button_side.dark': 'ButtonDarkSide.png',
'button_side.light': 'ButtonLightSide.png'
"Editor": {
"runtime": {
"toolbar.dark": "ToolbarDark.png",
"toolbar.light": "ToolbarLight.png",
"button_side.dark": "ButtonDarkSide.png",
"button_side.light": "ButtonLightSide.png"
},
'toggle_button': {
'stage': 'ToolbarIconStaging.png',
'add_part': 'ToolbarIconAddPart.png',
'menu': 'ToolbarIconMenu.png'
"toggle_button": {
"stage": "ToolbarIconStaging.png",
"add_part": "ToolbarIconAddPart.png",
"menu": "ToolbarIconMenu.png"
},
'push_button': {
'zoom': 'ToolbarIconZoom.png',
'zoom.in': 'ToolbarIconZoomIn.png',
'zoom.out': 'ToolbarIconZoomOut.png',
'play': 'ToolbarIconPlay.png',
'rotate': 'RotateButton.png',
'trash_can': 'TrashCan.png'
"push_button": {
"zoom": "ToolbarIconZoom.png",
"zoom.in": "ToolbarIconZoomIn.png",
"zoom.out": "ToolbarIconZoomOut.png",
"play": "ToolbarIconPlay.png",
"rotate": "RotateButton.png",
"trash_can": "TrashCan.png"
}
},
'Runtime': {
"Runtime": {
},
'Parts': {
'battery': 'Battery.png',
'beam': 'Beam.png',
'cover_bottom': 'CoverBottom.png',
'nose_cone': 'NoseCone.png'
"Parts": {
"battery": "Battery.png",
"beam": "Beam.png",
"cover_bottom": "CoverBottom.png",
"nose_cone": "NoseCone.png"
}
}