如何在Python2中调用logging.setLogRecordFactory?
How to call logging.setLogRecordFactory in Python 2?
给定以下简单示例:
import logging
class SmartLogRecord(logging.LogRecord):
""" Dummy LogRecord example """
def getMessage(self):
return self.msg % self.args
logging.setLogRecordFactory(SmartLogRecord)
var = 'SmartLogRecord'
logging.warning('I am a %s', var)
我可以在 Python 3
上 运行 并使用我的自定义 LogRecord
class,但是 Python 2
抛出错误:
linux@linux-PC$ python3 text.py
WARNING:root:I am a SmartLogRecord
linux@linux-PC$ python2 text.py
Traceback (most recent call last):
File "text.py", line 9, in <module>
logging.setLogRecordFactory(SmartLogRecord)
AttributeError: 'module' object has no attribute 'setLogRecordFactory'
linux@linux-PC$ python3 --version
Python 3.7.2
linux@linux-PC$ python2 --version
Python 2.7.16
这是 CPython 3.7 中的 setLogRecordFactory()
:
# https://github.com/python/cpython/blob/29500737d45cbca9604d9ce845fb2acc3f531401/Lib/logging/__init__.py#L386
_logRecordFactory = LogRecord
def setLogRecordFactory(factory):
global _logRecordFactory
_logRecordFactory = factory
def getLogRecordFactory():
return _logRecordFactory
def makeLogRecord(dict):
rv = _logRecordFactory(None, None, "", 0, "", (), None, None)
rv.__dict__.update(dict)
return rv
这个被调用的地方是 Called in Logger.makeRecord()
:
def makeRecord(self, name, level, fn, lno, msg, args, exc_info,
func=None, extra=None, sinfo=None):
"""
A factory method which can be overridden in subclasses to create
specialized LogRecords.
"""
rv = _logRecordFactory(name, level, fn, lno, msg, args, exc_info, func,
sinfo)
相反,在Python2中,这不是一个东西:
# https://github.com/python/cpython/blob/7c2c01f02a1821298a62dd16ecc3a12da663e14b/Lib/logging/__init__.py#L1261
def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
"""
A factory method which can be overridden in subclasses to create
specialized LogRecords.
"""
rv = LogRecord(name, level, fn, lno, msg, args, exc_info, func)
你可以做的基本上是 替换 .makeRecord()
对象上的 .makeRecord()
绑定方法。换句话说:
>>> class A:
... def f(self, a, b):
... return a + b
>>> def new_f(self, a, b):
... return a * b
...
>>> A.f = new_f
>>> A().f(10, 20)
200
这看起来像:
class MyLogRecord(logging.LogRecord):
pass
# override stuff here
def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
print "Using a MyLogRecord instance"
rv = MyLogRecord(name, level, fn, lno, msg, args, exc_info, func)
if extra is not None:
for key in extra:
if (key in ["message", "asctime"]) or (key in rv.__dict__):
raise KeyError("Attempt to overwrite %r in LogRecord" % key)
rv.__dict__[key] = extra[key]
return rv
logging.Logger.makeRecord = makeRecord
插图:
>>> logging.error("hello")
Using a MyLogRecord instance
ERROR:root:hello
在这种情况下,您只是根据使用其他 MyLogRecord
class 的特定需求来定制内容。如果你真的想要,你可以写你自己的 setLogRecordFactory()
如上所示,然后在你的替换 .makeRecord()
方法中使用 _logRecordFactory
,就像 Python 3 所做的那样。
Assumption/alternatives(subclass,不要替换)
还有一条评论:这一切都假设您想要影响 logger
个实例,这些实例不是 "your own," 在别处创建的。如果您仅想要影响您自己的代码定义的记录器,您可以 subclass Logger
而不是完全替换属于 logging.__init__
模块命名空间的 Logger
class。
给定以下简单示例:
import logging
class SmartLogRecord(logging.LogRecord):
""" Dummy LogRecord example """
def getMessage(self):
return self.msg % self.args
logging.setLogRecordFactory(SmartLogRecord)
var = 'SmartLogRecord'
logging.warning('I am a %s', var)
我可以在 Python 3
上 运行 并使用我的自定义 LogRecord
class,但是 Python 2
抛出错误:
linux@linux-PC$ python3 text.py
WARNING:root:I am a SmartLogRecord
linux@linux-PC$ python2 text.py
Traceback (most recent call last):
File "text.py", line 9, in <module>
logging.setLogRecordFactory(SmartLogRecord)
AttributeError: 'module' object has no attribute 'setLogRecordFactory'
linux@linux-PC$ python3 --version
Python 3.7.2
linux@linux-PC$ python2 --version
Python 2.7.16
这是 CPython 3.7 中的 setLogRecordFactory()
:
# https://github.com/python/cpython/blob/29500737d45cbca9604d9ce845fb2acc3f531401/Lib/logging/__init__.py#L386
_logRecordFactory = LogRecord
def setLogRecordFactory(factory):
global _logRecordFactory
_logRecordFactory = factory
def getLogRecordFactory():
return _logRecordFactory
def makeLogRecord(dict):
rv = _logRecordFactory(None, None, "", 0, "", (), None, None)
rv.__dict__.update(dict)
return rv
这个被调用的地方是 Called in Logger.makeRecord()
:
def makeRecord(self, name, level, fn, lno, msg, args, exc_info,
func=None, extra=None, sinfo=None):
"""
A factory method which can be overridden in subclasses to create
specialized LogRecords.
"""
rv = _logRecordFactory(name, level, fn, lno, msg, args, exc_info, func,
sinfo)
相反,在Python2中,这不是一个东西:
# https://github.com/python/cpython/blob/7c2c01f02a1821298a62dd16ecc3a12da663e14b/Lib/logging/__init__.py#L1261
def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
"""
A factory method which can be overridden in subclasses to create
specialized LogRecords.
"""
rv = LogRecord(name, level, fn, lno, msg, args, exc_info, func)
你可以做的基本上是 替换 .makeRecord()
对象上的 .makeRecord()
绑定方法。换句话说:
>>> class A:
... def f(self, a, b):
... return a + b
>>> def new_f(self, a, b):
... return a * b
...
>>> A.f = new_f
>>> A().f(10, 20)
200
这看起来像:
class MyLogRecord(logging.LogRecord):
pass
# override stuff here
def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
print "Using a MyLogRecord instance"
rv = MyLogRecord(name, level, fn, lno, msg, args, exc_info, func)
if extra is not None:
for key in extra:
if (key in ["message", "asctime"]) or (key in rv.__dict__):
raise KeyError("Attempt to overwrite %r in LogRecord" % key)
rv.__dict__[key] = extra[key]
return rv
logging.Logger.makeRecord = makeRecord
插图:
>>> logging.error("hello")
Using a MyLogRecord instance
ERROR:root:hello
在这种情况下,您只是根据使用其他 MyLogRecord
class 的特定需求来定制内容。如果你真的想要,你可以写你自己的 setLogRecordFactory()
如上所示,然后在你的替换 .makeRecord()
方法中使用 _logRecordFactory
,就像 Python 3 所做的那样。
Assumption/alternatives(subclass,不要替换)
还有一条评论:这一切都假设您想要影响 logger
个实例,这些实例不是 "your own," 在别处创建的。如果您仅想要影响您自己的代码定义的记录器,您可以 subclass Logger
而不是完全替换属于 logging.__init__
模块命名空间的 Logger
class。