source

디버깅 정보를 사용하여 Python 오류를 기록하려면 어떻게 해야 합니까?

bestscript 2022. 12. 24. 20:37

디버깅 정보를 사용하여 Python 오류를 기록하려면 어떻게 해야 합니까?

예외 를 Python 로그 .logging.error:

import logging
try:
    1/0
except ZeroDivisionError as e:
    logging.error(e)  # ERROR:root:division by zero

예외 문자열뿐만 아니라 예외 및 예외 생성 코드에 대한 자세한 정보를 인쇄할 수 있습니까?회선번호나 스택트레이스 같은 게 좋을 것 같아요

logger.exception 는 오류 메시지와 함께 스택트레이스를 출력합니다

예를 들어 다음과 같습니다.

import logging
try:
    1/0
except ZeroDivisionError:
    logging.exception("message")

출력:

ERROR:root:message
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: integer division or modulo by zero

@Paulo Check는 다음과 같이 말합니다. "Python 3에서는logging.exception except이 메서드를 임의의 장소에서 호출하면 이상한 예외가 발생할 수 있습니다.의사들도 이에 대해 경고하고 있습니다."

「」를 사용합니다.exc_info레벨을 할 수 (「이러면」을 사용하고 있는 ).exception , 에 있을 입니다.error★★★★★

try:
    # do something here
except Exception as e:
    logging.critical(e, exc_info=True)  # log exception info at CRITICAL log level

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★의 장점logging.exceptionSiggyF의 답변에는 표시되지 않는 것은 임의의 메시지를 전달할 수 있다는 것입니다.또, 로그에는, 예외의 상세를 포함한 완전한 트레이스 백이 표시됩니다.

import logging
try:
    1/0
except ZeroDivisionError:
    logging.exception("Deliberate divide by zero traceback")

버전에서는, 만을 「」( 「」), 「」( 「」), 「」( 「」)로 합니다.sys.stderr 되어

>>> import logging
>>> try:
...     1/0
... except ZeroDivisionError:
...     logging.exception("Deliberate divide by zero traceback")
... 
ERROR:root:Deliberate divide by zero traceback
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: integer division or modulo by zero

견적

이 다른 있는 하지 않는 )는 어떻게 해야 합니까?logging모??

그럼 이제 ㅇㅇㅇㄹㄹㄹㄹ,traceback여기서 사용할 수 있습니다.

import traceback

def log_traceback(ex, ex_traceback=None):
    if ex_traceback is None:
        ex_traceback = ex.__traceback__
    tb_lines = [ line.rstrip('\n') for line in
                 traceback.format_exception(ex.__class__, ex, ex_traceback)]
    exception_logger.log(tb_lines)
  • Python 2에서 사용:

    try:
        # your function call is here
    except Exception as ex:
        _, _, ex_traceback = sys.exc_info()
        log_traceback(ex, ex_traceback)
    
  • Python 3에서 사용:

    try:
        x = get_number()
    except Exception as ex:
        log_traceback(ex)
    

스택 트레이스는 예외 없이 로그에 기록할 수 있습니다.

https://docs.python.org/3/library/logging.html#logging.Logger.debug

두 번째 옵션의 키워드 인수는 stack_info 입니다.기본값은 False 입니다.true일 경우 실제 로깅콜을 포함한 스택 정보가 로깅메시지에 추가됩니다.이는 exc_info를 지정함으로써 표시되는 스택 정보와 동일하지 않습니다.전자는 스택의 하단에서 현재 스레드의 로깅콜까지의 스택프레임입니다.후자는 예외 핸들러 검색 중 예외 후에 언로드된 스택프레임에 대한 정보입니다.

예:

>>> import logging
>>> logging.basicConfig(level=logging.DEBUG)
>>> logging.getLogger().info('This prints the stack', stack_info=True)
INFO:root:This prints the stack
Stack (most recent call last):
  File "<stdin>", line 1, in <module>
>>>

로그를 - 는 이 해야 합니다. - 로그 레코드는 이 규칙에 부합합니다.one record = one line 이 사용하시면 .grep이치노

하지만 트레이스백 정보는 여러 줄입니다.이 스레드에서 위의 zangw가 제안한 솔루션의 확장 버전입니다.문제는 트레이스백 회선이\n안에서는 이 을 없애기 합니다.

import logging


logger = logging.getLogger('your_logger_here')

def log_app_error(e: BaseException, level=logging.ERROR) -> None:
    e_traceback = traceback.format_exception(e.__class__, e, e.__traceback__)
    traceback_lines = []
    for line in [line.rstrip('\n') for line in e_traceback]:
        traceback_lines.extend(line.splitlines())
    logger.log(level, traceback_lines.__str__())

그런 다음(로그를 분석할 때) 로그 파일에서 필요한 트레이스백 행을 복사/붙여넣고 다음을 수행할 수 있습니다.

ex_traceback = ['line 1', 'line 2', ...]
for line in ex_traceback:
    print(line)

이익!

이 답변은 위의 우수한 답변으로 구성됩니다.

대부분의 응용 프로그램에서 logging.exception(e)을 직접 호출하지 않습니다.대부분의 경우 응용 프로그램 또는 모듈에 고유한 커스텀로거를 다음과 같이 정의하고 있습니다.

# Set the name of the app or module
my_logger = logging.getLogger('NEM Sequencer')
# Set the log level
my_logger.setLevel(logging.INFO)

# Let's say we want to be fancy and log to a graylog2 log server
graylog_handler = graypy.GELFHandler('some_server_ip', 12201)
graylog_handler.setLevel(logging.INFO)
my_logger.addHandler(graylog_handler)

이 경우 로거를 사용하여 다음과 같이 예외(e)를 호출합니다.

try:
    1/0
except ZeroDivisionError, e:
    my_logger.exception(e)

했을 때 'debugging information'은 'debugging information'입니다.logging.exception(...)트레이스백 자동으로 합니다.따라서 트레이스백 행과 함께 모든 변수 값을 자동으로 기록하는 도구가 필요합니다.

개봉 후 다음과 같은 로그를 얻을 수 있습니다.

2020-03-30 18:24:31 main ERROR   File "./temp.py", line 13, in get_ratio
2020-03-30 18:24:31 main ERROR     return height / width
2020-03-30 18:24:31 main ERROR       height = 300
2020-03-30 18:24:31 main ERROR       width = 0
2020-03-30 18:24:31 main ERROR builtins.ZeroDivisionError: division by zero

몇 가지 Pypi 도구를 보면 다음과 같은 이름을 붙일 수 있습니다.

그 중 일부는 당신에게 크래시 메시지를 준다.

하지만 당신은 pypi에서 더 찾을 수 있을 것이다.

약간의 데코레이터 트리트먼트(Maybe monad와 리프팅에서 매우 느슨하게 영감을 받았습니다.Python 3.6 유형의 주석을 안전하게 제거하고 이전 메시지 형식 스타일을 사용할 수 있습니다.

틀리기 쉽다.화이

from functools import wraps
from typing import Callable, TypeVar, Optional
import logging


A = TypeVar('A')


def fallible(*exceptions, logger=None) \
        -> Callable[[Callable[..., A]], Callable[..., Optional[A]]]:
    """
    :param exceptions: a list of exceptions to catch
    :param logger: pass a custom logger; None means the default logger, 
                   False disables logging altogether.
    """
    def fwrap(f: Callable[..., A]) -> Callable[..., Optional[A]]:

        @wraps(f)
        def wrapped(*args, **kwargs):
            try:
                return f(*args, **kwargs)
            except exceptions:
                message = f'called {f} with *args={args} and **kwargs={kwargs}'
                if logger:
                    logger.exception(message)
                if logger is None:
                    logging.exception(message)
                return None

        return wrapped

    return fwrap

데모:

In [1] from fallible import fallible

In [2]: @fallible(ArithmeticError)
    ...: def div(a, b):
    ...:     return a / b
    ...: 
    ...: 

In [3]: div(1, 2)
Out[3]: 0.5

In [4]: res = div(1, 0)
ERROR:root:called <function div at 0x10d3c6ae8> with *args=(1, 0) and **kwargs={}
Traceback (most recent call last):
  File "/Users/user/fallible.py", line 17, in wrapped
    return f(*args, **kwargs)
  File "<ipython-input-17-e056bd886b5c>", line 3, in div
    return a / b

In [5]: repr(res)
'None'

이 솔루션을 도 있습니다.None except 이 을 part(일부)로 도 있습니다).fallible의인인)

로깅 모듈(커스텀모듈의 경우)에서 stack_info를 활성화하기만 하면 됩니다.

api_logger.exceptionLog("*Input your Custom error message*",stack_info=True)

이 코드 예제를 보면 (파이썬 2와 3에서 동작하는)가 추출할 수 있는 함수의 정의를 아래에 볼 수 있습니다.

  • 방법
  • 회선 번호
  • 코드 콘텍스트
  • 파일 경로

예외 유무에 관계없이 스택트레이스 전체에 대해 다음과 같이 설정합니다.

def sentry_friendly_trace(get_last_exception=True):
    try:
        current_call = list(map(frame_trans, traceback.extract_stack()))
        alert_frame = current_call[-4]
        before_call = current_call[:-4]

        err_type, err, tb = sys.exc_info() if get_last_exception else (None, None, None)
        after_call = [alert_frame] if err_type is None else extract_all_sentry_frames_from_exception(tb)

        return before_call + after_call, err, alert_frame
    except:
        return None, None, None

물론 이 함수는 위에 링크된 전체 요지에 의존하며, 특히extract_all_sentry_frames_from_exception() ★★★★★★★★★★★★★★★★★」frame_trans()예외 정보 추출의 합계는 약 60줄 미만입니다.

도움이 됐으면 좋겠네요!

저의 접근 방식은 컨텍스트 매니저를 생성하여 예외를 기록하고 발생시키는 것이었습니다.

import logging
from contextlib import AbstractContextManager


class LogError(AbstractContextManager):

    def __init__(self, logger=None):
        self.logger = logger.name if isinstance(logger, logging.Logger) else logger

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_value is not None:
            logging.getLogger(self.logger).exception(exc_value)


with LogError():
    1/0

를 로거 으로 전달할 수 .LogError()로거를 합니다(「이러한 로거」를Nonelogging.getLogger)를 선택합니다.에러를 발생시키기 위한 스위치를 추가하거나 로깅만 할 수도 있습니다.

커스텀 디자인 로거를 중심으로 모든 기능을 정리합니다.

import json
import timeit
import traceback
import sys
import unidecode

def main_writer(f,argument):
  try:
    f.write(str(argument))
  except UnicodeEncodeError:
    f.write(unidecode.unidecode(argument))


def logger(*argv,logfile="log.txt",singleLine = False):
  """
  Writes Logs to LogFile
  """
  with open(logfile, 'a+') as f:
    for arg in argv:
      if arg == "{}":
        continue
      if type(arg) == dict and len(arg)!=0:
        json_object = json.dumps(arg, indent=4, default=str)
        f.write(str(json_object))
        f.flush()
        """
        for key,val in arg.items():
          f.write(str(key) + " : "+ str(val))
          f.flush()
        """
      elif type(arg) == list and len(arg)!=0:
        for each in arg:
          main_writer(f,each)
          f.write("\n")
          f.flush()
      else:
        main_writer(f,arg)
        f.flush()
      if singleLine==False:
        f.write("\n")
    if singleLine==True:
      f.write("\n")

def tryFunc(func, func_name=None, *args, **kwargs):
  """
  Time for Successfull Runs
  Exception Traceback for Unsuccessful Runs
  """
  stack = traceback.extract_stack()
  filename, codeline, funcName, text = stack[-2]
  func_name = func.__name__ if func_name is None else func_name # sys._getframe().f_code.co_name # func.__name__
  start = timeit.default_timer()
  x = None
  try:
    x = func(*args, **kwargs)
    stop = timeit.default_timer()
    # logger("Time to Run {} : {}".format(func_name, stop - start))
  except Exception as e:
    logger("Exception Occurred for {} :".format(func_name))
    logger("Basic Error Info :",e)
    logger("Full Error TraceBack :")
    # logger(e.message, e.args)
    logger(traceback.format_exc())
  return x

def bad_func():
  return 'a'+ 7

if __name__ == '__main__':
    logger(234)
    logger([1,2,3])
    logger(['a','b','c'])
    logger({'a':7,'b':8,'c':9})
    tryFunc(bad_func)

추가 의존성에 대처할 수 있다면 twisted.log를 사용하여 명시적으로 오류를 기록할 필요가 없으며 전체 트레이스 백과 시간을 파일 또는 스트림으로 되돌립니다.

깔끔한 방법은format_exc()출력을 해석하여 관련 부품을 가져옵니다.

from traceback import format_exc

try:
    1/0
except Exception:
    print 'the relevant part is: '+format_exc().split('\n')[-2]

안부 전해요

언급URL : https://stackoverflow.com/questions/5191830/how-do-i-log-a-python-error-with-debug-information