Python - 如何打印所有日志级别甚至外部异常的堆栈跟踪?
Python - How to print stack trace at all log levels and even outside exceptions?
我的代码库非常大,我们想打印所有日志的堆栈。
这包括所有级别的日志(甚至 INFO 和 DEBUG)。
这还包括异常发生之外的日志。
我学到的东西:
- 堆栈跟踪不会显示,除非你在一个例外中:当调用 logger.exception、set_exec=True 时,跟踪 back.print_exc()
- 我发现显示堆栈的唯一方法是 traceback.print_stack()
- 我现在希望我所有的日志都打印这个,但我不知道如何覆盖记录器。debug/info/warning/error 添加 traceback.print_stack()
- 这可以使用格式化程序吗?如果不是,是否可以在 logger.info() 方法发送到格式化程序之前覆盖它?
- 还有其他建议吗?
你走在正确的轨道上。我建议您阅读 logging HOWTO,它解释了很多事情。
您可以使用级别和过滤器来决定您的处理程序是否应该处理日志。并且您可以使用 Formatter 将堆栈跟踪添加到日志记录消息中。
这是一个概念验证:
import logging
import traceback
import sys
logger = logging.getLogger("app.main")
class StacktraceLogFormatter(logging.Formatter):
def format(self, record: logging.LogRecord) -> str:
stack_lines = traceback.format_stack()
# we have the lines down to ^^^^^^ this call, but we don't want to show it, nor the internal logging ones
stack_lines_without_logging_intermediary_calls = filter(
lambda line: ("lib/logging/__init__.py" not in line)
and ("lib\logging\__init__.py") not in line,
stack_lines[:-1]
)
return record.msg + "\nOrigin :\n" + "".join(stack_lines_without_logging_intermediary_calls)
# beware of :
class InfoOrLessFilter(logging.Filter):
def filter(self, record: logging.LogRecord) -> bool:
return record.levelno <= logging.INFO
def do_some_logging():
logger.debug("debug message")
logger.info("info message")
logger.warning("warning message")
logger.error("error message")
try:
1/0
except ZeroDivisionError:
logger.exception("exception message")
logger.critical("critical message")
def setup_custom_logging():
logger.handlers = [] # remove the existing handlers from the logger
regular_handler_for_info_messages = logging.StreamHandler(sys.stdout)
regular_handler_for_info_messages.setLevel(logging.DEBUG) # at least DEBUG
regular_handler_for_info_messages.addFilter(InfoOrLessFilter()) # but not more than INFO
logger.addHandler(regular_handler_for_info_messages)
stacktrace_handler_for_important_messages = logging.StreamHandler(sys.stderr)
stacktrace_handler_for_important_messages.setLevel(logging.INFO + 1) # more than INFO
stacktrace_handler_for_important_messages.setFormatter(StacktraceLogFormatter())
logger.addHandler(stacktrace_handler_for_important_messages)
logger.propagate = False
def main():
logging.basicConfig(level=logging.DEBUG)
do_some_logging()
setup_custom_logging()
do_some_logging()
if __name__ == "__main__":
main()
它产生于:
debug message
info message
DEBUG:app.main:debug message
INFO:app.main:info message
WARNING:app.main:warning message
ERROR:app.main:error message
ERROR:app.main:exception message
Traceback (most recent call last):
File "C:/PycharmProjects/stack_overflow/67846424.py", line 43, in do_some_logging
1/0
ZeroDivisionError: division by zero
CRITICAL:app.main:critical message
及之后:
warning message
Origin :
File "C:/PycharmProjects/stack_overflow/67846424.py", line 73, in <module>
main()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 69, in main
do_some_logging()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 40, in do_some_logging
logger.warning("warning message")
error message
Origin :
File "C:/PycharmProjects/stack_overflow/67846424.py", line 73, in <module>
main()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 69, in main
do_some_logging()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 41, in do_some_logging
logger.error("error message")
exception message
Origin :
File "C:/PycharmProjects/stack_overflow/67846424.py", line 73, in <module>
main()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 69, in main
do_some_logging()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 45, in do_some_logging
logger.exception("exception message")
critical message
Origin :
File "C:/PycharmProjects/stack_overflow/67846424.py", line 73, in <module>
main()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 69, in main
do_some_logging()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 46, in do_some_logging
logger.critical("critical message")
我的代码库非常大,我们想打印所有日志的堆栈。
这包括所有级别的日志(甚至 INFO 和 DEBUG)。
这还包括异常发生之外的日志。
我学到的东西:
- 堆栈跟踪不会显示,除非你在一个例外中:当调用 logger.exception、set_exec=True 时,跟踪 back.print_exc()
- 我发现显示堆栈的唯一方法是 traceback.print_stack()
- 我现在希望我所有的日志都打印这个,但我不知道如何覆盖记录器。debug/info/warning/error 添加 traceback.print_stack()
- 这可以使用格式化程序吗?如果不是,是否可以在 logger.info() 方法发送到格式化程序之前覆盖它?
- 还有其他建议吗?
你走在正确的轨道上。我建议您阅读 logging HOWTO,它解释了很多事情。
您可以使用级别和过滤器来决定您的处理程序是否应该处理日志。并且您可以使用 Formatter 将堆栈跟踪添加到日志记录消息中。
这是一个概念验证:
import logging
import traceback
import sys
logger = logging.getLogger("app.main")
class StacktraceLogFormatter(logging.Formatter):
def format(self, record: logging.LogRecord) -> str:
stack_lines = traceback.format_stack()
# we have the lines down to ^^^^^^ this call, but we don't want to show it, nor the internal logging ones
stack_lines_without_logging_intermediary_calls = filter(
lambda line: ("lib/logging/__init__.py" not in line)
and ("lib\logging\__init__.py") not in line,
stack_lines[:-1]
)
return record.msg + "\nOrigin :\n" + "".join(stack_lines_without_logging_intermediary_calls)
# beware of :
class InfoOrLessFilter(logging.Filter):
def filter(self, record: logging.LogRecord) -> bool:
return record.levelno <= logging.INFO
def do_some_logging():
logger.debug("debug message")
logger.info("info message")
logger.warning("warning message")
logger.error("error message")
try:
1/0
except ZeroDivisionError:
logger.exception("exception message")
logger.critical("critical message")
def setup_custom_logging():
logger.handlers = [] # remove the existing handlers from the logger
regular_handler_for_info_messages = logging.StreamHandler(sys.stdout)
regular_handler_for_info_messages.setLevel(logging.DEBUG) # at least DEBUG
regular_handler_for_info_messages.addFilter(InfoOrLessFilter()) # but not more than INFO
logger.addHandler(regular_handler_for_info_messages)
stacktrace_handler_for_important_messages = logging.StreamHandler(sys.stderr)
stacktrace_handler_for_important_messages.setLevel(logging.INFO + 1) # more than INFO
stacktrace_handler_for_important_messages.setFormatter(StacktraceLogFormatter())
logger.addHandler(stacktrace_handler_for_important_messages)
logger.propagate = False
def main():
logging.basicConfig(level=logging.DEBUG)
do_some_logging()
setup_custom_logging()
do_some_logging()
if __name__ == "__main__":
main()
它产生于:
debug message
info message
DEBUG:app.main:debug message
INFO:app.main:info message
WARNING:app.main:warning message
ERROR:app.main:error message
ERROR:app.main:exception message
Traceback (most recent call last):
File "C:/PycharmProjects/stack_overflow/67846424.py", line 43, in do_some_logging
1/0
ZeroDivisionError: division by zero
CRITICAL:app.main:critical message
及之后:
warning message
Origin :
File "C:/PycharmProjects/stack_overflow/67846424.py", line 73, in <module>
main()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 69, in main
do_some_logging()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 40, in do_some_logging
logger.warning("warning message")
error message
Origin :
File "C:/PycharmProjects/stack_overflow/67846424.py", line 73, in <module>
main()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 69, in main
do_some_logging()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 41, in do_some_logging
logger.error("error message")
exception message
Origin :
File "C:/PycharmProjects/stack_overflow/67846424.py", line 73, in <module>
main()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 69, in main
do_some_logging()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 45, in do_some_logging
logger.exception("exception message")
critical message
Origin :
File "C:/PycharmProjects/stack_overflow/67846424.py", line 73, in <module>
main()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 69, in main
do_some_logging()
File "C:/PycharmProjects/stack_overflow/67846424.py", line 46, in do_some_logging
logger.critical("critical message")