Python 로그: 깊이 있는 튜토리얼

14521 단어 loggingpythontutorial
응용 프로그램이 갈수록 복잡해지면서 좋은 로그를 가지고 디버깅할 때 매우 유용할 뿐만 아니라 응용 프로그램의 문제/성능을 깊이 있게 이해할 수 있다.측정도 유명한 The twelve-factor app의 한 요인이다.
Python 표준 라이브러리에는 logging 모듈이 첨부되어 있으며, 이 모듈은 대부분의 기본 로그 기능을 제공합니다.정확한 설정을 통해 로그 메시지는 언제 로그를 터치하는지, 실행 중인 프로세스/루틴 같은 로그 상하문을 포함하여 많은 유용한 정보를 가져올 수 있습니다.
비록 이러한 장점이 있지만, 로그 모듈은 정확하게 설정할 수 있는 시간이 좀 걸리기 때문에 종종 무시된다.공식 문건 https://docs.python.org/3/library/logging.html은 완전하지만 최선의 실천을 보여주거나 일지 서프라이즈를 강조하지 않았다.
이 Python 로그 강좌는 로그 모듈에 대한 완전한 문서가 아니라 로그 개념과 주의해야 할 문제점을 소개하는 입문 안내서입니다.이 글은 최선의 실천으로 끝날 것이다.
이 문서의 모든 코드 세그먼트는 로그 모듈을 가져온 것으로 가정합니다.
import logging

Python 로그의 개념


이 절은 로그 모듈에서 자주 만나는 개념들을 개술하였다.

수평


로그 수준은 주어진 로그에 대응하는 중요성: error 로그는 warn 로그보다 더 긴급해야 하고, debug 로그는 디버깅 프로그램에서만 사용해야 한다.
Python에는 6개의 로그 레벨이 있습니다.각 레벨은 하나의 정수와 연결되며, 이 정수는 로그의 심각성을 나타냅니다. NOTSET=0, DEBUG=10, INFO=20, WARN=30, ERROR=40, CRITICAL=50.

포맷 프로그램


로그 formatter은 상하문 정보를 추가하여 로그 메시지를 풍부하게 합니다.로그의 발송 시간, 위치 (Python 파일, 줄 번호, 방법 등) 및 추가 상하문 (예를 들어 루트와 프로세스 id) 을 이해하는 데 매우 유용합니다. (다중 루트 프로그램을 디버깅할 때 매우 유용합니다.)
예를 들어 이 로그 포맷 프로그램을 통해 로그 hello world을 보낼 때:
"%(asctime)s — %(name)s — %(levelname)s — %(funcName)s:%(lineno)d — %(message)s"
그것은2018-02-07 19:47:41,864 - a.b.c - WARNING - <module>:1 - hello world

처리 프로그램


로그 handler은 로그를 올바르게 쓰기/표시하는 구성 요소입니다. StreamHandler을 통해 컨트롤러에 로그를 표시하고, FileHandler을 통해 파일을 작성하고, SMTPHandler을 통해 이메일을 보낼 수 있습니다.
각 로그 프로세서에는 다음과 같은 두 개의 중요한 필드가 있습니다.
  • 은 로그에 상하문 정보를 추가하는 포맷 프로그램입니다.
  • 은 낮은 로그를 필터하는 데 사용되는 로그 수준입니다.예를 들어 정보 등급이 있는 로그 프로세서는 디버깅 로그를 처리하지 않습니다.
  • 표준 라이브러리는 흔히 볼 수 있는 용례를 충족시킬 수 있는 처리 프로그램을 제공했다. https://docs.python.org/3/library/logging.handlers.html#module-logging.handlers.가장 흔히 볼 수 있는 것은 StreamHandlerFileHandler:
    console_handler = logging.StreamHandler()
    file_handler = logging.FileHandler("filename")
    

    레코더


    기록기는 우리가 그것과 가장 많은 상호작용을 할 대상이자 가장 복잡한 개념이다.다음 방법으로 새 레코더를 얻을 수 있습니다.
    toto_logger = logging.getLogger("toto")
    
    레코더에는 다음과 같은 세 가지 주요 필드가 있습니다.
  • Propagate: 로그를 기록기의 부급으로 전파해야 하는지 여부를 결정합니다.기본값은 True입니다.
  • Level: 프로세서 레벨과 마찬가지로 기록기 레벨은 중요하지 않은 로그를 필터하는 데 사용됩니다.이외에 로그 처리 프로그램과 달리 하위 기록기에서만 단계를 검사합니다.로그가 상위 레벨로 전파되면 레벨을 확인하지 않습니다.이것은 일종의 비직각적인 행위다.
  • Handlers: 로그가 기록기에 도착했을 때 보내는 프로세서 목록입니다.이것은 유연한 로그 처리를 허용합니다. 예를 들어 모든 디버그 로그를 기록하는 파일 로그 처리 프로그램과 관건적인 로그에만 사용되는 전자 우편 로그 처리 프로그램이 있습니다.이 방면에서 기록기-처리 프로그램 관계는 발표자-소비자 관계와 유사하다. 로그는 기록기 등급 검사를 통해 모든 처리 프로그램에 방송된다.

  • 레코더의 이름은 고유합니다. 이것은 toto이라는 레코더가 생성된 경우 logging.getLogger("toto")의 후속 호출이 같은 객체로 되돌아온다는 것을 의미합니다.
    assert id(logging.getLogger("toto")) == id(logging.getLogger("toto"))
    
    이미 짐작했듯이 벌목꾼은 차원 구조를 가지고 있다.차원 구조의 맨 위에는 root 기록기가 있는데 logging.root을 통해 이 기록기에 접근할 수 있다.logging 모듈(예를 들어 logging.debug())에서 직접 방법을 호출할 때 이 기록기를 호출합니다.기본적으로 루트 로그 레벨은 WARN이므로 각 레벨이 낮은 로그 (예: logging.info("info")) 는 무시됩니다.
    루트 레코더의 또 다른 특수성은 기본 프로세서가 WARN보다 높은 로그를 처음 기록할 때 만들어진다는 것이다.일반적으로 logging.debug() 등의 방법을 통해 루트 기록기를 직접 또는 간접적으로 사용하는 것을 권장하지 않는다.
    기본적으로 새 레코더를 만들 때 부모 레코더는 루트 레코더로 설정됩니다.
    lab = logging.getLogger("a.b")
    assert lab.parent == logging.root # lab's parent is indeed the root logger
    
    그러나 기록기는 점 기호를 사용한다. 이것은 a.b이라는 기록기가 기록기 a의 자급이 된다는 것을 의미한다.그러나 레코더 a이 생성되었을 때만 이것이 사실입니다. 그렇지 않으면 ab의 상위 항목은 여전히 root 레코더입니다.
    la = logging.getLogger("a")
    assert lab.parent == la # lab's parent is now la instead of root
    
    기록기가 레벨 검사에 따라 로그를 통과해야 하는지 여부를 결정할 때 (예를 들어 로그 레벨이 기록기 레벨보다 낮으면 로그를 무시합니다) 실제 레벨이 아닌 logger.level을 사용합니다.유효 등급이 NOTSET, 즉 디버깅에서 임계까지의 모든 값이 아니라면 유효 등급은 기록기 등급과 같다.그러나 레코더 레벨이 NOTSET이면 유효 레벨은 NOTSET 레벨이 아닌 최초의 조상 레벨이 됩니다.
    기본적으로 새 레코더의 레벨은 NOTSET입니다. 루트 레코더의 레벨은 WARN이기 때문에 레코더의 유효 레벨은 WARN입니다.따라서 새 레코더에 일부 프로세서가 추가되더라도 로그 레벨이 WARN을 초과하지 않는 한 이러한 프로세서는 호출되지 않습니다.
    toto_logger = logging.getLogger("toto")
    assert toto_logger.level == logging.NOTSET # new logger has NOTSET level
    assert toto_logger.getEffectiveLevel() == logging.WARN # and its effective level is the root logger level, i.e. WARN
    
    # attach a console handler to toto_logger
    console_handler = logging.StreamHandler()
    toto_logger.addHandler(console_handler)
    toto_logger.debug("debug") # nothing is displayed as the log level DEBUG is smaller than toto effective level
    toto_logger.setLevel(logging.DEBUG)
    toto_logger.debug("debug message") # now you should see "debug message" on screen
    
    기본적으로 logger 레벨은 로그의 통과 여부를 결정하는 데 사용됩니다. 로그 레벨이 레코더 레벨보다 낮으면 로그를 무시합니다.

    Python 로깅 모범 사례


    로그 모듈은 정말 편리하지만, 가장 우수한 파이썬 개발자라도 오랫동안 골치 아플 수 있는 괴벽이 포함되어 있다.다음은 이 모듈을 사용하는 가장 좋은 방법입니다.
  • 은 루트 기록기를 설정하지만 코드에서 사용하지 마십시오. 예를 들어 logging.info() 같은 함수를 호출하지 마십시오. 이 함수는 백엔드에서 루트 기록기를 호출합니다.사용 중인 라이브러리에서 오류 메시지를 캡처하려면 루트 레코더를 설정하는 것이 유용합니다.
  • 에서 로깅을 사용하려면 logging.getLogger(logger name)으로 새 레코더를 만드십시오.나는 보통 __name__을 단일 모듈의 레코더 이름이나 전체 응용 프로그램/라이브러리의 정적 이름으로 사용하지만, 일치하기만 하면 모든 이름을 사용할 수 있다.더 많은 처리 프로그램을 추가하기 위해서, 나는 보통 기록기를 되돌려 주는 방법이 있다. (https://gist.github.com/nguyenkims/e92df0f8bd49973f0c94bddf36ed7fd0에서 요점을 찾을 수 있습니다.)
  • import logging
    import sys
    from logging.handlers import TimedRotatingFileHandler
    FORMATTER = logging.Formatter("%(asctime)s — %(name)s — %(levelname)s — %(message)s")
    LOG_FILE = "my_app.log"
    
    def get_console_handler():
       console_handler = logging.StreamHandler(sys.stdout)
       console_handler.setFormatter(FORMATTER)
       return console_handler
    
    def get_file_handler():
       file_handler = TimedRotatingFileHandler(LOG_FILE, when='midnight')
       file_handler.setFormatter(FORMATTER)
       return file_handler
    
    def get_logger(logger_name):
       logger = logging.getLogger(logger_name)
       logger.setLevel(logging.DEBUG) # better to have too much log than not enough
       logger.addHandler(get_console_handler())
       logger.addHandler(get_file_handler())
       # with this pattern, it's rarely necessary to propagate the error up to parent
       logger.propagate = False
       return logger
    
    새 레코더를 만들고 사용한 후:
    my_logger = get_logger("my module name")
    my_logger.debug("a debug message")
    
  • RotatingFileHandler 클래스를 사용합니다. 예를 들어 예시에서 사용한 TimedRotatingFileHandler이 아니라 FileHandler을 사용합니다. 파일이 크기 제한에 도달하면 자동으로 파일을 회전하거나 매일 회전하기 때문입니다.
  • 은 Sentry, Airbrake, Raygun 등의 도구를 사용하여 오류 로그를 자동으로 캡처합니다.이것은 웹 응용 프로그램의 상하문에서 특히 유용하다. 웹 응용 프로그램에서 로그가 매우 상세할 수 있고 오류 로그는 잃어버리기 쉽다.이 도구를 사용하는 또 다른 장점은 오류의 변수 값에 대한 상세한 정보를 얻을 수 있다는 것이다. 그러면 오류를 일으키는 URL이 무엇인지, 사용자가 무엇을 관심을 가지는지 등을 알 수 있다.
  • 로그의 정상적인 작업을 확보하는 것은 새로운 프로젝트를 설정할 때 가장 먼저 해야 할 일 중 하나이다. 왜냐하면 앞으로 무수한 시간의 디버깅 시간을 절약할 수 있기 때문이다.

    좋은 웹페이지 즐겨찾기