tor*_*ond 9 logging python-3.x
我正在尝试使用在我的日志记录中添加自定义字段LogRecordFactory
。我重复调用一个类,每次这样做时,我都想在 init 模块中设置 custom_attribute,以便类中的其余代码将具有此属性。但我无法让它发挥作用。我发现以下内容有效,但它是静态的。
import logging
old_factory = logging.getLogRecordFactory()
def record_factory(*args, **kwargs):
record = old_factory(*args, **kwargs)
record.custom_attribute = "whatever"
return record
logging.basicConfig(format="%(custom_attribute)s - %(message)s")
logging.setLogRecordFactory(record_factory)
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
logging.debug("test")
Run Code Online (Sandbox Code Playgroud)
这将正确输出:
whatever - test
Run Code Online (Sandbox Code Playgroud)
但是,我的用例是 custom_attribute 会有所不同。每次我调用一个特定的函数时,我都想改变它。因此,record_factory 似乎需要传递另一个参数,以便它可以使用新参数返回正确的记录。但我无法弄清楚。我尝试向该函数添加参数,但是当我进行调用时,我得到:
TypeError: __init__() missing 7 required positional arguments: 'name', 'level', 'pathname', 'lineno', 'msg', 'args', and 'exc_info'
Run Code Online (Sandbox Code Playgroud)
*args
我认为这与and**kwargs
但我真的不知道有关。record_factory
另外,为什么调用 by后没有括号logging.setLogRecordFactory
?我从来没有见过一个函数像这样工作。
您可以尝试使用闭包:
import logging
old_factory = logging.getLogRecordFactory()
def record_factory_factory(context_id):
def record_factory(*args, **kwargs):
record = old_factory(*args, **kwargs)
record.custom_attribute = context_id
return record
return record_factory
logging.basicConfig(format="%(custom_attribute)s - %(message)s")
logging.setLogRecordFactory(record_factory_factory("whatever"))
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
logging.debug("test")
logging.setLogRecordFactory(record_factory_factory("whatever2"))
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
logging.debug("test")
Run Code Online (Sandbox Code Playgroud)
结果:
$ python3 log_test.py
whatever - test
whatever2 - test
Run Code Online (Sandbox Code Playgroud)
当我尝试做类似的事情时,我偶然发现了这个问题。这就是我解决这个问题的方法,假设您想将名为 xyz 的内容添加到每个日志行(下面有进一步的解释):
import logging
import threading
thread_local = threading.local()
def add_xyz_to_logrecords(xyz):
factory = logging.getLogRecordFactory()
if isinstance(factory, XYZLogFactory):
factory.set_xyz(xyz)
else:
logging.setLogRecordFactory(XYZLogFactory(factory, xyz))
class XYZLogFactory():
def __init__(self, original_factory, xyz):
self.original_factory = original_factory
thread_local.xyz = xyz
def __call__(self, *args, **kwargs):
record = self.original_factory(*args, **kwargs)
try:
record.xyz = thread_local.xyz
except AttributeError:
pass
return record
def set_xyz(self, xyz):
thread_local.xyz = xyz
Run Code Online (Sandbox Code Playgroud)
Here I've created a callable class XYZLogFactory, that remembers what the current value of xyz is, and also remembers what the original LogRecordFactory was. When called as a function, it creates a record using the original LogRecordFactory, and adds an xyz attribute with the current value. The thread_local is to make it thread-safe, but for an easier version, you could just use an attribute on the XYZLogFactory:
class XYZLogFactory():
def __init__(self, original_factory, xyz):
self.original_factory = original_factory
self.xyz = xyz
def __call__(self, *args, **kwargs):
record = self.original_factory(*args, **kwargs)
record.xyz = self.xyz
return record
def set_xyz(self, xyz):
self.xyz = xyz
Run Code Online (Sandbox Code Playgroud)
In my very first attempt (not shown here), I did not store the original factory, but stored it implicitly in the new LogRecordFactury using a closure. However, after a while that led to a RecursionError, because it kept calling the previous factory, which called the previous factory, etc.
Regarding your last question: there are no parentheses because the function is not called here. Instead it's passed to the logging.setLogRecordFactory, which saves it in a variable somewhere, and then calls that someplace else. If you want more information you can google something like 'functions as first class citizens'. Easy example:
x = str # Assign to x the function that gives string representation of object
x(1) # outputs the string representation of 1, same as if you'd called str(1)
> '1'
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4003 次 |
最近记录: |