我的记录功能如下。
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']
答案 0 :(得分:18)
您只需更改格式字符串以包含它们即可执行当前功能名称,模块和行号。
logging.basicConfig(
filename = fileName,
format = "%(levelname) -10s %(asctime)s %(module)s:%(lineno)s %(funcName)s %(message)s",
level = logging.DEBUG
)
大多数人在记录异常时只需要堆栈,而如果您调用logging.exception()
,则日志记录模块会自动执行此操作。如果您真的想要其他时间的堆栈信息,那么您将需要使用回溯模块来提取所需的其他信息。
答案 1 :(得分:17)
import inspect
import traceback
def method():
frame = inspect.currentframe()
stack_trace = traceback.format_stack(frame)
print ''.join(stack_trace)
使用stack_trace [: - 1]避免在堆栈跟踪中包含方法/ printinfo。
答案 2 :(得分:9)
从Python 3.2开始,这可以简化为将stack_info=True
标志传递给logging calls。但是,对于任何早期版本,您都需要使用上述答案之一。
答案 3 :(得分:4)
迟到的回答,但是很好。
另一种解决方案是,您可以使用文档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日志包本身的堆栈帧。(也可能需要针对不同版本的日志包进行调整)
答案 4 :(得分: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()
答案 5 :(得分:1)
使用traceback模块。
logging.error(traceback.format_exc())
答案 6 :(得分:1)
这是基于@mouad的答案,但通过在每个级别都包括调用堆栈的文件名(但不包括其完整路径)和行号,并且将堆栈保留在最近的位置而变得更加有用(IMO) -from(即不可逆)顺序,因为那是我要阅读的方式:-)
每个条目都具有file:line:func(),其顺序与普通stacktrace相同,但都在同一行上,因此更加紧凑。
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()
我只需要两个关键函数中的这个stacktrace,因此我将调用者的输出添加到logger.debug()调用的文本中,例如htis:
logger.debug("\nWIRE: justdoit request -----\n"+callers()+"\n\n")
答案 7 :(得分:0)
查看追溯模块
>>> 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