로그¶
logging 모듈은 2.3 버전 이래로 파이썬의 표준 라이브러리였습니다. 이에 관해서는 PEP 282 을 보시면 간략히 써져 있습니다. 그 문서는 읽기 어렵기로 악명이 높지만, 그래도 basic logging tutorial 은 그나마 낫습니다.
대안으로, loguru 는 단순한 print 구문을 사용하는 것만큼이나 간단한 로깅 방법을 제공합니다.
로그를 남기는데에는 2가지 목적이 있습니다:
진단용 로그 는 어플리케이션의 동작과 관련된 이벤트를 기록합니다. 예를 들어 사용자가 오류 보고서를 남기면, 그 로그를 해당 에러와 관련된 상황을 확인하는데 쓸 수 있습니다.
감사용 로그 는 비지니스 분석에 필요한 이벤트를 기록합니다. 사용자가 무슨 동작을 했는지 알아낼 수 있으며, 다른 사용자와는 무슨 동작을 했는지도 상세하게 알 수 있습니다. 이를 통해 보고서를 작성하거나 업무적으로 최적화를 할 수 있습니다.
… Print는?¶
print 가 logging보다 좋은 경우는 커맨드라인 어플리케이션에서 help 구문을 화면에 보여줄 때 뿐입니다. logging이 print 보다 좋은 이유입니다:
log record 는 로그 남기는 이벤트가 발생할 때마다 만들어지는데, 여기에는 로그 남기는 이벤트의 파일명과 경로, 함수, 몇 행에서 문제가 발생했는지 등의 정보가 들어있어 문제를 확인하기에 편리합니다.
내장된 모듈에서 발생한 이벤트들도 로그가 남는데, 이 로그들은 루트 로그 기록기를 통하여 어플리케이션의 로그 스트림으로 보낼 수 있습니다. 필터링해서 걸러내지만 않는다면 말입니다.
logging.Logger.setLevel()메소드를 쓰면 로그를 선택적으로 남길 수 있습니다.logging.Logger.disabled속성을True로 설정하면 로그를 끌 수도 있습니다.
라이브러리에서의 로그 남기기¶
라이브러리에 로그 설정 하려면 로그 남기기 튜토리얼 을 보시면 됩니다. 로그를 남기는 이벤트가 발생하면 그게 무슨 일인지 알아내야 하는 건 라이브러리가 아니라 사용자 입니다. 따라서 반복적으로 경보를 보내야합니다.
참고
당신의 라이브러리에 NullHandler 이외의 다른 로그 남기는 핸들러를 넣지 말 것을 강력 추천합니다.
라이브러리에서 로그 기록기를 인스턴스화 하는 유일한 방법은 __name__ 전역 변수를 사용해서 만드는 방법 뿐입니다. logging 모듈은 . 을 사용해서 로그 기록기의 계층 구조를 만들기 때문에 __name__ 을 사용해야 충돌을 막을 수 있습니다.
requests의 소스 에서 가져온 훌륭한 예시를 보여드리겠습니다. 이걸 당신의 __init__.py 에 두시면 됩니다.
import logging
logging.getLogger(__name__).addHandler(logging.NullHandler())
어플리케이션에서의 로그 남기기¶
멋진 앱을 만들기 위한 12가지 는 어플리케이션 개발을 위한 좋은 습관을 들이기에 참고할만 합니다. 로그를 남기는 방법 에 관한 섹션도 있는데, 여기서는 로그 이벤트를 이벤트 스트림으로 취급하여 어플리케이션 환경이 처리할 수 있도록 표준 출력으로 보낼 것을 강력하게 추천합니다.
로그를 설정하는데에는 적어도 3가지 방식이 있습니다:
- INI 포맷의 파일을 사용하는 방법:
장점:
logging.config.listen()함수로 소켓을 리스닝하여 어플리케이션 실행 중에도 설정을 갱신할 수 있습니다.단점: 코드로 로거를 설정할 때보다 제어할 수 있는 범위가 적습니다(예: 직접 서브클래스로 만든 필터나 로거).
- 딕셔너리나 JSON 포맷 파일을 사용하는 방법:
이렇게 하자: 어플리케이션 실행 중에도 업데이트를 할 수 있을 뿐만 아니라, 파이썬 2.6부터는 표준 라이브러리에서
json모듈을 사용하여 파일에서 설정을 불러올 수도 있다.이렇게 하지 마세요: 코드에 로그를 설정할 때 할 수 있는 설정도 하지 않는다
- 코드를 사용하는 방법:
이렇게 하자: 모든 설정을 완벽하게 한다.
단점: 수정하려면 소스코드를 변경해야 합니다.
INI 파일로 설정하는 예시¶
파일명은 logging_config.ini 로 합시다. 파일 포맷에 대한 자세한 설명은 로그 튜토리얼 의 로그 설정 을 보시면 됩니다.
[loggers]
keys=root
[handlers]
keys=stream_handler
[formatters]
keys=formatter
[logger_root]
level=DEBUG
handlers=stream_handler
[handler_stream_handler]
class=StreamHandler
level=DEBUG
formatter=formatter
args=(sys.stderr,)
[formatter_formatter]
format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s
그런 다음 코드에 logging.config.fileConfig() 를 쓰세요.
import logging
from logging.config import fileConfig
fileConfig('logging_config.ini')
logger = logging.getLogger()
logger.debug('often makes a very good meal of %s', 'visiting tourists')
딕셔너리로 설정하는 예시¶
파이썬 2.7부터는 딕셔너리를 사용해서 상세한 설정을 할 수 있습니다. PEP 391 을 보시면 설정 딕셔너리에 반드시 넣어야 하는 요소와 그렇지 않은 요소를 확인할 수 있습니다.
import logging
from logging.config import dictConfig
logging_config = dict(
version = 1,
formatters = {
'f': {'format':
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s'}
},
handlers = {
'h': {'class': 'logging.StreamHandler',
'formatter': 'f',
'level': logging.DEBUG}
},
root = {
'handlers': ['h'],
'level': logging.DEBUG,
},
)
dictConfig(logging_config)
logger = logging.getLogger()
logger.debug('often makes a very good meal of %s', 'visiting tourists')
코드에 바로 설정하는 예시¶
import logging
logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
logger.debug('often makes a very good meal of %s', 'visiting tourists')
