我有一个用于日志记录功能的 python 类包装器,当我调用 Print 时,它会同时记录在控制台上(如果我从控制台调用)和文件(始终)。这涵盖了我从 cron 作业实现自动化时的情况。
这些解决方案的问题是日志记录选项“
%(asctime)s:[%(filename)s->%(funcName)s():%(lineno)s] %(levelname)s>> %(message)s
”不会引用“print”方法的原始调用者。
我正在谈论的一个例子,如果我有“Foo”类:
class Foo:
def bar():
try:
print("example")
except Exception as e:
print(f"ERROR:\n{e}")
return
我称之为:
wrapped_logger = Logger()
a = Foo()
a.bar()
输出将是:
2024-11-05 12:02:15,994:[logger.py->write():39] INFO>> example
虽然这在技术上是正确的,但我想知道发生打印的类和函数
Foo.bar
。
这是
logger.py
上的记录器类:
import logging
import sys
from datetime import datetime
class Logger(object):
"""
Fake file-like stream object that redirects writes to a logger instance.
"""
def __init__(self, log_level=logging.INFO):
month = datetime.today().strftime('%Y-%m')
self.logFile = f'./logs/{month}.log'
self.terminal = sys.stdout
self.log = open(self.logFile, "a")
logger = logging.getLogger(__name__)
logger.handlers = []
fh = logging.FileHandler(filename=self.logFile, mode = 'a')
formatter = logging.Formatter('%(asctime)s:[%(filename)s->%(funcName)s():%(lineno)s] %(levelname)s>> %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.setLevel("DEBUG")
self.logger = logger
self.log_level = log_level
self.linebuf = ''
sys.stdout = self
def write(self, buf):
self.terminal.write(buf)
temp_linebuf = self.linebuf + buf
self.linebuf = ''
for line in temp_linebuf.splitlines(True):
if line[-1] == '\n':
self.logger.log(self.log_level, line.rstrip())
else:
self.linebuf += line
def flush(self):
if self.linebuf != '':
self.logger.log(self.log_level, self.linebuf.rstrip())
self.linebuf = ''
我怎样才能做到输出为“
2024-11-05 12:02:15,994:[foo.py->Foo.bar():4] INFO>> example
”
如何获得正确的函数和类名称以及行号?
(是的,类似于 log4net 对 c# 的作用或 log4j 对 java 的作用,有 log4py 吗?xD)是否有更简单的方法来实现这一切?人们如何进行日志记录?
您可以像这样使用
stacklevel
参数。 (详情请参阅参考。)
...
class Logger(object):
...
def write(self, buf):
...
self.logger.log(self.log_level, line.rstrip(), stacklevel=2)
...
...