logging.config --- 로깅 구성

소스 코드: Lib/logging/config.py


이 절에서는 logging 모듈을 구성하기 위한 API에 관해 설명합니다.

구성 함수

다음 함수는 logging 모듈을 구성합니다. logging.config 모듈에 있습니다. 사용은 선택 사항입니다 --- 이 함수들을 사용하거나 (logging 자체에서 정의된) 주 API를 호출하고 logging이나 logging.handlers에서 선언된 처리기를 정의해서 logging 모듈을 구성할 수 있습니다.

logging.config.dictConfig(config)

딕셔너리로 로깅 구성을 받습니다. 이 딕셔너리의 내용은 아래의 구성 딕셔너리 스키마에 설명되어 있습니다.

구성 중에 에러를 만나면, 이 함수는 적절하게 설명하는 메시지와 함께 ValueError, TypeError, AttributeError 또는 ImportError를 발생시킵니다. 다음은 에러를 발생시킬 수 있는 (불완전한) 조건 목록입니다:

  • 문자열이 아니거나 실제 로깅 수준과 일치하지 않는 문자열인 level.

  • 불리언이 아닌 propagate 값.

  • 해당 대상이 없는 id.

  • 증분(incremental) 호출 중에 발견된 존재하지 않는 처리기 id.

  • 잘못된 로거 이름.

  • 결정할 수 없는 내부나 외부 객체.

구문 분석은 DictConfigurator 클래스에 의해 수행되며, 생성자로는 구성에 사용되는 딕셔너리가 전달되고, 객체는 configure() 메서드를 가집니다. logging.config 모듈에는 초기에 DictConfigurator로 설정된 콜러블 어트리뷰트 dictConfigClass가 있습니다. 여러분 자신의 적절한 구현으로 dictConfigClass의 값을 바꿀 수 있습니다.

dictConfig()dictConfigClass를 호출해서 지정된 딕셔너리를 전달한 다음, 반환된 객체의 configure() 메서드를 호출하여 구성을 적용합니다:

def dictConfig(config):
    dictConfigClass(config).configure()

예를 들어, DictConfigurator의 서브 클래스는 자체 __init__()에서 DictConfigurator.__init__()를 호출한 다음, 후속 configure() 호출에서 사용할 수 있는 사용자 정의 접두사를 설정할 수 있습니다. dictConfigClass는 이 새 서브 클래스에 연결되고, dictConfig()는 기본, 사용자 정의되지 않은 상태에서와 똑같이 호출될 수 있습니다.

버전 3.2에 추가.

logging.config.fileConfig(fname, defaults=None, disable_existing_loggers=True)

configparser-형식 파일에서 로깅 구성을 읽습니다. 파일 형식은 구성 파일 형식에 설명된 것과 같아야 합니다. 이 함수는 응용 프로그램에서 여러 번 호출 할 수 있어서, 최종 사용자가 여러 가지 미리 준비된 구성 중에서 선택할 수 있도록 합니다 (개발자가 선택 사항을 표시하고 선택한 구성을 로드하는 메커니즘을 제공한다면).

매개변수
  • fname -- 파일명, 또는 파일류 객체, 또는 RawConfigParser에서 파생된 인스턴스. RawConfigParser-파생 인스턴스가 전달되면, 그대로 사용됩니다. 그렇지 않으면, Configparser의 인스턴스가 만들어지고, 이것으로 fname으로 전달된 객체로부터 구성을 읽습니다. readline() 메서드가 있으면, 파일류 객체라고 가정하고, read_file()을 사용하여 읽습니다; 그렇지 않으면, 파일명으로 간주하고 read()로 전달됩니다.

  • defaults -- ConfigParser로 전달되는 기본값을 이 인자로 지정할 수 있습니다.

  • disable_existing_loggers -- False로 지정되면, 이 호출이 이루어졌을 때 존재하는 로거는 활성화된 상태로 남습니다. 기본값은 True이므로, 과거 호환성을 유지하도록 이전 동작을 활성화합니다. 이 동작은 이미 존재하는 비 루트 로거를 그들이나 그들의 조상이 로깅 구성에서 명시적으로 명명되지 않으면 비활성화하는 것입니다.

버전 3.4에서 변경: RawConfigParser의 서브 클래스의 인스턴스가 이제 fname에 대한 값으로 허용됩니다. 이것은 다음을 쉽게 합니다:

  • 로깅 구성이 전체 응용 프로그램 구성의 일부인 구성 파일의 사용.

  • 파일에서 읽어 들인 다음 fileConfig로 전달되기 전에 사용하는 응용 프로그램이 (예를 들어, 명령 줄 매개 변수나 실행 시간 환경의 다른 측면에 기반하여) 수정하는 구성의 사용.

logging.config.listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None)

지정된 포트에서 소켓 서버를 시작하고, 새 구성을 수신 대기합니다. 포트를 지정하지 않으면, 모듈의 기본 DEFAULT_LOGGING_CONFIG_PORT가 사용됩니다. 로깅 구성은 dictConfig()fileConfig()로 처리하기에 적합한 파일로 전송됩니다. 서버를 시작하기 위해 start()를 호출할 수 있는 Thread 인스턴스를 반환하고, 적절할 때 join()할 수 있습니다. 서버를 중지하려면, stopListening()을 호출하십시오.

flowdas

DEFAULT_LOGGING_CONFIG_PORT은 9030입니다.

verify 인자가 지정되면, 소켓을 통해 수신된 바이트열이 유효하고 처리되어야 하는지를 확인하는 콜러블이어야 합니다. 소켓을 통해 전송되는 것을 암호화 및/또는 서명하고, verify 콜러블이 서명 확인 및/또는 암호 해독을 수행할 수 있습니다. verify 콜러블은 단일 인자(소켓을 통해 수신된 바이트열)로 호출되며, 처리할 바이트열이나 바이트열을 버려야 함을 나타내기 위해 None을 반환합니다. 반환된 바이트열은 전달된 바이트열과 같을 수 있고 (예를 들어, 확인만 수행될 때), 또는 완전히 다를 수 있습니다 (아마도 암호 해독이 수행될 때).

소켓으로 구성을 보내려면, 구성 파일을 읽어서 소켓에 struct.pack('>L', n)를 사용하여 바이너리로 만든 4바이트의 길이를 앞에 붙인 바이트 시퀀스를 보냅니다.

flowdas

앞에 붙는 4바이트 길이는 암호화나 서명의 대상이 아닙니다. verify로는 그 뒤에 오는 바이트열만 전달됩니다. 따라서 길이는 암호화나 서명 이후의 바이트열의 길이가 되어야 합니다.

또한 4바이트 길이가 한 번의 recv() 로 읽힌다고 가정하고 있습니다. 아주 안전하지는 않은 코드인데, 구성을 보낼 때 최소한 4바이트 길이는 한 번의 send() 호출로 전달되도록 신경 써야 합니다.

참고

구성 일부가 eval()로 전달되므로, 이 함수를 사용하면 사용자를 보안 위험에 노출할 수 있습니다. 이 함수는 소켓을 localhost에만 바인드하고, 원격 기계의 연결은 허용하지 않지만, 신뢰할 수 없는 코드가 listen()을 호출하는 프로세스의 계정으로 실행될 수 있는 시나리오가 있습니다. 특히, listen()을 호출하는 프로세스가 사용자가 서로를 신뢰할 수 없는 다중 사용자 시스템에서 실행되는 경우, 악의적인 사용자는 피해자의 listen() 소켓에 연결하여 공격자가 피해자의 프로세스에서 실행하고자 하는 코드를 실행하는 구성을 보내는 것만으로도, 피해 사용자의 프로세스에서 사실상 임의의 코드를 실행할 수 있습니다. 이것은 기본 포트를 사용하는 경우 특히 쉽게 수행할 수 있지만, 다른 포트가 사용되는 경우에도 어렵지는 않습니다. 이러한 일이 발생할 위험을 피하려면, listen()verify 인자를 사용하여 인식되지 않은 구성이 적용되지 않도록 하십시오.

버전 3.4에서 변경: verify 인자가 추가되었습니다.

참고

리스너에 기존 로거를 비활성화하지 않는 구성을 보내려면, dictConfig()를 사용하도록 구성에 JSON 형식을 사용해야 합니다. 이 방법은 보내는 구성에서 disable_existing_loggersFalse로 지정할 수 있도록 합니다.

logging.config.stopListening()

listen()에 대한 호출로 만들어진 리스닝 서버를 중지합니다. 이것은 일반적으로 listen()의 반환 값에 대해 join()을 호출하기 전에 호출됩니다.

구성 딕셔너리 스키마

로깅 구성을 기술하려면 만들려는 다양한 객체와 그들 간의 연결을 나열해야 합니다; 예를 들어, 'console'이라는 처리기를 만든 다음 'startup'이라는 로거가 'console' 처리기에 메시지를 보낼 것이라고 말할 수 있습니다. 사용자 자신의 포매터나 처리기 클래스를 작성할 수 있으므로, 이러한 객체가 logging 모듈에서 제공하는 객체로만 제한되지는 않습니다. 이러한 클래스의 매개 변수는 sys.stderr과 같은 외부 객체를 포함할 수도 있습니다. 이러한 객체와 연결을 기술하는 문법은 아래의 객체 연결에 정의되어 있습니다.

딕셔너리 스키마 세부사항

dictConfig()에 전달되는 딕셔너리에는 반드시 다음 키가 있어야 합니다:

  • version - 스키마 버전을 나타내는 정숫값으로 설정됩니다. 현재 유효한 유일한 값은 1이지만, 이 키를 사용하면 과거 호환성을 유지하면서 스키마를 발전시킬 수 있습니다.

다른 모든 키는 선택 사항이지만, 있으면 아래에 설명된 대로 해석됩니다. 아래에서 '구성 딕셔너리(configuring dict)'가 언급되는 모든 경우에, 특수한 '()' 키를 검사해서 사용자 정의 인스턴스화가 필요한지를 확인합니다. 있다면, 아래의 사용자 정의 객체에 설명된 메커니즘을 사용하여 인스턴스를 만듭니다; 그렇지 않다면, 어떤 인스턴스를 만들지를 결정하는데 문맥이 사용됩니다.

  • formatters - 해당 값은 딕셔너리인데, 각 키는 포매터 id이고, 각 값은 해당 Formatter 인스턴스를 구성하는 방법을 설명하는 딕셔너리입니다.

    구성 딕셔너리는 키 formatdatefmt(기본값은 None)으로 검색되며 이들은 Formatter 인스턴스를 만드는 데 사용됩니다.

    버전 3.8에서 변경: 구성 딕셔너리의 formatters 섹션에 validate 키(기본값은 True)를 추가할 수 있습니다. 이것은 포맷을 확인하기 위함입니다.

  • filters - 해당 값은 딕셔너리인데, 각 키가 필터 id이고 각 값은 해당 Filter 인스턴스를 구성하는 방법을 설명하는 딕셔너리입니다.

    구성 딕셔너리는 키 name(기본값은 빈 문자열)으로 검색되며, 이는 logging.Filter 인스턴스를 만드는 데 사용됩니다.

  • handlers - 해당 값은 딕셔너리인데, 각 키가 처리기 id이고 각 값은 해당 Handler 인스턴스를 구성하는 방법을 설명하는 딕셔너리입니다.

    구성 딕셔너리는 다음 키에서 검색합니다:

    • class (필수). 이것은 처리기 클래스의 완전히 정규화된 이름입니다.

    • level (선택). 처리기의 수준.

    • formatter (선택). 이 처리기의 포매터의 id.

    • filters (선택). 이 처리기의 필터의 id의 리스트.

    모든 다른 키는, 처리기의 생성자에 키워드 인자로 전달됩니다. 예를 들어, 다음과 같이 주어진 조각에서:

    handlers:
      console:
        class : logging.StreamHandler
        formatter: brief
        level   : INFO
        filters: [allow_foo]
        stream  : ext://sys.stdout
      file:
        class : logging.handlers.RotatingFileHandler
        formatter: precise
        filename: logconfig.log
        maxBytes: 1024
        backupCount: 3
    

    id가 console 인 처리기는 sys.stdout를 하부 스트림으로 사용하는 logging.StreamHandler로 인스턴스가 만들어집니다. id가 file 인 처리기는 키워드 인자 filename='logconfig.log', maxBytes=1024, backupCount=3를 사용하여 logging.handlers.RotatingFileHandler로 인스턴스가 만들어집니다.

  • loggers - 해당 값은 딕셔너리인데, 각 키가 로거 이름이고 각 값은 해당 Logger 인스턴스를 구성하는 방법을 설명하는 딕셔너리입니다.

    구성 딕셔너리는 다음 키에서 검색합니다:

    • level (선택). 로거의 수준.

    • propagate (선택). 로거의 전파(propagation) 설정.

    • filters (선택). 이 로거의 필터의 id의 리스트

    • handlers (선택). 이 로거의 처리기의 id의 리스트.

    지정된 로거는 지정된 수준, 전파, 필터와 처리기에 따라 구성됩니다.

  • root - 루트 로거에 대한 구성입니다. propagate 설정을 적용할 수 없다는 점을 제외하고 구성 처리는 모든 로거와 같습니다.

  • incremental - 구성을 기존 구성의 증분으로 해석할지 여부. 이 값의 기본값은 False이며, 이는 지정된 구성이 기존 구성을 기존 fileConfig() API에서 사용된 것과 같은 의미로 대체 함을 뜻합니다.

    지정된 값이 True이면, 증분 구성 절에서 설명하는 대로 구성이 처리됩니다.

  • disable_existing_loggers - 기존의 루트가 아닌 로거를 비활성화할지 여부. 이 설정은 fileConfig()의 같은 이름의 매개 변수를 반영합니다. 없으면, 이 매개 변수의 기본값은 True입니다. incrementalTrue이면 이 값은 무시됩니다.

증분 구성

증분 구성에 완벽한 유연성을 제공하기는 어렵습니다. 예를 들어, 필터와 포매터와 같은 객체는 익명이므로, 일단 구성이 설정되면, 이러한 익명 객체를 참조하여 구성을 보강할 수 없습니다.

또한, 일단 구성이 설정되면, 실행 시간에 로거, 처리기, 필터, 포매터의 객체 그래프를 임의로 변경해야 할 강력한 사례는 없습니다; 로거와 처리기의 상세도는 단지 수준(과, loggers에서는 전파 플래그)을 설정하여 제어할 수 있습니다. 객체 그래프를 임의로 안전하게 변경하는 것은 다중 스레드 환경에서 문제가 됩니다; 불가능하지는 않지만, 구현에 추가되는 복잡성을 상쇄할만한 가치가 없습니다.

따라서, 구성 딕셔너리의 incremental 키가 있고 True이면, 시스템은 formattersfilters 항목을 완전히 무시하고 handlers 항목의 level 설정과 loggersroot 항목의 levelpropagate 설정만 처리합니다.

구성 딕셔너리의 값을 사용하면 구성을 피클 된 딕셔너리의 형태로 네트워크를 통해 소켓 리스너로 전송할 수 있습니다. 따라서, 장기 실행 응용 프로그램의 로깅 상세도는 응용 프로그램을 중지하고 다시 시작할 필요 없이 도중에 변경될 수 있습니다.

객체 연결

스키마는 객체 그래프에서 서로 연결된 로깅 객체 집합(로거, 처리기, 포매터, 필터)을 기술합니다. 따라서, 스키마는 객체 간의 연결을 표현할 필요가 있습니다. 예를 들어, 일단 구성되면, 특정 로거가 특정 처리기에 연결된다고 합시다. 이 토론의 목적을 위해, 둘 간의 연결에서 로거는 소스를, 처리기는 대상(destination)을 나타낸다고 할 수 있습니다. 물론 구성된 객체에서 이것은 처리기에 대한 참조를 갖는 로거로 표현됩니다. 구성 딕셔너리에서, 각 대상 객체에 명확하게 식별하는 id를 부여한 다음, 소스 객체의 구성에서 그 id를 사용하여, 소스와 그 id를 갖는 대상 객체 사이에 연결이 있음을 나타냅니다.

그래서, 예를 들어, 다음 YAML 조각을 고려해보십시오:

formatters:
  brief:
    # id 'brief'인 포매터 구성이 여기에 옵니다
  precise:
    # id 'precise'인 포매터 구성이 여기에 옵니다
handlers:
  h1: #이것은 id입니다
   # id 'h1'인 처리기 구성이 여기에 옵니다
   formatter: brief
  h2: #이것은 다른 id입니다.
   # id 'h2'인 처리기 구성이 여기에 옵니다
   formatter: precise
loggers:
  foo.bar.baz:
    # 로거 'foo.bar.baz'의 다른 구성
    handlers: [h1, h2]

(참고: 딕셔너리에 해당하는 파이썬 소스 형식보다 약간 더 읽기 쉬우므로 여기에서 YAML을 사용했습니다.)

로거의 id는 로거로의 참조를 얻기 위해서 프로그램적으로 사용되는 로거 이름입니다, 예를 들어 foo.bar.baz. 포매터와 필터의 id는 임의의 문자열 값(가령 위의 brief, precise)이 될 수 있으며, 일시적이므로 구성 딕셔너리 처리에만 의미가 있고 객체 간의 연결을 결정하는 데 사용되며, 구성 호출이 완료된 후에는 어디에도 남아있지 않습니다.

위의 조각은 foo.bar.baz라는 로거에 두 개의 처리기가 연결되어 있어야 하며, 이 처리기들은 처리기 id h1h2``에 의해 기술됩니다. ``h1의 포매터는 id brief로 기술되는 것이고, h2의 포매터는 id precise로 기술되는 것입니다.

사용자 정의 객체

스키마는 처리기, 필터 및 포매터에 대한 사용자 정의 객체를 지원합니다. (로거에는 인스턴스마다 다른 형이 필요하지 않으므로, 이 구성 스키마에는 사용자 정의 로거 클래스에 대한 지원이 없습니다.)

구성할 객체는 구성을 자세히 설명하는 딕셔너리로 시술됩니다. 어떤 곳에서는, 로깅 시스템이 객체를 어떻게 인스턴스화할지 문맥으로부터 추측할 수 있지만, 사용자 정의 객체를 인스턴스화 해야 할 때, 시스템은 이를 수행하는 방법을 알 수 없습니다. 사용자 정의 객체 인스턴스화를 위한 완벽한 유연성을 제공하기 위해, 사용자는 '팩토리'를 제공해야 하는데, 구성 딕셔너리로 호출되고 인스턴스화 된 객체를 반환하는 콜러블입니다. 이것은 특수키 '()'로 제공되는 팩토리로의 절대적 임포트 경로로 표시됩니다. 다음은 구체적인 예입니다:

formatters:
  brief:
    format: '%(message)s'
  default:
    format: '%(asctime)s %(levelname)-8s %(name)-15s %(message)s'
    datefmt: '%Y-%m-%d %H:%M:%S'
  custom:
      (): my.package.customFormatterFactory
      bar: baz
      spam: 99.9
      answer: 42

위의 YAML 조각은 세 가지 포매터를 정의합니다. 첫 번째(id brief)는 지정된 포맷 문자열을 갖는 표준 logging.Formatter 인스턴스입니다. 두 번째(id default)는 더 긴 포맷을 가지며 명시적으로 시간 포맷을 정의하기도 하고, 이 두 포맷 문자열로 초기화된 logging.Formatter가 됩니다. 파이썬 소스 형식으로 표시하면, briefdefault 포매터는 각각 다음과 같은 구성 서브 딕셔너리를 갖습니다:

{
  'format' : '%(message)s'
}

그리고:

{
  'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s',
  'datefmt' : '%Y-%m-%d %H:%M:%S'
}

그리고, 이 딕셔너리에는 특수키 '()'가 포함되어 있지 않으므로, 문맥에서 인스턴스가 추론됩니다: 결과적으로, 표준 logging.Formatter 인스턴스가 만들어집니다. 세 번째 포매터(id custom)에 대한 구성 서브 딕셔너리는 다음과 같습니다:

{
  '()' : 'my.package.customFormatterFactory',
  'bar' : 'baz',
  'spam' : 99.9,
  'answer' : 42
}

여기에는 특수키 '()'가 포함되어 있는데, 사용자 정의 인스턴스가 필요하다는 뜻입니다. 이때, 지정된 팩토리 콜러블이 사용됩니다. 그것이 실제 콜러블이면 직접 사용됩니다 - 그렇지 않고, (예에서와같이) 문자열을 지정하면 일반적인 임포트 메커니즘을 사용하여 실제 콜러블을 얻습니다. 콜러블은 구성 서브 딕셔너리의 나머지 항목을 키워드 인자로 호출됩니다. 위의 예제에서, id가 custom인 포매터는 다음과 같은 호출이 반환한다고 가정합니다:

my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42)

'()' 키가 유효한 키워드 매개 변수 이름이 아니라서 특수키로 사용되었습니다. 그러므로 호출에 사용되는 키워드 인자의 이름과 충돌하지 않습니다. '()'는 해당 값이 콜러블이라는 표시로도 기능합니다.

외부 객체에 대한 액세스

구성에서 구성 외부의 객체를 참조해야 하는 경우가 있습니다, 예를 들어 sys.stderr. 구성 딕셔너리가 파이썬 코드를 사용하여 만들어질 때는 간단하지만, 구성이 텍스트 파일(예를 들어, JSON, YAML)을 통해 제공될 때 문제가 발생합니다. 텍스트 파일에서는, sys.stderr를 리터럴 문자열 'sys.stderr'과 구별하는 표준 방법이 없습니다. 이 구별을 쉽게 하기 위해, 구성 시스템은 문자열 값에서 특정 접두사를 찾아 특수하게 처리합니다. 예를 들어, 리터럴 문자열 'ext://sys.stderr'이 구성에서 값으로 제공되면, ext://는 제거되고 값의 나머지 부분을 일반 임포트 메커니즘을 사용하여 처리합니다.

이러한 접두사의 처리는 프로토콜 처리와 유사한 방식으로 수행됩니다: 정규식 ^(?P<prefix>[a-z]+)://(?P<suffix>.*)$와 일치하는 접두사를 찾는 일반 메커니즘이 있습니다. prefix가 인식되면 suffix는 접두사 종속적 방식으로 처리되고 처리 결과가 문자열 값을 대체합니다. 접두사가 인식되지 않으면, 문자열 값은 그대로 남습니다.

내부 객체에 대한 액세스

외부 객체뿐만 아니라, 때로 구성에 있는 객체를 참조할 필요도 있습니다. 이것은 구성 시스템이 알고 있는 것들에 대해 묵시적으로 수행됩니다. 예를 들어, 로거나 처리기의 level에 대한 문자열 값 'DEBUG'은 자동으로 값 logging.DEBUG으로 변환되고, handlers, filtersformatter 항목은 객체 id를 받아서 적절한 대상 객체로 결정합니다.

하지만, logging 모듈에 알려지지 않은 사용자 정의 객체에는 더욱 일반적인 메커니즘이 필요합니다. 예를 들어, 위임할 다른 처리기인 target 인자를 취하는 logging.handlers.MemoryHandler를 고려해봅시다. 시스템이 이미 이 클래스에 대해 알고 있으므로, 구성에서, 주어진 target은 단지 관련 target 처리기의 객체 id이기만 하면 되며, 시스템은 id로부터 처리기를 결정합니다. 그러나 사용자가 alternate 처리기를 갖는 my.package.MyHandler를 정의하면, 구성 시스템은 alternate가 처리기를 참조한다는 것을 알 수 없습니다. 이 문제를 해결하기 위해, 일반 결정 시스템은 사용자가 다음과 같이 지정할 수 있게 합니다:

handlers:
  file:
    # configuration of file handler goes here

  custom:
    (): my.package.MyHandler
    alternate: cfg://handlers.file

리터럴 문자열 'cfg://handlers.file'ext:// 접두사가 있는 문자열과 비슷하게 결정되지만, 임포트 이름 공간이 아닌 구성 자체를 조회합니다. 이 메커니즘은 str.format에서 제공하는 것과 유사한 방식으로 점이나 인덱스로 액세스하는 것을 허락합니다. 따라서, 구성에서 다음과 같은 조각이 주어질 때:

handlers:
  email:
    class: logging.handlers.SMTPHandler
    mailhost: localhost
    fromaddr: my_app@domain.tld
    toaddrs:
      - support_team@domain.tld
      - dev_team@domain.tld
    subject: Houston, we have a problem.

문자열 'cfg://handlers'는 키 handlers의 딕셔너리로 결정되고, 문자열 'cfg://handlers.emailhandlers 딕셔너리에 있는 키 email의 딕셔너리로 결정됩니다, 등등. 문자열 'cfg://handlers.email.toaddrs[1]'dev_team.domain.tld'로 결정되고 문자열 'cfg://handlers.email.toaddrs[0]'은 값 'support_team@domain.tld'로 결정됩니다. subject 값은 'cfg://handlers.email.subject'나 동등하게 'cfg://handlers.email[subject]'를 사용하여 액세스할 수 있습니다. 후자의 형식은 키에 공백이나 영숫자가 아닌 문자가 포함되어있을 때만 필요합니다. 인덱스값이 십진수로만 구성되면, 해당 정숫값을 사용하여 액세스가 시도되고, 필요하면 문자열 값으로 다시 시도합니다.

문자열 cfg://handlers.myhandler.mykey.123이 주어지면, config_dict['handlers']['myhandler']['mykey']['123']으로 변환됩니다. 문자열이 cfg://handlers.myhandler.mykey[123]로 지정되면, 시스템은 config_dict['handlers']['myhandler']['mykey'][123]에서 값을 가져오려고 시도하고, 실패하면 config_dict['handlers']['myhandler']['mykey']['123']으로 폴백합니다.

임포트 결정과 사용자 정의 임포터

임포트 결정은, 기본적으로, 임포트 하는데 내장 __import__() 함수를 사용합니다. 이것을 자신의 임포트 메커니즘으로 바꾸고 싶을 수 있습니다: 그렇다면, DictConfigurator나 그것의 슈퍼 클래스(BaseConfigurator 클래스)의 importer 어트리뷰트를 바꿀 수 있습니다. 그러나, 함수가 클래스에서 디스크립터를 통해 액세스 되는 방식 때문에 주의해야 합니다. 파이썬 콜러블을 사용하여 임포트를 수행하려고 하고, 인스턴스 수준이 아닌 클래스 수준에서 정의하려고 한다면, staticmethod()로 감쌀 필요가 있습니다. 예를 들면:

from importlib import import_module
from logging.config import BaseConfigurator

BaseConfigurator.importer = staticmethod(import_module)

구성자 instance에서 임포트 콜러블을 설정한다면, staticmethod()로 감쌀 필요가 없습니다.

구성 파일 형식

fileConfig()이 이해하는 구성 파일 형식은 configparser 기능을 기반으로 합니다. 파일에는 [loggers], [handlers][formatters]라는 섹션이 있어야 하며, 이 섹션에서는 파일에 정의된 각 유형의 엔티티를 이름으로 식별합니다. 이러한 엔티티마다 해당 엔티티 구성 방법을 식별하는 별도의 섹션이 있습니다. 따라서, [loggers] 섹션에서 log01이라고 이름 붙은 로거에 대해, 관련 구성 세부 사항은 [logger_log01] 섹션에 담깁니다. 마찬가지로, [handlers] 섹션에서 hand01이라고 부르는 처리기는 [handler_hand01]이라는 섹션에 구성이 담기고, [formatters] 섹션에서 form01이라고 부르는 포매터는 [formatter_form01]이라는 섹션에서 구성이 지정됩니다. 루트 로거 구성은 [logger_root]라는 섹션에서 지정해야 합니다.

참고

fileConfig() API는 dictConfig() API보다 오래되었으며 로깅의 특정 측면을 다루는 기능을 제공하지 않습니다. 예를 들어, fileConfig()를 사용해서는 간단한 정수 수준을 넘어서는 메시지 필터링을 제공하는 Filter 객체를 구성할 수 없습니다. 로깅 구성에 Filter 인스턴스가 필요하면, dictConfig()를 사용해야 합니다. 향후 구성 기능의 개선은 dictConfig()에 추가될 것임에 유의하십시오. 따라서, 편리할 때 이 새로운 API로 전환하는 것을 고려해 볼 가치가 있습니다.

파일에 있는 이 절의 예는 아래에 나와 있습니다.

[loggers]
keys=root,log02,log03,log04,log05,log06,log07

[handlers]
keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09

[formatters]
keys=form01,form02,form03,form04,form05,form06,form07,form08,form09

루트 로거는 수준과 처리기 목록을 지정해야 합니다. 루트 로거 섹션의 예가 아래에 나와 있습니다.

[logger_root]
level=NOTSET
handlers=hand01

level 항목은 DEBUG, INFO, WARNING, ERROR, CRITICAL 또는 NOTSET 중 하나일 수 있습니다. 루트 로거에서만, NOTSET는 모든 메시지가 로그 됨을 의미합니다. 수준 값은 logging 패키지의 이름 공간 컨텍스트에서 eval()됩니다.

handlers 항목은 [handlers] 섹션에 나타나야 하는 처리기 이름의 쉼표로 구분된 목록입니다. 이 이름들은 [handlers] 섹션에 나타나야 하며, 구성 파일에 해당 섹션이 있어야 합니다.

루트 로거가 아닌 로거의 경우, 몇 가지 추가 정보가 필요합니다. 이것은 다음 예제가 보여줍니다.

[logger_parser]
level=DEBUG
handlers=hand01
propagate=1
qualname=compiler.parser

levelhandlers 항목은 루트 로거에서처럼 해석됩니다. 단, 루트가 아닌 로거의 수준이 NOTSET로 지정되면, 시스템은 로거의 유효 수준을 판별하기 위해 상위 계층 로거를 참조합니다. propagate 항목은 메시지가 이 로거로부터 더 높은 로거 계층의 처리기로 전파되어야 함을 나타내려면 1로 설정되고, 메시지가 계층 위의 처리기로 전달되지 않음을 나타내려면 0으로 설정됩니다. qualname 항목은 로거의 계층적 채널 이름, 즉 응용 프로그램에서 로거를 가져오는 데 사용되는 이름입니다.

처리기 구성을 지정하는 섹션은 다음과 같이 예시됩니다.

[handler_hand01]
class=StreamHandler
level=NOTSET
formatter=form01
args=(sys.stdout,)

class 항목은 (logging 패키지의 이름 공간에서 eval()로 결정되는) 처리기의 클래스를 나타냅니다. level은 로거에서처럼 해석되며, NOTSET은 '모든 것을 로깅'을 의미합니다.

formatter 항목은 이 처리기의 포매터의 키 이름을 나타냅니다. 비어 있으면, 기본 포매터(logging._defaultFormatter)가 사용됩니다. 이름이 지정되면, [formatters] 섹션에 나타나야 하며 구성 파일에 해당 섹션이 있어야 합니다.

args 항목은, logging 패키지의 이름 공간 컨텍스트에서 eval()될 때, 처리기 클래스의 생성자에 대한 인자 목록입니다. 일반적인 항목 작성 방법을 보려면, 관련 처리기의 생성자나 아래 예제를 참조하십시오. 제공되지 않으면, 기본값은 ()입니다.

선택적 kwargs 항목은, logging 패키지의 이름 공간 컨텍스트에서 eval()될 때, 처리기 클래스의 생성자에 대한 키워드 인자 딕셔너리입니다. 제공되지 않으면, 기본값은 {}입니다.

[handler_hand02]
class=FileHandler
level=DEBUG
formatter=form02
args=('python.log', 'w')

[handler_hand03]
class=handlers.SocketHandler
level=INFO
formatter=form03
args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)

[handler_hand04]
class=handlers.DatagramHandler
level=WARN
formatter=form04
args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)

[handler_hand05]
class=handlers.SysLogHandler
level=ERROR
formatter=form05
args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)

[handler_hand06]
class=handlers.NTEventLogHandler
level=CRITICAL
formatter=form06
args=('Python Application', '', 'Application')

[handler_hand07]
class=handlers.SMTPHandler
level=WARN
formatter=form07
args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
kwargs={'timeout': 10.0}

[handler_hand08]
class=handlers.MemoryHandler
level=NOTSET
formatter=form08
target=
args=(10, ERROR)

[handler_hand09]
class=handlers.HTTPHandler
level=NOTSET
formatter=form09
args=('localhost:9022', '/log', 'GET')
kwargs={'secure': True}

포매터 구성을 지정하는 섹션은 다음과 같이 예시됩니다.

[formatter_form01]
format=F1 %(asctime)s %(levelname)s %(message)s
datefmt=
class=logging.Formatter

format 항목은 전체 포맷 문자열이고, datefmt 항목은 strftime() 호환 날짜/시간 포맷 문자열입니다. 비어있으면, 패키지는 날짜 포맷 문자열 '%Y-%m-%d %H:%M:%S'를 지정하는 것과 거의 동등한 것으로 대체합니다. 이 포맷은 밀리 초도 지정하는데, 위의 포맷 문자열을 사용한 결과에 쉼표 구분 기호와 함께 추가됩니다. 이 포맷의 예제 시간은 2003-01-23 00:29:50,411입니다.

class 항목은 선택적입니다. 포매터 클래스의 이름을 나타냅니다 (점으로 구분된 모듈과 클래스 이름). 이 옵션은 Formatter 서브 클래스를 인스턴스화하는 데 유용합니다. Formatter의 서브 클래스는 확장 또는 압축 형식으로 예외 트래이스백을 표시할 수 있습니다.

참고

위에서 설명한 대로 eval()를 사용하기 때문에, listen()을 사용하여 소켓을 통해 구성을 보내고 받을 때 발생할 수 있는 잠재적인 보안 위험이 있습니다. 위험은 상호 신뢰가 없는 여러 사용자가 같은 기계에서 코드를 실행할 때로 제한됩니다; 자세한 내용은 listen() 설명서를 참조하십시오.

더 보기

모듈 logging

logging 모듈에 관한 API 레퍼런스.

모듈 logging.handlers

logging 모듈에 포함된 유용한 처리기.