Django에서 Python 로깅의 우아한 설정


101

나는 아직 내가 만족하는 Django로 Python 로깅을 설정하는 방법을 찾지 못했습니다. 내 요구 사항은 매우 간단합니다.

  • 다른 이벤트에 대한 다른 로그 처리기-즉, 다른 파일에 기록 할 수 있기를 원합니다.
  • 내 모듈의 로거에 쉽게 액세스 할 수 있습니다. 모듈은 적은 노력으로 로거를 찾을 수 있어야합니다.
  • 명령 줄 모듈에 쉽게 적용 할 수 있어야합니다. 시스템의 일부는 독립 실행 형 명령 줄 또는 데몬 프로세스입니다. 로깅은 이러한 모듈에서 쉽게 사용할 수 있어야합니다.

내 현재 설정은 logging.conf내가 로그하는 각 모듈에서 파일 및 설정 로깅 을 사용하는 것입니다. 옳지 않다.

원하는 로깅 설정이 있습니까? 자세히 설명하십시오 : 구성 설정 방법 ( logging.conf코드에서 사용 또는 설정), 로거를 시작하는 위치 / 시점, 모듈에서 액세스하는 방법 등.


1
다음 스크린 캐스트가 유용 할 수 있습니다 -ericholscher.com/blog/2008/aug/29/… . 또한 Simon Willison이 Django 로그인에 대한 더 나은 지원을 제안했습니다 ( simonwillison.net/2009/Sep/28/ponies 참조 ).
Dominic Rodger

@Dominic Rodger-주로 Django 내부에서 로깅을 용이하게하기위한 Simon의 제안 인 Django에서 앱의 유연한 로깅을 이미 수행 할 수 있습니다. Python 로깅에 딕셔너리 기반 구성을 추가하는 작업이 Python에서 진행되고 있으며, Django가 이점을 얻을 수 있습니다.
Vinay Sajip

답변:


57

지금까지 찾은 가장 좋은 방법은 settings.py에서 로깅 설정을 초기화하는 것입니다. 구성 파일을 사용하거나 단계별로 프로그래밍 방식으로 수행 할 수 있습니다. 요구 사항에 따라 다릅니다. 핵심은 보통 레벨을 사용하고 때로는 logging.Filters를 사용하여 루트 로거에 원하는 핸들러를 추가한다는 것입니다. 적절한 파일, 콘솔, syslog 등에 원하는 이벤트를 가져 오기 위해 필터를 사용합니다. 물론 다른 로거에 핸들러를 추가 할 수 있습니다. 그러나 내 경험상 일반적으로 이것이 필요하지 않습니다.

각 모듈에서 다음을 사용하여 로거를 정의합니다.

logger = logging.getLogger(__name__)

모듈에서 이벤트를 로깅하는 데 사용하고 (더 구분하고 싶다면) 위에서 만든 로거의 자식 인 로거를 사용하십시오.

내 앱이 settings.py에 로그인을 구성하지 않는 사이트에서 잠재적으로 사용되는 경우 다음과 같이 어딘가에 NullHandler를 정의합니다.

#someutils.py

class NullHandler(logging.Handler):
    def emit(self, record):
        pass

null_handler = NullHandler()

로깅을 사용하는 내 앱의 모듈에서 생성 된 모든 로거에 인스턴스가 추가되었는지 확인합니다. (참고 : NullHandler는 이미 Python 3.1 용 로깅 패키지에 있으며 Python 2.7에 포함될 예정입니다.) 따라서 :

logger = logging.getLogger(__name__)
logger.addHandler(someutils.null_handler)

이는 settings.py에 로그인을 구성하지 않는 사이트에서 모듈이 잘 작동하는지 확인하고 "로거 XYZ에 대한 핸들러를 찾을 수 없습니다"라는 성가신 메시지 (잠재적으로 경고)를받지 않도록하기위한 것입니다. 잘못 구성된 로깅).

이렇게하면 명시된 요구 사항을 충족합니다.

  • 현재 수행하는 것처럼 다른 이벤트에 대해 다른 로그 핸들러를 설정할 수 있습니다.
  • 모듈의 로거에 쉽게 액세스- getLogger(__name__).
  • 명령 줄 모듈에 쉽게 적용 할 수 있으며 settings.py.

업데이트 : 버전 1.3부터 ​​Django 는 로깅 지원을 통합 합니다 .


이렇게하려면 모든 모듈에 구성에 정의 된 핸들러가 있어야하지 않습니까 (foo에 대한 핸들러를 사용하여 foo.bar를 처리 할 수 ​​없음)? groups.google.com/group/comp.lang.python/browse_thread/thread/…
andrew cooke

1
@andrew cooke :에 대한 처리기를 사용하여에 기록 된 이벤트를 처리 있습니다 . 레. 해당 스레드-fileConfig 및 dictConfig 모두 이제 이전 로거를 비활성화하는 것을 방지하는 옵션이 있습니다. 이 문제를 참조하십시오 : bugs.python.org/issue3136 , 문제 가 발생한 지 몇 달 후 bugs.python.org/issue2697- 어쨌든, 2008 년 6 월 이후로 분류되었습니다.foofoo.bar
Vinay Sajip

null_handler가 이미 추가 된 로거를 반환하는 logger = someutils.getLogger(__name__)곳 에서 수행하는 것이 더 낫지 않을까요? someutils.getLoggerlogging.getLogger
7yl4r

1
@ 7yl4r 추가 된 모든 로거가 필요하지는 않습니다. NullHandler일반적으로 패키지 계층 구조의 최상위 로거 만 필요합니다. 그래서 그것은 과잉 일 것입니다, IMO.
Vinay Sajip

122

나는 이것이 이미 해결 된 대답이라는 것을 알고 있지만 django> = 1.3에 따라 새로운 로깅 설정이 있습니다.

이전에서 새 것으로 이동하는 것은 자동이 아니므로 여기에 적어 두겠습니다.

그리고 물론 더 많은 것을 위해 django 문서 를 확인 하십시오 .

이것은 django-admin createproject v1.3으로 기본적으로 생성되는 기본 conf입니다. 마일리지는 최신 django 버전으로 변경 될 수 있습니다.

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        }
    }
}

이 구조는 다음 블록을 지시하는 표준 Python 로깅 dictConfig를 기반으로합니다 .

  • formatters -해당 값은 각 키가 포맷터 ID이고 각 값이 해당 Formatter 인스턴스를 구성하는 방법을 설명하는 dict 인 dict입니다.
  • filters -해당 값은 각 키가 필터 ID 인 dict이고 각 값은 해당 Filter 인스턴스를 구성하는 방법을 설명하는 dict입니다.
  • handlers-해당 값은 각 키가 핸들러 ID 인 dict이고 각 값은 해당 Handler 인스턴스를 구성하는 방법을 설명하는 dict입니다. 각 핸들러에는 다음 키가 있습니다.

    • class(필수). 이것은 핸들러 클래스의 완전한 이름입니다.
    • level(선택 과목). 핸들러의 레벨입니다.
    • formatter(선택 과목). 이 핸들러에 대한 포맷터의 ID입니다.
    • filters(선택 과목). 이 핸들러에 대한 필터의 ID 목록입니다.

나는 보통 적어도 이것을한다 :

  • .log 파일 추가
  • 이 로그에 쓰도록 내 앱 구성

다음으로 번역됩니다.

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'null': {
            'level':'DEBUG',
            'class':'django.utils.log.NullHandler',
        },
        'console':{
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        # I always add this handler to facilitate separating loggings
        'log_file':{
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(VAR_ROOT, 'logs/django.log'),
            'maxBytes': '16777216', # 16megabytes
            'formatter': 'verbose'
        },
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler',
            'include_html': True,
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        'apps': { # I keep all my of apps under 'apps' folder, but you can also add them one by one, and this depends on how your virtualenv/paths are set
            'handlers': ['log_file'],
            'level': 'INFO',
            'propagate': True,
        },
    },
    # you can also shortcut 'loggers' and just configure logging for EVERYTHING at once
    'root': {
        'handlers': ['console', 'mail_admins'],
        'level': 'INFO'
    },
}

편집하다

이제 요청 예외가 항상 기록 되고 티켓 # 16288을 참조하십시오 .

기본적으로 debug가 True 일 때 이메일이 전송되지 않도록 mail_admins에 대한 올바른 필터를 명시 적으로 포함하도록 위의 샘플 conf를 업데이트했습니다.

필터를 추가해야합니다.

'filters': {
    'require_debug_false': {
        '()': 'django.utils.log.RequireDebugFalse'
    }
},

mail_admins 핸들러에 적용합니다.

    'mail_admins': {
        'level': 'ERROR',
        'filters': ['require_debug_false'],
        'class': 'django.utils.log.AdminEmailHandler',
        'include_html': True,
    }

그렇지 않으면 django.core.handers.base.handle_uncaught_exceptionsettings.DEBUG가 True 인 경우 'django.request'로거에 오류를 전달하지 않습니다.

Django 1.5에서이 작업을 수행하지 않으면

DeprecationWarning : 'mail_admins'로깅 핸들러에 정의 된 필터가 없습니다. 암시 적 디버그-거짓 전용 필터 추가

그러나 django 1.4와 django 1.5에서 모두 올바르게 작동합니다.

** 편집 종료 **

이 conf는 django 문서의 샘플 conf에서 영감을 얻었지만 로그 파일 부분을 추가했습니다.

나는 종종 다음을 수행합니다.

LOG_LEVEL = 'DEBUG' if DEBUG else 'INFO'

...
    'level': LOG_LEVEL
...

그런 다음 내 파이썬 코드에서 로깅 conf가 정의되지 않은 경우 항상 NullHandler를 추가합니다. 이렇게하면 핸들러가 지정되지 않은 경우 경고가 발생하지 않습니다. Django ( ref ) 에서만 호출되지 않는 libs에 특히 유용합니다.

import logging
# Get an instance of a logger
logger = logging.getLogger(__name__)
class NullHandler(logging.Handler): #exists in python 3.1
    def emit(self, record):
        pass
nullhandler = logger.addHandler(NullHandler())

# here you can also add some local logger should you want: to stdout with streamhandler, or to a local file...

[...]

logger.warning('etc.etc.')

도움이 되었기를 바랍니다!


Stefano, 자세한 답변에 감사드립니다. 이렇게하면 1.3으로 업그레이드 할 가치가 있습니다.
Parand 2011-04-28

Parand, 확실히 (IMHO!) django 1.3으로 올라갈 가치가 있습니다.하지만 원활한 전환을 위해 처리해야 할 몇 가지 사항이 있습니다. 문제가 발생하면 새 SO 질문을 엽니 다 ;-)
Stefano

그건 그렇고 : 나는 여전히 이런 종류의 설정과 파일 로그를 사용하지만 프로덕션 을 위해 보초 로 옮겼습니다 !
Stefano

@clime 잘 나는 대답 자체에서 그것을 설명하려고 노력했다 : 로깅 conf가 전혀 정의되지 않은 경우. 이렇게하면 핸들러가 지정되지 않은 경우 경고가 발생하지 않습니다. Django에서만 호출되지 않는 libs에 특히 유용합니다 (ref)
Stefano

'널 (null)': { 'django.utils.log.NullHandler', '수준': 'DEBUG', '클래스'} 난 당신이 정의를 사용하는 방법이 표시되지 않습니다
지방

9

파일 urls.py을 사용하여 최상위 수준에서 로깅을 초기화 logging.ini합니다.

의 위치는에서 logging.ini제공 settings.py되지만 그게 전부입니다.

그런 다음 각 모듈은

logger = logging.getLogger(__name__)

테스트, 개발 및 프로덕션 인스턴스를 구분하기 위해 다른 logging.ini 파일이 있습니다. 대부분의 경우, 오류 만있는 stderr로 이동하는 "콘솔 로그"가 있습니다. 로그 디렉토리로 이동하는 일반 롤링 로그 파일을 사용하는 "애플리케이션 로그"가 있습니다.


urls.py 대신 settings.py에서 초기화하는 것을 제외하고는 이것을 사용하게되었습니다
Parand

logging.ini 파일에서 settings.py의 설정을 어떻게 사용합니까? 예를 들어 BASE_DIR 설정이 필요하므로 로그 파일을 저장할 위치를 알려줄 수 있습니다.
slypete 2010 년

@slypete : logging.ini의 설정을 사용하지 않습니다. 로깅은 거의 독립적이므로 Django 설정을 사용하지 않습니다. 예, 무언가를 반복 할 가능성이 있습니다. 아니요, 실제적인 차이는별로 없습니다.
S.Lott

이 경우 앱을 설치할 때마다 별도의 logging.ini 파일을 사용합니다.
slypete 2010-06-03

@slypete : 각 설치에 대한 settings.py가 있습니다. 또한 각 설치에 대한 logging.ini가 있습니다. 또한 각 설치마다 Apache conf 파일이있을 것입니다. 게다가 wsgi 인터페이스 파일. 당신의 요점이 무엇인지 잘 모르겠습니다.
S.Lott

6

현재 직접 만든 로깅 시스템을 사용하고 있습니다. 로깅을 위해 CSV 형식을 사용합니다.

django-csvlog

이 프로젝트에는 여전히 완전한 문서가 없지만 작업 중입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.