your programing

프로그램을 중단하지 않고 전체 트레이스 백을 인쇄하는 방법은 무엇입니까?

lovepro 2020. 9. 30. 11:11
반응형

프로그램을 중단하지 않고 전체 트레이스 백을 인쇄하는 방법은 무엇입니까?


저는 10 개의 웹 사이트를 구문 분석하고, 데이터 파일을 찾고, 파일을 저장 한 다음이를 구문 분석하여 NumPy 라이브러리에서 쉽게 사용할 수있는 데이터를 만드는 프로그램을 작성하고 있습니다. 있다 이 파일 만남 내가 분류 아직했습니다 잘못된 링크, 제대로 형성된 XML, 누락 된 항목 및 기타 물건을 통해 오류가. 처음에는 다음과 같은 오류를 처리하기 위해이 프로그램을 만들었습니다.

try:
    do_stuff()
except:
    pass

하지만 이제는 오류를 기록하고 싶습니다.

try:
    do_stuff()
except Exception, err:
    print Exception, err

나중에 검토 할 수 있도록 로그 파일에 인쇄됩니다. 이것은 일반적으로 매우 쓸모없는 데이터를 인쇄합니다. 내가 원하는 것은 예외를 가로 채는 try-except없이 오류가 트리거 될 때 인쇄 된 똑같은 줄을 인쇄하는 것입니다.하지만 프로그램이 일련의 for 루프에 중첩되어 있기 때문에 프로그램을 중단하고 싶지 않습니다. 완료를 참조하십시오.


다른 답변은 이미 traceback 모듈을 지적했습니다 .

를 사용 print_exc하면 일부 코너의 경우 기대 한 것을 얻지 못할 수 있습니다. Python 2.x에서 :

import traceback

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_exc()

... 마지막 예외 의 역 추적을 표시합니다 .

Traceback (most recent call last):
  File "e.py", line 7, in <module>
    raise TypeError("Again !?!")
TypeError: Again !?!

원래 트레이스 백에 실제로 액세스해야하는 경우 한 가지 해결책은 로컬 변수에서 반환 된 예외 정보 를 캐시하고 exc_info다음을 사용하여 표시하는 것입니다 print_exception.

import traceback
import sys

try:
    raise TypeError("Oups!")
except Exception, err:
    try:
        exc_info = sys.exc_info()

        # do you usefull stuff here
        # (potentially raising an exception)
        try:
            raise TypeError("Again !?!")
        except:
            pass
        # end of useful stuff


    finally:
        # Display the *original* exception
        traceback.print_exception(*exc_info)
        del exc_info

생산 :

Traceback (most recent call last):
  File "t.py", line 6, in <module>
    raise TypeError("Oups!")
TypeError: Oups!

그래도 몇 가지 함정이 있습니다.

  • 의 문서에서 sys_info:

    예외를 처리하는 함수의 지역 변수에 역 추적 반환 값을 할당하면 순환 참조 가 발생합니다 . 이렇게하면 동일한 함수의 로컬 변수 또는 트레이스 백이 참조하는 항목이 가비지 수집되는 것을 방지 할 수 있습니다. [...] 트레이스 백이 필요한 경우 사용 후 삭제해야합니다 (try ... finally 문을 사용하는 것이 가장 좋습니다).

  • 그러나 동일한 문서에서 :

    Python 2.2부터 이러한주기는 가비지 수집이 활성화되고 도달 할 수 없게되면 자동으로 회수 되지만주기 생성을 피하는 것이 더 효율적입니다.


반면에 예외 와 관련된 트레이스 백에 액세스 할 수 있도록 허용함으로써 Python 3는 덜 놀라운 결과를 생성합니다.

import traceback

try:
    raise TypeError("Oups!")
except Exception as err:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_tb(err.__traceback__)

... 표시됩니다 :

  File "e3.py", line 4, in <module>
    raise TypeError("Oups!")

traceback.format_exc()또는 sys.exc_info()원하는 경우 더 많은 정보를 얻을 수 있습니다.

import traceback
import sys

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    # or
    print(sys.exc_info()[2])

디버깅 중이고 현재 스택 추적 만보고 싶다면 다음을 호출하면됩니다.

traceback.print_stack()

다시 잡기 위해 수동으로 예외를 발생시킬 필요가 없습니다.


프로그램을 중단하지 않고 전체 트레이스 백을 인쇄하는 방법은 무엇입니까?

오류로 인해 프로그램을 중지하지 않으려면 try / except로 해당 오류를 처리해야합니다.

try:
    do_something_that_might_error()
except Exception as error:
    handle_the_error(error)

전체 트레이스 백을 추출하기 위해 traceback표준 라이브러리 모듈을 사용합니다 .

import traceback

그리고 우리가 전체 스택 트레이스를 얻었음을 보여주기 위해 상당히 복잡한 스택 트레이스를 생성하려면 :

def raise_error():
    raise RuntimeError('something bad happened!')

def do_something_that_might_error():
    raise_error()

인쇄

전체 역 추적 인쇄 하려면 다음 traceback.print_exc방법을 사용하십시오 .

try:
    do_something_that_might_error()
except Exception as error:
    traceback.print_exc()

어떤 인쇄 :

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

인쇄, 로깅보다 낫습니다.

그러나 모범 사례는 모듈에 대해 로거를 설정하는 것입니다. 모듈의 이름을 알고 레벨을 변경할 수 있습니다 (처리기와 같은 다른 속성 중에서).

import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

어떤 경우에는 logger.exception대신 함수를 원할 것입니다.

try:
    do_something_that_might_error()
except Exception as error:
    logger.exception(error)

어떤 로그 :

ERROR:__main__:something bad happened!
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

또는 문자열을 원할 수도 있습니다.이 경우 traceback.format_exc대신 함수를 원할 것입니다.

try:
    do_something_that_might_error()
except Exception as error:
    logger.debug(traceback.format_exc())

어떤 로그 :

DEBUG:__main__:Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

결론

세 가지 옵션 모두에 대해 오류가 발생했을 때와 동일한 결과를 얻습니다.

>>> do_something_that_might_error()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in do_something_that_might_error
  File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!

첫째, print로깅에 s를 사용하지 마십시오.이를 수행하기 위해 안정적이고 입증되었으며 잘 고려 된 stdlib 모듈이 logging있습니다.. 당신은 확실히 해야한다 대신 사용.

둘째, 기본적이고 간단한 접근 방식이있을 때 관련없는 도구를 엉망 으로 만들고 싶은 유혹을받지 마십시오 . 여기있어:

log = logging.getLogger(__name__)

try:
    call_code_that_fails()
except MyError:
    log.exception('Any extra info you want to see in your logs')

그게 다야. 이제 끝났습니다.

내부 작업 방식에 관심이있는 모든 사람을위한 설명

무엇 log.exception실제로하는 일은 그냥 전화입니다 log.error(즉, 레벨 이벤트 로그 ERROR) 다음 역 추적 인쇄 할 수 있습니다.

왜 더 낫습니까?

다음은 몇 가지 고려 사항입니다.

  • 그것은 옳다 ;
  • 간단합니다.
  • 간단하다.

왜 아무도 traceback로거를 사용 하거나 호출 exc_info=True하거나 손을 더럽 히지 않아야 sys.exc_info합니까?

글쎄, 왜냐하면! 그들은 모두 다른 목적으로 존재합니다. 예를 들어 traceback.print_exc의 출력은 인터프리터 자체가 생성 한 역 추적과 약간 다릅니다. 당신이 그것을 사용하면, 당신은 당신의 로그를 읽는 사람을 혼란스럽게 할 것이고, 그들은 그들에게 머리를 부딪 히게 될 것입니다.

exc_info=True통화 기록에 전달 하는 것은 부적절합니다. 그러나 복구 가능한 오류를 포착 할 때 유용 하며 한 수준의 로그 만 생성 INFO하기 때문에 ( 예 : 수준 사용) 트레이스 백을 사용하여 기록하려는 경우에도 유용합니다 .log.exceptionERROR

그리고 당신은 확실히 sys.exc_info당신이 할 수 있는 한 많이 엉망이 되는 것을 피해야 합니다. 그것은 단지 공용 인터페이스가 아니라 내부 인터페이스 입니다. 당신이 무엇을하고 있는지 확실히 알고 있다면 그것을 사용할 있습니다. 예외를 인쇄하기위한 것이 아닙니다.


@Aaron Hall의 답변 외에도 로깅 중이지만 사용하지 않으려는 경우 logging.exception()(오류 수준에서 로깅하므로) 더 낮은 수준을 사용하고 통과 할 수 있습니다 exc_info=True. 예 :

try:
    do_something_that_might_error()
except Exception:
    logger.info('General exception noted.', exc_info=True)

얻으려면 정확한 스택 추적을 문자열로, 그 위에 단계가이었다 제외하고는 어떤 시도는 /, 단순히 블록이 캐치를 일으키는 예외를 제외하고는이를 배치하지 않는 경우 제기되고있다.

desired_trace = traceback.format_exc(sys.exc_info())

사용 방법은 다음과 같습니다 ( flaky_func정의 된 것으로 가정 하고 log선호하는 로깅 시스템을 호출합니다).

import traceback
import sys

try:
    flaky_func()
except KeyboardInterrupt:
    raise
except Exception:
    desired_trace = traceback.format_exc(sys.exc_info())
    log(desired_trace)

KeyboardInterruptCtrl-C를 사용하여 프로그램을 계속 죽일 수 있도록 s 를 잡아서 다시 올리는 것이 좋습니다 . 로깅은 질문의 범위를 벗어나지 만 좋은 옵션은 logging 입니다. systraceback 모듈에 대한 문서입니다 .


오류가 발생할 수있는 가장 내부 루프 내부에 try / except를 넣어야합니다.

for i in something:
    for j in somethingelse:
        for k in whatever:
            try:
                something_complex(i, j, k)
            except Exception, e:
                print e
        try:
            something_less_complex(i, j)
        except Exception, e:
            print e

... 등등

In other words, you will need to wrap statements that may fail in try/except as specific as possible, in the most inner-loop as possible.


A remark about this answer's comments: print(traceback.format_exc()) does a better job for me than traceback.print_exc(). With the latter, the hello is sometimes strangely "mixed" with the traceback text, like if both want to write to stdout or stderr at the same time, producing weird output (at least when building from inside a text editor and viewing the output in the "Build results" panel).

Traceback (most recent call last):
File "C:\Users\User\Desktop\test.py", line 7, in
hell do_stuff()
File "C:\Users\User\Desktop\test.py", line 4, in do_stuff
1/0
ZeroDivisionError: integer division or modulo by zero
o
[Finished in 0.1s]

So I use:

import traceback, sys

def do_stuff():
    1/0

try:
    do_stuff()
except Exception:
    print(traceback.format_exc())
    print('hello')

I don't see this mentioned in any of the other answers. If you're passing around an Exception object for whatever reason...

In Python 3.5+ you can get a trace from an Exception object using traceback.TracebackException.from_exception(). For example:

import traceback


def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')


def stack_lvl_2():
    try:
        stack_lvl_3()
    except Exception as e:
        # raise
        return e


def stack_lvl_1():
    e = stack_lvl_2()
    return e

e = stack_lvl_1()

tb1 = traceback.TracebackException.from_exception(e)
print(''.join(tb1.format()))

However, the above code results in:

Traceback (most recent call last):
  File "exc.py", line 10, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')
Exception: ('a1', 'b2', 'c3')

This is just two levels of the stack, as opposed to what would have been printed on screen had the exception been raised in stack_lvl_2() and not intercepted (uncomment the # raise line).

As I understand it, that's because an exception records only the current level of the stack when it is raised, stack_lvl_3() in this case. As it's passed back up through the stack, more levels are being added to its __traceback__. But we intercepted it in stack_lvl_2(), meaning all it got to record was levels 3 and 2. To get the full trace as printed on stdout we'd have to catch it at the highest (lowest?) level:

import traceback


def stack_lvl_3():
    raise Exception('a1', 'b2', 'c3')


def stack_lvl_2():
    stack_lvl_3()


def stack_lvl_1():
    stack_lvl_2()


try:
    stack_lvl_1()
except Exception as exc:
    tb = traceback.TracebackException.from_exception(exc)

print('Handled at stack lvl 0')
print(''.join(tb.stack.format()))

Which results in:

Handled at stack lvl 0
  File "exc.py", line 17, in <module>
    stack_lvl_1()
  File "exc.py", line 13, in stack_lvl_1
    stack_lvl_2()
  File "exc.py", line 9, in stack_lvl_2
    stack_lvl_3()
  File "exc.py", line 5, in stack_lvl_3
    raise Exception('a1', 'b2', 'c3')

Notice that the stack print is different, the first and last lines are missing. Because it's a different format().

Intercepting the exception as far away from the point where it was raised as possible makes for simpler code while also giving more information.


You want the traceback module. It will let you print stack dumps like Python normally does. In particular, the print_last function will print the last exception and a stack trace.


Get the full traceback as a string from the exception object with traceback.format_exception

If you only have the exception object, you can get the traceback as a string from any point of the code in Python 3 with:

import traceback

''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))

Full example:

#!/usr/bin/env python3

import traceback

def f():
    g()

def g():
    raise Exception('asdf')

try:
    g()
except Exception as e:
    exc = e

tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)

Output:

Traceback (most recent call last):
  File "./main.py", line 12, in <module>
    g()
  File "./main.py", line 9, in g
    raise Exception('asdf')
Exception: asdf

Documentation: https://docs.python.org/3.7/library/traceback.html#traceback.format_exception

See also: Extract traceback info from an exception object

Tested in Python 3.7.3.

참고URL : https://stackoverflow.com/questions/3702675/how-to-print-the-full-traceback-without-halting-the-program

반응형