如何使用Python记录当前行和堆栈信息?

问题描述 投票:18回答:8

我有如下记录功能。

logging.basicConfig(
    filename = fileName,
    format = "%(levelname) -10s %(asctime)s %(message)s",
    level = logging.DEBUG
)

def printinfo(string):
    if DEBUG:
        logging.info(string)

def printerror(string):
    if DEBUG:
        logging.error(string)
    print string

我需要登录行号,堆栈信息。例如:

1: def hello():
2:    goodbye()
3:
4: def goodbye():
5:    printinfo()

---> Line 5: goodbye()/hello()

我怎么能用Python做到这一点?

解决了

def printinfo(string):
    if DEBUG:
        frame = inspect.currentframe()
        stack_trace = traceback.format_stack(frame)
        logging.debug(stack_trace[:-1])
    if LOG:
        logging.info(string)

给我这个信息,这正是我需要的。

DEBUG      2011-02-23 10:09:13,500 [
  '  File "/abc.py", line 553, in <module>\n    runUnitTest(COVERAGE, PROFILE)\n', 
  '  File "/abc.py", line 411, in runUnitTest\n    printinfo(string)\n']
python logging traceback
8个回答
19
投票

您可以通过更改格式字符串以包含它们来执行当前函数名称,模块和行号。

logging.basicConfig(
    filename = fileName,
    format = "%(levelname) -10s %(asctime)s %(module)s:%(lineno)s %(funcName)s %(message)s",
    level = logging.DEBUG
)

大多数人在记录异常时只需要堆栈,如果调用logging.exception(),则日志记录模块会自动执行该操作。如果您在其他时间确实需要堆栈信息,则需要使用回溯模块来提取所需的其他信息。


17
投票
import inspect
import traceback

def method():
   frame = inspect.currentframe()
   stack_trace = traceback.format_stack(frame)
   print ''.join(stack_trace)

使用stack_trace [: - 1]可以避免在堆栈跟踪中包含方法/ printinfo。


10
投票

从Python 3.2开始,这可以简化为将stack_info=True标志传递给logging calls。但是,对于任何早期版本,您都需要使用上述答案之一。


4
投票

迟到的回答,但是哦。

另一种解决方案是,您可以使用docs here中指定的过滤器创建自己的格式化程序。这是一个非常棒的功能,因为您现在不再需要使用辅助函数(并且必须将帮助函数放在您想要堆栈跟踪的任何位置)。相反,自定义格式化将其直接实现到日志本身。

import logging
class ContextFilter(logging.Filter):
    def __init__(self, trim_amount)
        self.trim_amount = trim_amount
    def filter(self, record):
        import traceback
        record.stack = ''.join(
            str(row) for row in traceback.format_stack()[:-self.trim_amount]
        )
        return True

# Now you can create the logger and apply the filter.
logger = logging.getLogger(__name__)
logger.addFilter(ContextFilter(5))

# And then you can directly implement a stack trace in the formatter.    
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s \n %(stack)s')

注意:在上面的代码中,我修剪了最后5个堆栈帧。这只是为了方便,因此我们不会显示python日志包本身的堆栈帧。(也可能需要针对不同版本的日志包进行调整)


3
投票

这是一个我希望它可以帮助你的例子:

import inspect
import logging

logging.basicConfig(
    format = "%(levelname) -10s %(asctime)s %(message)s",
    level = logging.DEBUG
)

def test():

    caller_list = []
    frame = inspect.currentframe()
    this_frame = frame  # Save current frame.

    while frame.f_back:
        caller_list.append('{0}()'.format(frame.f_code.co_name))
        frame = frame.f_back

    caller_line = this_frame.f_back.f_lineno
    callers =  '/'.join(reversed(caller_list))

    logging.info('Line {0} : {1}'.format(caller_line, callers))

def foo():
    test()

def bar():
    foo()

bar()

结果:

INFO       2011-02-23 17:03:26,426 Line 28 : bar()/foo()/test()

2
投票

使用traceback模块。

logging.error(traceback.format_exc())

1
投票

这是基于@ mouad的答案,但通过在每个级别包括文件名(但不是它的完整路径)和调用堆栈的行号,并通过将堆栈保留在最近最近调用的来自(使IMO)更有用(IMO)即,没有逆转)订单,因为这是我想读它的方式:-)

每个条目都有文件:line:func(),它与普通的堆栈跟踪序列相同,但是在同一行上都是如此紧凑。

import inspect

def callers(self):
    caller_list = []
    frame = inspect.currentframe()
    while frame.f_back:
        caller_list.append('{2}:{1}:{0}()'.format(frame.f_code.co_name,frame.f_lineno,frame.f_code.co_filename.split("\\")[-1]))
        frame = frame.f_back
    callers =  ' <= '.join(caller_list)
    return callers

如果您有任何干预调用来生成日志文本,则可能需要添加额外的f_back。

        frame = inspect.currentframe().f_back

产生这样的输出:

file2.py:620:func1() <= file3.py:211:func2() <= file3.py:201:func3() <= main.py:795:func4() <= file4.py:295:run() <= main.py:881:main()

我只需要两个关键函数中的堆栈跟踪,所以我将调用者的输出添加到logger.debug()调用的文本中,如htis:

logger.debug("\nWIRE: justdoit request -----\n"+callers()+"\n\n")

0
投票

查看traceback模块

>>> import traceback
>>> def test():
>>>     print "/".join( str(x[2]) for x in traceback.extract_stack() )
>>> def main():
>>>     test()
>>> main()
<module>/launch_new_instance/mainloop/mainloop/interact/push/runsource/runcode/<module>/main/test
© www.soinside.com 2019 - 2024. All rights reserved.