로깅 구성 및 사용 방법¶
더 보기
Django는 쉽게 확장할 수 있는 :ref:`기본 로깅 구성 <default-logging-configuration>`을 제공합니다.
기본 로깅 호출하기¶
코드 내에서 로그 메시지를 보내려면 로깅 호출을 입력합니다.
``settings.py``에서 로깅 호출을 사용하고 싶은 유혹에 빠지지 마십시오.
Django 로깅을 setup() 함수의 일부로 구성하면 ``settings.py``에 있는 로깅 호출이 예상대로 작동하지 않을 수 있습니다. 왜냐하면 로깅이 그 시점에서 설정되지 않기 때문입니다. 로깅을 탐색하려면 아래 예에서 제안된 뷰 함수를 사용하십시오.
First, import the Python logging library, and then obtain a logger instance
with logging.getLogger(). Provide the getLogger() method with a
name to identify it and the records it emits. A good option is to use
__name__ (see 로거 네임스페이싱 사용 below for more on this) which will
provide the name of the current Python module as a dotted path:
import logging
logger = logging.getLogger(__name__)
모듈 수준에서 이 선언을 수행하는 것이 좋습니다.
그런 다음 함수 안(예: 뷰 안)에서 로거에 레코드를 보냅니다:
def some_view(request):
...
if some_risky_state:
logger.warning("Platform is running at risk")
When this code is executed, a LogRecord containing that
message will be sent to the logger. If you’re using Django’s default logging
configuration, the message will appear in the console.
위의 예에서 사용된 WARNING 수준은 여러 로깅 심각도 수준들 <topic-logging-parts-loggers>`중 하나입니다: ``DEBUG`, INFO, WARNING, ERROR, CRITICAL. 따라서 다른 예는 다음과 같습니다:
logger.critical("Payment system is not responding")
중요
``WARNING``보다 낮은 수준의 레코드는 기본적으로 콘솔에 나타나지 않습니다. 이 동작을 변경하려면 추가 구성이 필요합니다.
로깅 구성 사용자 정의¶
Django의 로깅 구성은 별 다른 구성 없이도 작동하지만, 몇 가지 추가 구성을 통해 로그가 다양한 대상(로그 파일, 외부 서비스, 이메일 등)으로 전송되는 방식을 정확하게 제어할 수 있습니다.
다음을 설정할 수 있습니다:
어떤 레코드를 어떤 핸들러로 보낼지 결정하는 로거 매핑
받은 레코드로 무엇을 할지 결정하는 핸들러
레코드 전송에 대한 추가 제어를 제공하고 레코드를 바로 수정할 수 있는 필터
LogRecord객체를 사람이나 다른 시스템에서 사용할 문자열이나 다른 형식으로 변환하는 포맷터
로깅 구성에는 다양한 방법들이 있습니다. Django에서는 LOGGING 구성이 가장 일반적으로 사용됩니다. 이 구성은 :ref:`dictConfig 형식 <logging-config-dictschema>`을 사용하고 :ref:`기본 로깅 구성 <default-logging-definition>`을 확장합니다.
사용자 지정 설정이 Django의 기본값과 병합되는 방법에 대한 설명은 :ref:`configuring-logging`을 참조하세요.
로깅을 구성하는 다른 방법에 대한 자세한 내용은 mod:Python 로깅 문서 <python:logging.config>`를 참조하세요. 단순화를 위해 이 문서에서는 ``LOGGING` 설정을 통한 구성만 고려합니다.
기본 로깅 구성¶
로깅을 구성할 때, 다음을 수행하는 것이 좋습니다:
LOGGING 사전 생성¶
``settings.py``에서:
LOGGING = {
"version": 1, # the dictConfig format version
"disable_existing_loggers": False, # retain the default loggers
}
``disable_existing_loggers``를 ``False``로 설정하여 기본 로깅 구성을 유지하고 확장하는 것이 거의 항상 좋습니다.
핸들러 구성¶
이 예제는 Python의 FileHandler`를 사용하여 ``DEBUG` 이상의 로그를 (프로젝트 루트에 있는) general.log 파일에 저장하는 ``file``이라는 단일 핸들러를 구성합니다:
LOGGING = {
# ...
"handlers": {
"file": {
"class": "logging.FileHandler",
"filename": "general.log",
},
},
}
Different handler classes take different configuration options. For more
information on available handler classes, see the
AdminEmailHandler provided by Django and the various
handler classes provided by Python.
로깅 수준은 핸들러에서도 설정할 수 있습니다(기본적으로 모든 수준의 로그 메시지를 수락함). 위의 예를 사용하여 다음을 추가합니다:
{
"class": "logging.FileHandler",
"filename": "general.log",
"level": "DEBUG",
}
DEBUG 수준 이상의 레코드만 허용하는 핸들러 구성을 정의합니다.
로거 매핑 설정¶
이 핸들러로 레코드를 보내려면, 로거 매핑을 구성합니다. 예를 들면 다음과 같습니다:
LOGGING = {
# ...
"loggers": {
"": {
"level": "DEBUG",
"handlers": ["file"],
},
},
}
매핑의 이름은 처리할 로그 레코드를 결정합니다. 이 구성('')은 unnamed*입니다. 즉, *모든 로거의 레코드를 처리한다는 의미입니다(레코드를 처리할 로거를 결정하기 위해 매핑 이름을 사용하는 방법은 아래의 로거 네임스페이싱 사용 참조).
DEBUG 수준 이상의 메시지를 ``file``이라는 핸들러로 전달합니다.
로거는 여러 핸들러에 메시지를 전달할 수 있으므로, 로거와 핸들러 간의 관계는 many-to-many입니다.
만약 다음을 실행하는 경우:
logger.debug("Attempting to connect to API")
코드에서 프로젝트 루트의 general.log 파일에서 해당 메시지를 찾을 수 있습니다.
포맷터 구성¶
기본적으로 최종 로그 출력에는 각 로그 레코드 <logging.LogRecord>`의 메시지 부분이 포함됩니다. 추가 데이터를 포함하려면 포맷터를 사용하십시오. 먼저 이름을 지정하고 포맷터를 정의합니다. 이 예에서는 verbose 및 ``simple``이라는 포맷터를 정의합니다:
LOGGING = {
# ...
"formatters": {
"verbose": {
"format": "{name} {levelname} {asctime} {module} {process:d} {thread:d} {message}",
"style": "{",
},
"simple": {
"format": "{levelname} {message}",
"style": "{",
},
},
}
style 키워드를 사용하면 str.format`에 ``{``를 지정하거나 :class:`string.Template() 형식에 ``$``를 지정할 수 있습니다. 기본값은 ``$``입니다.
include할 수 있는 LogRecord 속성에 대해 :ref:`logrecord-attributes`를 참조하십시오.
포맷터를 핸들러에 적용하려면, 이름으로 포맷터를 참조하는 핸들러의 사전에 formatter 항목을 추가하십시오. 예를 들면 다음과 같습니다:
"handlers": {
"file": {
"class": "logging.FileHandler",
"filename": "general.log",
"formatter": "verbose",
},
}
로거 네임스페이싱 사용¶
명명되지 않은 로깅 설정 ``’’``은 모든 Python 응용 프로그램에서 로그를 캡처합니다. 명명된 로깅 구성은 이름이 일치하는 로거에서만 로그를 캡처합니다.
The namespace of a logger instance is defined using
getLogger(). For example in views.py of my_app:
logger = logging.getLogger(__name__)
는 my_app.views 네임스페이스에 로거를 생성합니다. ``__name__``을 사용하면 프로젝트의 애플리케이션 내에서 출처에 따라 로그 메시지를 자동으로 구성할 수 있습니다. 또한 이름 충돌이 발생하지 않도록 보장해줍니다.
``my_app.views``라는 로거 매핑은 이 로거에서 레코드를 캡처합니다:
LOGGING = {
# ...
"loggers": {
"my_app.views": {...},
},
}
my_app``이라는 이름의 로거 매핑은 ``my_app 네임스페이스(my_app.views, my_app.utils 등 포함) 내의 모든 로거에서 레코드를 캡처하기 떄문에 더 관대합니다:
LOGGING = {
# ...
"loggers": {
"my_app": {...},
},
}
다음과 같이 로거 네임스페이스를 명시적으로 정의할 수도 있습니다:
logger = logging.getLogger("project.payment")
그리고 그에 따라 로거 매핑을 설정합니다.
로거 계층 및 전파 사용¶
로거 이름 지정은 *계층적*입니다. my_app``은 ``my_app.views.private``의 부모인 ``my_app.views``의 부모입니다. 달리 지정하지 않는 한, 로거 매핑은 처리하는 레코드를 부모에게 전파합니다. ``my_app.views.private 네임스페이스에 있는 로거의 레코드는 my_app 및 my_app.views 모두에 대한 매핑에 의해 처리됩니다.
이 동작을 관리하려면, 당신이 정의한 매핑에서 전파 키를 설정합니다.
LOGGING = {
# ...
"loggers": {
"my_app": {
# ...
},
"my_app.views": {
# ...
},
"my_app.views.private": {
# ...
"propagate": False,
},
},
}
``propagate``의 기본값은 ``True``입니다. 이 예에서 ``my_app.views.private``의 로그는 상위에서 처리되지 않지만 ``my_app.views``의 로그는 처리됩니다.
반응형 로깅 구성¶
로깅은 필요하지 않은 정보를 제외한 가능한 많은 정보를 포함할 때 가장 유용합니다. 필요한 정보의 양은 수행 중인 작업에 따라 다릅니다. 디버깅할 때는 프로덕션에서는 과도하고 도움이 되지 않는 수준의 정보가 필요합니다.
필요할 때 필요한 세부 수준을 제공하도록 로깅을 구성할 수 있습니다. 이를 위해 수동으로 구성을 변경하는 것보다, 환경에 따라 자동으로 구성을 적용하는 것이 더 좋은 방법입니다.
예를 들어, 개발 및 스테이징 환경에서 DJANGO_LOG_LEVEL 환경 변수를 적절하게 설정하여 로거 매핑에서 사용할 수 있습니다:
"level": os.getenv("DJANGO_LOG_LEVEL", "WARNING")
- 따라서 환경이 더 낮은 로그 수준을 지정하지 않는 한 이 구성은 WARNING 이상의 심각도를 가진 레코드만 핸들러로 전달합니다.
구성의 다른 옵션(예: 핸들러의 level 또는 formatter 옵션)도 유사하게 관리할 수 있습니다.