pymud.logger 源代码
import datetime, threading
from queue import SimpleQueue, Empty
from pathlib import Path
from .settings import Settings
[文档]
class Logger:
"""
PyMUD 的记录器类型,可用于会话中向文件记录数据。记录文件保存在当前目录下的 log 子目录中
:param name: 记录器名称,各记录器名称应保持唯一。记录器名称会作为记录文件名称的主要参数
:param mode: 记录模式。可选模式包括 a, w, n 三种。
- a为添加模式,当新开始记录时,会添加在原有记录文件(name.log)之后。
- w为覆写模式,当新开始记录时,会覆写原记录文件(name.log)。
- n为新建模式,当新开始记录时,会以name和当前时间为参数新建一个文件(name.now.log)用于记录。
:param encoding: 记录文件的编码格式,默认为 "utf-8"
:param errors: 当编码模式失败时的处理方式,默认为 "ignore"
:param raw: 记录带ANSI标记的原始内容,还是记录纯文本内容,默认为True,即记录带ANSI标记的原始内容。
"""
# _esc_regx = re.compile(r"\x1b\[[\d;]+[abcdmz]", flags = re.IGNORECASE)
def __init__(self, name, mode = 'a', encoding = "utf-8", errors = "ignore", raw = False):
self._name = name
self._enabled = False
self._raw = raw
self.mode = mode
self._encoding = encoding
self._errors = errors
self._lock = threading.RLock()
self._stream = None
self._queue = SimpleQueue()
@property
def name(self):
"记录器名称,仅在创建时设置,过程中只读"
return self._name
@property
def enabled(self):
"""
使能属性。
从false切换到true时,会打开文件,创建后台线程进行记录。
从true切换到false时,会终止后台记录线程,并关闭记录文件。
"""
return self._enabled
@enabled.setter
def enabled(self, enabled):
if self._enabled != enabled:
if enabled:
mode = "a"
if self._mode in ("a", "w"):
filename = f"{self.name}.log"
mode = self._mode
elif self._mode == "n":
now = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
filename = f"{self.name}.{now}.log"
else:
raise ValueError(Settings.gettext("exception_logmode_error", self._mode))
logdir = Path.cwd().joinpath('log')
if not logdir.exists() or not logdir.is_dir():
logdir.mkdir()
filename = logdir.joinpath(filename)
#filename = os.path.abspath(filename)
self._stream = open(filename, mode = mode, encoding = self._encoding, errors = self._errors)
self._thread = t = threading.Thread(target=self._monitor)
t.daemon = True
t.start()
else:
self._queue.put_nowait(None)
if self._thread:
self._thread.join()
self._thread = None
self._closeFile()
self._enabled = enabled
@property
def raw(self):
"属性,设置和获取是否记录带有ANSI标记的原始记录"
return self._raw
@raw.setter
def raw(self, val: bool):
self._raw = val
@property
def mode(self):
"属性,记录器模式,可为 a, w, n"
return self._mode
@mode.setter
def mode(self, value):
if value in ("a", "w", "n"):
self._mode = value
def _closeFile(self):
"""
Closes the stream.
"""
self._lock.acquire()
try:
if self._stream:
try:
self._stream.flush()
finally:
stream = self._stream
self._stream = None
stream.close()
finally:
self._lock.release()
[文档]
def log(self, msg):
"""
向记录器记录信息。记录的信息会通过队列发送到独立的记录线程。
当记录器未使能时,使用该函数调用也不会记录。
:param msg: 要记录的信息
"""
if self._enabled:
self._queue.put_nowait(msg)
def _monitor(self):
"""
Monitor the queue for records, and ask the handler
to deal with them.
This method runs on a separate, internal thread.
The thread will terminate if it sees a sentinel object in the queue.
"""
newline = True
while self._stream:
try:
data = self._queue.get(block = True)
if data:
self._lock.acquire()
if newline:
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
header = f"{now} {self._name}: "
self._stream.write(header)
newline = False
if data.endswith("\n"):
data = data.rstrip("\n").rstrip("\r") + "\n"
newline = True
if not self._raw:
from .session import Session
data = Session.PLAIN_TEXT_REGX.sub("", data)
#data = self._esc_regx.sub("", data)
self._stream.write(data)
self._stream.flush()
self._lock.release()
else:
break
except Empty:
break