Logger implment
This commit is contained in:
parent
d1d4860ddc
commit
2ed3bdce68
41
example/logger/outstream.py
Normal file
41
example/logger/outstream.py
Normal file
@ -0,0 +1,41 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
import time
|
||||
import inspect
|
||||
|
||||
from lib_not_dr.logger.structure import LogMessage
|
||||
from lib_not_dr.logger.outstream import FileCacheOutputStream, StdioOutputStream
|
||||
|
||||
if __name__ == '__main__':
|
||||
log_message = LogMessage(messages=['Hello World!'],
|
||||
level=20,
|
||||
stack_trace=inspect.currentframe(),
|
||||
logger_tag='tester',
|
||||
logger_name='test')
|
||||
|
||||
file_cache = FileCacheOutputStream(file_name='test.log')
|
||||
stdio = StdioOutputStream()
|
||||
|
||||
print(file_cache.as_markdown())
|
||||
print(stdio.as_markdown())
|
||||
|
||||
file_cache.write_stdout(log_message)
|
||||
stdio.write_stdout(log_message)
|
||||
# wait for 10 sec
|
||||
print('wait for 11 sec')
|
||||
time.sleep(11)
|
||||
print('finish')
|
||||
# write 10 lines
|
||||
|
||||
for i in range(10):
|
||||
log_message.log_time = time.time_ns()
|
||||
file_cache.write_stdout(log_message)
|
||||
stdio.write_stdout(log_message)
|
||||
|
||||
print('write 10 lines')
|
||||
time.sleep(3)
|
||||
print('exit')
|
@ -12,20 +12,23 @@ import atexit
|
||||
import threading
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from lib_not_dr.types.options import Options
|
||||
from lib_not_dr.logger.structure import LogMessage
|
||||
from lib_not_dr.logger.formatter import BaseFormatter, StdFormatter
|
||||
|
||||
__all__ = [
|
||||
'BaseOutputStream'
|
||||
'BaseOutputStream',
|
||||
'StdioOutputStream',
|
||||
'FileCacheOutputStream'
|
||||
]
|
||||
|
||||
|
||||
class BaseOutputStream(Options):
|
||||
name = 'BaseOutputStream'
|
||||
|
||||
level: int = 20
|
||||
level: int = 10
|
||||
enable: bool = True
|
||||
|
||||
formatter: BaseFormatter
|
||||
@ -46,6 +49,7 @@ class BaseOutputStream(Options):
|
||||
class StdioOutputStream(BaseOutputStream):
|
||||
name = 'StdioOutputStream'
|
||||
|
||||
level: int = 10
|
||||
formatter: BaseFormatter = StdFormatter()
|
||||
|
||||
def write_stdout(self, message: LogMessage) -> None:
|
||||
@ -77,8 +81,8 @@ class StdioOutputStream(BaseOutputStream):
|
||||
class FileCacheOutputStream(BaseOutputStream):
|
||||
name = 'FileCacheOutputStream'
|
||||
|
||||
level: int = 10
|
||||
formatter: BaseFormatter = StdFormatter(enable_color=False)
|
||||
|
||||
text_cache: io.StringIO = None
|
||||
|
||||
flush_counter: int = 0
|
||||
@ -88,12 +92,13 @@ class FileCacheOutputStream(BaseOutputStream):
|
||||
flush_lock: threading.Lock = None
|
||||
flush_timer: threading.Timer = None
|
||||
|
||||
file_path: Path = Path('./logs')
|
||||
file_path: Optional[Path] = Path('./logs')
|
||||
file_name: str
|
||||
# file mode: always 'a'
|
||||
file_encoding: str = 'utf-8'
|
||||
# do file swap or not
|
||||
file_swap: bool = False
|
||||
at_exit_register: bool = False
|
||||
|
||||
file_swap_counter: int = 0
|
||||
file_swap_name_template: str = '${name}-${counter}.log'
|
||||
@ -111,17 +116,11 @@ class FileCacheOutputStream(BaseOutputStream):
|
||||
file_swap_on_both: bool = False # swap file when both size and time limit reached
|
||||
|
||||
def init(self, **kwargs) -> bool:
|
||||
if self.text_cache is None:
|
||||
# ( 其实我也不确定为啥这么写 反正按照 "规范" 来说, StringIO 算是 "file" )
|
||||
return True
|
||||
self.flush_lock = threading.Lock()
|
||||
return False
|
||||
|
||||
def load_file(self) -> bool:
|
||||
self.file_start_time = round(time.time())
|
||||
if self.text_cache is None:
|
||||
self.text_cache = io.StringIO()
|
||||
return True
|
||||
self.flush_lock = threading.Lock()
|
||||
return False
|
||||
|
||||
def _write(self, message: LogMessage) -> None:
|
||||
"""
|
||||
@ -132,15 +131,17 @@ class FileCacheOutputStream(BaseOutputStream):
|
||||
"""
|
||||
self.text_cache.write(self.formatter.format_message(message))
|
||||
self.flush_counter += 1
|
||||
if message.flush or self.flush_counter >= self.flush_count_limit or \
|
||||
(0 < self.flush_time_limit <= time.time() - self.file_start_time):
|
||||
if message.flush or self.flush_counter >= self.flush_count_limit:
|
||||
self.flush()
|
||||
else:
|
||||
if self.flush_time_limit > 0:
|
||||
if not self.flush_timer.is_alive() or self.flush_timer is None:
|
||||
if self.flush_timer is None or not self.flush_timer.is_alive():
|
||||
self.flush_timer = threading.Timer(self.flush_time_limit, self.flush)
|
||||
self.flush_timer.daemon = True
|
||||
self.flush_timer.start()
|
||||
atexit.register(self.flush)
|
||||
if not self.at_exit_register:
|
||||
atexit.register(self.flush)
|
||||
self.at_exit_register = True
|
||||
return None
|
||||
|
||||
def write_stdout(self, message: LogMessage) -> None:
|
||||
@ -165,15 +166,18 @@ class FileCacheOutputStream(BaseOutputStream):
|
||||
:return:
|
||||
"""
|
||||
if (current_file := self.current_file_name) is None:
|
||||
if self.file_start_time is None:
|
||||
self.file_start_time = round(time.time())
|
||||
if not self.file_swap:
|
||||
# 直接根据 file name 生成文件
|
||||
current_file = Path(self.file_path) / self.file_name
|
||||
self.current_file_name = str(current_file)
|
||||
return current_file
|
||||
template = string.Template(self.file_swap_name_template)
|
||||
file_name = template.safe_substitute(name=self.file_name,
|
||||
counter=self.file_swap_counter,
|
||||
log_time=round(time.time()),
|
||||
start_time=self.file_start_time)
|
||||
current_file = Path(self.file_path) / file_name
|
||||
self.current_file_name = str(current_file.absolute())
|
||||
self.current_file_name = str(current_file)
|
||||
else:
|
||||
current_file = Path(current_file)
|
||||
return current_file
|
||||
@ -214,8 +218,10 @@ class FileCacheOutputStream(BaseOutputStream):
|
||||
if text == '':
|
||||
return None
|
||||
current_file = self.check_flush()
|
||||
current_file.touch(mode=0o666, exist_ok=True)
|
||||
with open(current_file, 'a', encoding=self.file_encoding) as f:
|
||||
if not current_file.exists():
|
||||
current_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
current_file.touch()
|
||||
with current_file.open('a', encoding=self.file_encoding) as f:
|
||||
f.write(text)
|
||||
return None
|
||||
|
||||
|
@ -24,7 +24,7 @@ class LogMessage(Options):
|
||||
split: str = ' '
|
||||
|
||||
# 消息的属性
|
||||
flush: bool = True
|
||||
flush: bool = None
|
||||
level: int = 20
|
||||
log_time: float = None # time.time_ns()
|
||||
logger_name: str = 'root'
|
||||
@ -35,7 +35,7 @@ class LogMessage(Options):
|
||||
messages: Optional[List[str]] = None,
|
||||
end: Optional[str] = '\n',
|
||||
split: Optional[str] = ' ',
|
||||
flush: Optional[bool] = True,
|
||||
flush: Optional[bool] = None,
|
||||
level: Optional[int] = 20,
|
||||
log_time: Optional[float] = None,
|
||||
logger_name: Optional[str] = 'root',
|
||||
@ -70,7 +70,7 @@ class LogMessage(Options):
|
||||
def init(self, **kwargs) -> bool:
|
||||
if self.log_time is None:
|
||||
self.log_time = time.time_ns()
|
||||
if not isinstance(self.flush, bool):
|
||||
if not isinstance(self.flush, bool) and self.flush is not None:
|
||||
self.flush = True if self.flush else False
|
||||
return False
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user