디버깅 정보를 사용하여 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
'source' 카테고리의 다른 글
| 이 Unbound Local Error가 발생하는(닫힘) 이유는 무엇입니까? (0) | 2022.12.24 |
|---|---|
| 브라우저 창에서 현재 탭을 닫으려면 어떻게 해야 합니까? (0) | 2022.12.24 |
| PHP foreach 루프 키 값 (0) | 2022.12.24 |
| 행을 복사하고 MySQL에서 자동 증분 필드와 동일한 테이블에 삽입하려면 어떻게 해야 합니까? (0) | 2022.12.24 |
| 두 표의 점수를 비교하여 가장 최근의 점수가 다른 부분을 보여줍니다. (0) | 2022.12.24 |