简体   繁体   English

在 Python 中继承记录器名称

[英]Inherit logger name in Python

I am trying to log the uncaught exception in python.我正在尝试在 python 中记录未捕获的异常。 For that, I am setting the sys.excepthook in my __init__.py as follows.为此,我在__init__.py中设置了sys.excepthook ,如下所示。

import sys
import logging
import traceback


def log_except_hook(*exc_info):
    logger = logging.getLogger(__name__)
    text = "".join(traceback.format_exception(*exc_info))
    logger.critical(f"Unhandled exception:\n{text}")


sys.excepthook = log_except_hook

My problem is that when I run a process and an exception occurs, the module name in the logged exception is the name of the folder containing the code ( src in this case), instead of the name of the function in which it occurred ( foo_produce_an_error in this example).我的问题是,当我运行一个进程并发生异常时,记录的异常中的模块名称是包含代码的文件夹的名称(在本例中为src ),而不是发生它的 function 的名称( foo_produce_an_error在这个例子中)。 Please find an example below:请在下面找到一个示例:

2019-10-09 18:55:48,638 src CRITICAL: Unhandled exception:
Traceback (most recent call last):
  File "/Users/ivallesp/Projects/Project_Folder/main.py", line 109, in <module>
    foo_function(7)
  File "/Users/ivallesp/Projects/Project_Folder/src/new_module.py", line 8, in foo_function
    foo_produce_an_error(x)
  File "/Users/ivallesp/Projects/Project_Folder/src/new_module.py", line 12, in foo_produce_an_error
    x / 0
ZeroDivisionError: division by zero

How can I make logging to show the module and name of the function where the error ocurred in the first logging line?如何进行日志记录以显示第一个日志记录行中发生错误的 function 的模块和名称?

You haven't provided enough information to answer the question - for example, how you've configured logging (specifically, the format string/formatter used).您没有提供足够的信息来回答这个问题 - 例如,您如何配置日志记录(特别是使用的格式字符串/格式化程序)。 I can illustrate how to achieve the desired result in general, with an example.我可以通过一个例子来说明如何总体上达到预期的结果。 Suppose you have a failing function in a module failfunc :假设您在模块 failfunc 中有一个失败的failfunc

# failfunc.py
def the_failing_func():
    1 / 0

Then, your main script might be:然后,您的主要脚本可能是:

# logtest_ue.py
import logging
import sys

from failfunc import the_failing_func

def log_except_hook(*exc_info):
    logger = logging.getLogger(__name__)
    tb = exc_info[-1]
    # get the bottom-most traceback entry
    while tb.tb_next:
        tb = tb.tb_next
    modname = tb.tb_frame.f_globals.get('__name__')
    funcname = tb.tb_frame.f_code.co_name
    logger.critical('Unhandled in module %r, function %r: %s',
                    modname, funcname, exc_info[1], exc_info=exc_info)

sys.excepthook = log_except_hook

def main():
    the_failing_func()

if __name__ == '__main__':
    logging.basicConfig(format='%(levelname)s %(message)s')
    sys.exit(main())

when this is run, it prints运行时,它会打印

CRITICAL Unhandled in module 'failfunc', function 'the_failing_func': division by zero
Traceback (most recent call last):
  File "logtest_ue.py", line 23, in <module>
    sys.exit(main())
  File "logtest_ue.py", line 19, in main
    the_failing_func()
  File "/home/vinay/projects/scratch/failfunc.py", line 2, in the_failing_func
    1 / 0
ZeroDivisionError: division by zero

Note the slightly simpler way of getting a traceback into the log, using the exc_info keyword parameter.请注意使用exc_info关键字参数获取日志回溯的稍微简单的方法。 Also note that in this case, the normal module and function name (which could be displayed using %(module)s and %(funcName)s in a format string) would be those where the sys.excepthook points to, not the values where the exception actually occurred.另请注意,在这种情况下,普通模块和 function 名称(可以在格式字符串中使用%(module)s%(funcName)s显示)将是sys.excepthook指向的那些,而不是其中的值异常确实发生了。 For those, you would have to use the traceback object in the way I've illustrated to get the bottom-most frame (where the exception actually occurred) and get the module and function names from that frame.对于那些,您必须按照我说明的方式使用回溯 object 来获取最底部的帧(实际发生异常的位置)并从该帧中获取模块和 function 名称。

The module is hard to get but you can have filename and line number.该模块很难获得,但您可以拥有文件名和行号。 They are contained in exc_info which you don't need to format yourself.它们包含在您不需要自己格式化的 exc_info 中。 You can just pass them to the log function and use a formatter to display it all.您可以将它们传递到日志 function 并使用格式化程序将其全部显示。 Here's an example code to give you an idea how this is done:这是一个示例代码,可让您了解如何完成此操作:

import sys
import logging
import traceback


def log_except_hook(*exc_info):
    logger = logging.getLogger(__name__)
    handler = logging.StreamHandler()
    handler.setFormatter(logging.Formatter('%(asctime)s %(fname)s:%(lnum)s %(message)s %(exc_info)s'))
    logger.addHandler(handler)

    frame = traceback.extract_tb(exc_info[2])[-1]
    fname = frame.filename
    lnum = frame.lineno
    logger.critical("Unhandled exception:", exc_info=exc_info, extra={'fname':fname, 'lnum':lnum})

sys.excepthook = log_except_hook

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM