当我在装饰器中记录错误时,记录pathname
不是我想要的。
logging.conf:
[loggers]
keys=root
[handlers]
keys=console
[formatters]
keys=console
[logger_root]
...
[handler_console]
...
[formatter_console]
format=%(levelname)s - File "%(pathname)s", line %(lineno)s, %(funcName)s: %(message)s
正常情况下,在文件/home/lizs/test/app.py
中记录错误:
def app():
try:
a # error, on line 12
except Exception, err:
logging.getLogger().error(str(err))
控制台上的调试消息:
ERROR - File "/home/lizs/test/app.py", line 12, app: global name 'a' is not defined
上面的日志记录pathname
(/ home / lizs / test / app.py)就是我想要的。但是当我使用装饰器时:
/home/lizs/test/app.py
:
from decorators import logging_decorator
@logging_decorator
def app():
a
/home/lizs/test/decorators.py
:
def logging_decorator(func):
def error_log():
try:
func() # on line 10
except Exception, err:
logging.getLogger().error(str(err))
return error_log
调试消息:
ERROR - File "/home/lizs/test/decorators.py", line 10, error_log: global name 'a' is not defined
现在,日志记录pathname
是装饰器的路径名(/home/lizs/test/decorators.py)。
当我使用装饰器时,如何将日志pathname
设置为/home/lizs/test/app.py
。
答案 0 :(得分:2)
试试这个:
<强> app.py:强>
from decorators import logging_decorator
@logging_decorator
def app():
a
app()
<强> decorators.py:强>
import logging
import inspect
# init logger
logger = logging.getLogger()
formatter = logging.Formatter('%(levelname)s - File %(real_pathname)s,'
' line %(real_lineno)s, %(real_funcName)s: %(message)s')
console_handle = logging.StreamHandler()
console_handle.setFormatter(formatter)
logger.addHandler(console_handle)
def logging_decorator(func):
def error_log():
try:
func()
except Exception as err:
logger.error(err, extra={'real_pathname': inspect.getsourcefile(func), # path to source file
'real_lineno': inspect.trace()[-1][2], # line number from trace
'real_funcName': func.__name__}) # function name
return error_log
根据docs here,您可以将字典作为extra
参数传递,以使用用户定义的属性填充为日志记录事件创建的__dict__
LogRecord
。然后可以根据需要使用这些自定义属性。
因此,because we can't modify pathname
directly,real_pathname
的这种方法是最直接的。
答案 1 :(得分:2)
您的问题是您的异常处理程序比最初引发异常的位置高一级,因此您必须检查堆栈跟踪并使用正确的文件/行信息手动构建LogRecord:
def logging_decorator(func):
def error_log():
try:
func() # on line 10
except Exception, err:
tb = sys.exc_info()[2] # extract the current exception info
exc_tup = traceback.extract_tb(tb)[-1] # extract the deeper stack frame
logger = logging.getLogger()
# manually build a LogRecord from that stack frame
lr = logger.makeRecord(logger.name,
logging.ERROR, exc_tup[0], exc_tup[1],
str(err), {}, None, exc_tup[2])
logger.handle(lr) # and ask the logging system to process it
return error_log