logging — Python 로깅 기능

logging — Python 로깅 기능

애플리케이션과 라이브러리를 위한 유연한 이벤트 로깅 시스템을 구현한 모듈이에요. 표준 라이브러리로 로깅 API를 제공하는 가장 큰 이점은 모든 Python 모듈이 로깅에 참여할 수 있다는 점이라, 여러분의 애플리케이션 로그에 내가 만든 메시지뿐 아니라 서드파티 모듈의 메시지까지 함께 담을 수 있어요. 이 페이지는 API 레퍼런스 정보를 담고 있어요. 튜토리얼과 고급 주제는 Basic Tutorial, Advanced Tutorial, Logging Cookbook을 참고하세요.

출처: Python 표준 라이브러리

본문

관용적인 사용법

다음은 관용적인 사용의 간단한 예시예요.

# myapp.py
import logging
import mylib
logger = logging.getLogger(__name__)

def main():
    logging.basicConfig(filename='myapp.log', level=logging.INFO)
    logger.info('Started')
    mylib.do_something()
    logger.info('Finished')

if __name__ == '__main__':
    main()
# mylib.py
import logging
logger = logging.getLogger(__name__)

def do_something():
    logger.info('Doing something')

myapp.py를 실행하면 myapp.log에 다음과 같은 내용이 보여요.

INFO:__main__:Started
INFO:mylib:Doing something
INFO:__main__:Finished

이 관용적 사용법의 핵심은 대부분의 코드가 getLogger(__name__)으로 모듈 레벨 로거를 만들고 그 로거로 필요한 로깅을 한다는 점이에요. 이 방식은 간결하면서도 필요할 때 하위 코드가 세밀하게 제어할 수 있게 해주죠. 모듈 레벨 로거에 기록된 메시지는 더 상위 모듈의 로거 핸들러로 전달되고, 궁극적으로는 루트 로거(root logger)라 불리는 최상위 로거까지 올라가요. 이런 방식을 계층적 로깅(hierarchical logging)이라고 해요.

로깅이 유용하려면 설정이 필요해요. 각 로거의 레벨과 목적지를 정하고, 특정 모듈이 어떻게 로그할지 바꿀 수도 있죠. 보통은 명령줄 인자나 애플리케이션 설정에 기반해요. 대부분의 경우 위 예시처럼 루트 로거만 설정하면 돼요. 모듈 레벨의 하위 로거들이 결국 그 핸들러로 메시지를 전달하거든요. basicConfig()는 많은 사용 사례를 처리하는 루트 로거 설정의 빠른 방법을 제공해요.

이 모듈이 정의하는 기본 클래스는 다음과 같이 나뉘어요.

  • Loggers — 애플리케이션 코드가 직접 사용하는 인터페이스.
  • Handlers — (로거가 만든) 로그 레코드를 적절한 목적지로 보내는 역할.
  • Filters — 어떤 로그 레코드를 출력할지 결정하는 더 세밀한 기능.
  • Formatters — 최종 출력에서 로그 레코드의 배치(레이아웃)를 지정.

Logger 객체

Logger는 다음 속성과 메서드를 가져요. 로거는 절대 직접 인스턴스화하면 안 되고, 항상 모듈 레벨 함수 logging.getLogger(name)으로 만들어야 해요. 같은 이름으로 getLogger()를 여러 번 호출해도 항상 같은 Logger 객체를 돌려줘요.

이름은 foo.bar.baz처럼 점으로 구분된 계층 값이 될 수 있어요(물론 그냥 foo 같은 평이한 이름도 돼요). 계층 목록에서 더 아래쪽에 있는 로거는 위쪽 로거의 자식이에요. 예를 들어 foo라는 로거가 있을 때 foo.bar, foo.bar.baz, foo.bam은 모두 foo의 하위 로거예요. 또 모든 로거는 루트 로거의 하위예요. 로거 이름 계층은 Python 패키지 계층과 유사하며, 권장 방식인 logging.getLogger(__name__)을 사용해 모듈별로 로거를 구성하면 완전히 일치해요. 모듈 안에서 __name__은 Python 패키지 네임스페이스에서의 모듈 이름이기 때문이에요.

클래스와 속성

class logging.Logger

  • name — 로거의 이름. getLogger()에 전달된 값이에요. (읽기 전용으로 취급해야 해요.)
  • levelsetLevel() 메서드가 설정한 이 로거의 임계값. 직접 설정하지 말고 항상 setLevel()을 사용하세요. 전달된 레벨을 검사하기 때문이에요.
  • parent — 이 로거의 부모 로거. 네임스페이스 계층에서 더 위쪽에 있는 로거가 나중에 인스턴스화되면 바뀔 수 있어요. (읽기 전용으로 취급.)
  • propagate — 이 속성이 참으로 평가되면 이 로거에 기록된 이벤트가 이 로거에 붙은 핸들러뿐 아니라 더 높은(조상) 로거의 핸들러로도 전달돼요. 메시지는 조상 로거의 핸들러로 직접 전달되며, 해당 조상 로거의 레벨이나 필터는 고려하지 않아요. 거짓이면 조상 로거의 핸들러로 전달되지 않아요. 생성자는 이 속성을 True로 설정해요.

예를 들어 A.B.C라는 로거의 propagate가 참이면, logging.getLogger('A.B.C').error(...) 같은 호출로 기록된 이벤트는 A.B.C에 붙은 핸들러에 먼저 전달된 뒤, A.B, A, 루트 로거에 붙은 핸들러로 차례로 전달돼요. 체인 A.B.C, A.B, A 중 어떤 로거의 propagate가 거짓이면 그 로거가 이벤트 처리를 제안받는 마지막 로거가 되고 전파는 거기서 멈춰요.

참고: 한 로거와 그 조상 중 하나 이상에 핸들러를 붙이면 같은 레코드가 여러 번 출력될 수 있어요. 일반적으로는 로거 하나 이상에 핸들러를 붙일 필요가 없어요. 로거 계층에서 가장 높은 적절한 로거에만 붙이면, 하위 로거의 propagateTrue로 남아 있는 한 모든 하위 로거가 기록한 이벤트를 볼 수 있어요. 흔한 시나리오는 루트 로거에만 핸들러를 붙이고 나머지는 전파에 맡기는 거예요.

  • handlers — 이 로거 인스턴스에 직접 붙은 핸들러 목록. (읽기 전용으로 취급. 보통 addHandler()removeHandler()를 통해 바뀌며, 이들은 스레드 안전을 위해 락을 사용해요.)
  • disabled — 모든 이벤트 처리를 비활성화하는 속성. 초기화 시 False로 설정되고 로깅 설정 코드에 의해서만 바뀌어요. (읽기 전용으로 취급.)

메서드

  • setLevel(level) — 이 로거의 임계값을 level로 설정해요. level보다 심각도가 낮은 로깅 메시지는 무시되고, level 이상인 메시지는 이 로거를 서비스하는 핸들러에 의해 출력돼요(단, 핸들러의 레벨이 level보다 높게 설정되지 않은 경우). 로거가 생성되면 레벨은 NOTSET으로 설정돼요. 이 경우 루트 로거면 모든 메시지가 처리되고, 루트가 아니면 부모에게 위임되죠. 루트 로거는 레벨 WARNING으로 생성된다는 점을 기억하세요. '부모에게 위임'이란 로거가 NOTSET일 때 조상 로거 체인을 따라 NOTSET이 아닌 조상을 찾거나 루트에 도달할 때까지 탐색하는 것을 말해요. NOTSET이 아닌 조상을 찾으면 그 조상의 레벨이 시작 지점 로거의 유효 레벨(effective level)로 사용돼요. 루트에 도달했는데 레벨이 NOTSET이면 모든 메시지가 처리되고, 아니면 루트의 레벨이 유효 레벨로 쓰여요.

    버전 3.2에서 변경: level 매개변수는 이제 INFO 같은 문자열 표현도 받아요. 다만 레벨은 내부적으로 정수로 저장되며, getEffectiveLevel()이나 isEnabledFor() 같은 메서드는 정수를 반환/기대해요.

  • isEnabledFor(level) — 심각도 level의 메시지가 이 로거에서 처리될지 여부를 알려줘요. 먼저 logging.disable(level)이 설정한 모듈 레벨을 확인하고, 다음으로 getEffectiveLevel()이 정한 유효 레벨을 확인해요.

  • getEffectiveLevel() — 이 로거의 유효 레벨을 알려줘요. setLevel()NOTSET이 아닌 값이 설정돼 있으면 그 값을 반환하고, 아니면 루트를 향해 계층을 탐색해 NOTSET이 아닌 값을 찾아 반환해요. 반환값은 정수로, 보통 logging.DEBUG, logging.INFO 등이에요.

  • getChild(suffix)suffix에 따라 이 로거의 하위 로거를 반환해요. logging.getLogger('abc').getChild('def.ghi')logging.getLogger('abc.def.ghi')가 반환하는 것과 같은 로거예요. 부모 로거를 리터럴 문자열이 아니라 __name__ 같은 것으로 이름지었을 때 유용한 편의 메서드예요. (버전 3.2에 추가.)

  • getChildren() — 이 로거의 바로 아래 자식 로거들의 집합을 반환해요. 예를 들어 logging.getLogger().getChildren()foobar는 포함하지만 foo.bar는 포함하지 않을 수 있어요. (버전 3.12에 추가.)

  • debug(msg, *args, **kwargs) — 이 로거에 레벨 DEBUG로 메시지를 기록해요. msg는 메시지 포맷 문자열이고, args는 문자열 포매팅 연산자로 msg에 합쳐지는 인자예요. args를 제공하지 않으면 msg% 포매팅을 수행하지 않아요. 검사되는 키워드 인자는 네 가지예요: exc_info, stack_info, stacklevel, extra.

    • exc_info가 거짓으로 평가되지 않으면 예외 정보가 로깅 메시지에 추가돼요. 예외 튜플(sys.exc_info() 형식)이나 예외 인스턴스가 주어지면 그걸 사용하고, 아니면 sys.exc_info()를 호출해 얻어요.

    • stack_info(기본값 False)가 참이면 실제 로깅 호출을 포함한 스택 정보가 추가돼요. exc_info로 표시되는 스택 정보와는 달라요. 전자는 현재 스레드에서 스택 바닥부터 로깅 호출까지의 프레임이고, 후자는 예외를 따라 되감은(unwound) 프레임 정보예요. stack_infoexc_info와 독립적으로 지정할 수 있어요. 스택 프레임은 다음 헤더 줄 뒤에 출력돼요.

      Stack (most recent call last):
      

      이는 예외 프레임 표시에 쓰이는 Traceback (most recent call last):를 흉내 낸 거예요.

    • stacklevel(기본값 1)이 1보다 크면, 만들어지는 LogRecord의 줄 번호와 함수 이름을 계산할 때 그만큼의 스택 프레임을 건너뛰어요. 로깅 헬퍼에서 사용하면 기록되는 함수 이름·파일 이름·줄 번호가 헬퍼가 아니라 호출자를 가리키게 돼요. 이 매개변수 이름은 warnings 모듈의 것과 동일해요.

    • extra는 로깅 이벤트로 생성된 LogRecord__dict__를 사용자 정의 속성으로 채우는 데 쓰는 딕셔너리예요. 예를 들어:

      FORMAT = '%(asctime)s %(clientip)-15s %(user)-8s %(message)s'
      logging.basicConfig(format=FORMAT)
      d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
      logger = logging.getLogger('tcpserver')
      logger.warning('Protocol problem: %s', 'connection reset', extra=d)
      

      이런 출력이 나와요.

      2006-02-08 22:20:02,165 192.168.0.1 fbloggs  Protocol problem: connection reset
      

      extra에 넘긴 딕셔너리 키는 로깅 시스템이 쓰는 키와 겹치면 안 돼요. 또 해당 키들이 LogRecord 속성 딕셔너리에 없으면 문자열 포매팅 예외가 나서 메시지가 기록되지 않으니 주의하세요. 이 기능은 멀티스레드 서버처럼 같은 코드가 여러 문맥에서 실행되고 흥미로운 조건이 문맥(예: 원격 클라이언트 IP, 인증된 사용자 이름)에 의존하는 특수한 상황을 위해 만들어졌어요.

    • 이 로거(또는 Logger.propagate 속성을 고려한 조상)에 핸들러가 없으면 메시지는 lastResort에 설정된 핸들러로 보내져요.

    버전 3.2에서 변경: stack_info 매개변수 추가. 버전 3.5에서 변경: exc_info가 예외 인스턴스도 받게 됨. 버전 3.8에서 변경: stacklevel 매개변수 추가.

  • info(msg, *args, **kwargs) — 레벨 INFO로 기록. 인자는 debug()와 동일하게 해석돼요.

  • warning(msg, *args, **kwargs) — 레벨 WARNING으로 기록. 인자는 debug()와 동일.

    참고: 기능적으로 동일한 구식 메서드 warn이 있어요. warn은 폐기 예정이니 사용하지 말고 warning을 쓰세요.

  • error(msg, *args, **kwargs) — 레벨 ERROR로 기록. (인자는 debug()와 동일)

  • critical(msg, *args, **kwargs) — 레벨 CRITICAL로 기록. (인자는 debug()와 동일)

  • log(level, msg, *args, **kwargs) — 정수 레벨 level로 기록. (다른 인자는 debug()와 동일)

  • exception(msg, *args, **kwargs) — 레벨 ERROR로 기록하고 예외 정보를 추가해요. 예외 핸들러 안에서만 호출해야 해요.

  • addFilter(filter) — 지정한 필터 filter를 이 로거에 추가해요.

  • removeFilter(filter) — 지정한 필터 filter를 이 로거에서 제거해요.

  • filter(record) — 이 로거의 필터를 record에 적용해, 처리할 레코드면 True를 반환해요. 필터는 하나가 거짓 값을 반환할 때까지 차례로 검사돼요. 모두 참이면 레코드가 처리(핸들러로 전달)되고, 하나라도 거짓이면 더는 처리되지 않아요.

  • addHandler(hdlr) — 지정한 핸들러 hdlr를 추가해요.

  • removeHandler(hdlr) — 지정한 핸들러 hdlr를 제거해요.

  • findCaller(stack_info=False, stacklevel=1) — 호출자의 소스 파일 이름과 줄 번호를 찾아요. (파일 이름, 줄 번호, 함수 이름, 스택 정보) 4-요소 튜플을 반환해요. stack_infoTrue가 아니면 스택 정보는 None으로 반환돼요. stacklevel이 1보다 크면 그만큼 스택 프레임을 건너뛰고 값을 결정해요.

  • handle(record) — 이 로거와 그 조상(거짓 propagate를 만날 때까지)의 모든 핸들러에 레코드를 전달해 처리해요. 소켓에서 받은 unpickle 레코드와 로컬에서 만든 레코드 모두에 쓰여요. 로거 레벨 필터링은 filter()로 적용돼요.

  • makeRecord(name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None) — 하위 클래스에서 전문적인 LogRecord 인스턴스를 만들도록 오버라이드할 수 있는 팩토리 메서드예요.

  • hasHandlers() — 이 로거에 핸들러가 설정돼 있는지 확인해요. 이 로거와 로거 계층의 부모에서 핸들러를 찾아요. 핸들러를 찾으면 True, 아니면 False. propagate가 거짓으로 설정된 로거를 만나면 그만 탐색해요. (버전 3.2 추가.)

    버전 3.7에서 변경: 로거를 피클링/언피클링할 수 있게 됨.

로깅 레벨

로깅 레벨의 숫자 값은 다음 표와 같아요. 이는 주로 자신만의 레벨을 정의하려고 할 때, 미리 정의된 레벨과의 상대적 값이 필요할 때 관심이 있어요. 같은 숫자 값의 레벨을 정의하면 미리 정의된 값을 덮어쓰고, 그 이름은 사라져요.

레벨 숫자 값 의미 / 사용 시점
logging.NOTSET 0 로거에 설정되면 조상 로거가 유효 레벨을 결정하도록 함을 나타냄. 그래도 NOTSET으로 해석되면 모든 이벤트가 기록됨. 핸들러에 설정되면 모든 이벤트가 처리됨.
logging.DEBUG 10 상세 정보. 보통 문제를 진단하려는 개발자에게만 관심 있음.
logging.INFO 20 일이 기대대로 진행되고 있음을 확인.
logging.WARNING 30 예상치 못한 일이 일어났거나, 가까운 미래에 문제('디스크 공간 부족' 등)가 생길 수 있음을 알림. 소프트웨어는 여전히 기대대로 작동 중.
logging.ERROR 40 더 심각한 문제로 인해 소프트웨어가 일부 기능을 수행하지 못했음.
logging.CRITICAL 50 프로그램 자체가 계속 실행되지 못할 수도 있는 심각한 오류.

Handler 객체

Handler는 다음 속성과 메서드를 가져요. Handler는 직접 인스턴스화되지 않으며, 더 유용한 하위 클래스들을 위한 기반 클래스 역할을 해요. 하위 클래스의 __init__()Handler.__init__()을 호출해야 해요.

class logging.Handler

  • __init__(level=NOTSET) — Handler 인스턴스를 초기화해요. 레벨을 설정하고 필터 목록을 빈 리스트로 만들며, I/O 메커니즘 접근을 직렬화하기 위해 createLock()으로 락을 만들어요.

  • createLock() — 스레드 안전하지 않을 수 있는 기본 I/O 기능 접근을 직렬화하는 데 쓸 스레드 락을 초기화해요.

  • acquire()createLock()으로 만든 스레드 락을 획득해요.

  • release()acquire()로 획득한 스레드 락을 해제해요.

  • setLevel(level) — 이 핸들러의 임계값을 level로 설정해요. level보다 심각도가 낮은 메시지는 무시돼요. 생성 시 레벨은 NOTSET(모든 메시지 처리)으로 설정돼요. (버전 3.2: 문자열 표현도 받게 됨)

  • setFormatter(fmt) — 이 핸들러의 포매터를 fmt로 설정해요. fmtFormatter 인스턴스 또는 None이어야 해요.

  • addFilter(filter) / removeFilter(filter) — 이 핸들러에 필터를 추가/제거해요.

  • filter(record) — 이 핸들러의 필터를 record에 적용해 True면 처리할 레코드로 판단해요. 하나가 거짓을 반환하면 핸들러는 레코드를 출력하지 않아요.

  • flush() — 모든 로깅 출력이 플러시되도록 해요. 이 기본 버전은 아무것도 하지 않으며 하위 클래스가 구현하도록 되어 있어요.

  • close() — 핸들러가 쓰는 리소스를 정리해요. 이 버전은 출력은 하지 않지만 이름으로 핸들러를 찾는 데 쓰는 내부 핸들러 맵에서 핸들러를 제거해요. 하위 클래스는 오버라이드된 close()에서 이 메서드가 호출되도록 해야 해요.

  • handle(record) — 핸들러에 추가된 필터에 따라 지정한 레코드를 조건부로 출력해요. 실제 출력을 I/O 스레드 락 획득/해제로 감싸요.

  • handleError(record)emit() 호출 중 예외가 발생하면 핸들러에서 호출해야 해요. 모듈 레벨 속성 raiseExceptionsFalse면 예외는 조용히 무시돼요. 이는 로깅 시스템에서 대부분 원하는 동작이에요(대부분의 사용자는 애플리케이션 오류에 관심이 있지 로깅 시스템의 오류엔 관심이 없으니까요). 원하면 커스텀 핸들러로 바꿀 수도 있어요. record는 예외 발생 당시 처리 중이던 레코드예요. (raiseExceptions 기본값은 True인데, 개발 중에 더 유용하기 때문이에요.)

  • format(record) — 레코드 포매팅을 해요. 포매터가 설정돼 있으면 쓰고, 아니면 모듈의 기본 포매터를 사용해요.

  • emit(record) — 지정한 로그 레코드를 실제로 기록하기 위한 작업을 해요. 이 버전은 하위 클래스가 구현하도록 설계돼 있어 NotImplementedError를 일으켜요.

    경고: 이 메서드는 핸들러 레벨 락이 획득된 후 호출되고, 메서드 반환 후에 풀려요. 오버라이드할 때 락을 잡을 수 있는 로깅 API의 다른 부분을 호출하지 않도록 주의하세요. 교착 상태(deadlock)가 생길 수 있어요. 구체적으로: 로깅 설정 API는 모듈 레벨 락을 획득한 다음 각 핸들러를 설정하면서 핸들러 레벨 락을 획득해요. 많은 로깅 API가 모듈 레벨 락을 잠가요. 이 메서드에서 그런 API를 호출하면, 다른 스레드가 설정 호출을 하는 경우 교착 상태가 될 수 있어요.

표준으로 포함된 핸들러 목록은 logging.handlers를 참고하세요.

Formatter 객체

class logging.Formatter(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)LogRecord를 사람이나 외부 시스템이 해석할 출력 문자열로 변환하는 역할을 해요.

매개변수:

  • fmt (str) — 주어진 스타일의 포맷 문자열. 가능한 매핑 키는 LogRecord 속성에서 따와요. 지정하지 않으면 '%(message)s)'(그냥 기록된 메시지)가 사용돼요.
  • datefmt (str) — 기록 출력의 날짜/시간 부분 포맷 문자열. 지정하지 않으면 formatTime()에 설명된 기본값을 사용해요.
  • style (str) — '%', '{', '$' 중 하나. 포맷 문자열이 데이터와 합쳐지는 방식을 정해요: printf 스타일 String Formatting (%), str.format() ({), string.Template ($). 이는 fmt에만 적용되며(예: '%(message)s''{message}'), 실제 로그 메시지에는 적용되지 않아요.
  • validate (bool) — True(기본값)면 잘못되었거나 불일치하는 fmtstyleValueError를 일으켜요. 예: logging.Formatter('%(asctime)s - %(message)s', style='{').
  • defaults (dict[str, Any]) — 커스텀 필드에 쓸 기본값 딕셔너리. 예: logging.Formatter('%(ip)s %(message)s', defaults={"ip": None}).

버전 3.2에서 style 추가, 버전 3.8에서 validate 추가, 버전 3.10에서 defaults 추가.

  • format(record) — 레코드의 속성 딕셔너리를 문자열 포매팅 연산의 피연산자로 사용해 결과 문자열을 반환해요. 포매팅 전에 준비 단계가 있어요. message 속성은 msg % args로 계산되고, 포맷 문자열이 '(asctime)'을 포함하면 formatTime()으로 이벤트 시간을 포맷해요. 예외 정보가 있으면 formatException()으로 포맷해 메시지에 덧붙여요. 포맷된 예외 정보는 exc_text 속성에 캐시돼요. 예외 정보를 피클해 네트워크로 보낼 수 있어 유용하지만, 예외 정보 포매팅을 커스텀하는 Formatter 하위 클래스가 여러 개면 캐시된 값을 None으로 지워야 다음 포매터가 새로 계산해요.
  • formatTime(record, datefmt=None) — 포매터가 포맷된 시간을 쓰려고 format()에서 호출해요. 기본 동작은 datefmt(문자열)가 지정되면 time.strftime()으로 레코드 생성 시간을 포맷하고, 아니면 '%Y-%m-%d %H:%M:%S,uuu'를 사용해요. uuu는 밀리초 값이에요. 예: 2003-01-23 00:29:50,411. 기본적으로 time.localtime()을 쓰는데, 특정 포매터 인스턴스에 대해 converter 속성을 time.localtime()이나 time.gmtime()과 같은 시그니처의 함수로 바꿀 수 있어요. 모든 포매터에 적용하려면 Formatter 클래스의 converter 속성을 바꾸세요.

    버전 3.3에서 변경: 기본 포맷이 하드코딩되던 것에서 클래스 레벨 속성으로 바뀜. 속성 이름은 default_time_format(strptime 포맷 문자열)과 default_msec_format(밀리초 값 덧붙이기). 버전 3.9에서 변경: default_msec_formatNone이 될 수 있음.

  • formatException(exc_info) — 지정한 예외 정보(sys.exc_info()가 반환하는 표준 예외 튜플)를 문자열로 포맷해요. 기본 구현은 traceback.print_exception()을 사용해요.
  • formatStack(stack_info) — 지정한 스택 정보(마지막 개행이 제거된 traceback.print_stack() 문자열)를 문자열로 포맷해요. 기본 구현은 입력 값을 그대로 반환해요.

class logging.BufferingFormatter(linefmt=None) — 많은 레코드를 포맷하려고 하위 분류할 수 있는 기본 포매터 클래스예요. 각 줄(단일 레코드)을 포맷할 Formatter 인스턴스를 넘길 수 있어요. 지정하지 않으면 기본 포매터(이벤트 메시지만 출력)가 줄 포매터로 쓰여요.

  • formatHeader(records) — 레코드 목록의 헤더를 반환해요. 기본 구현은 빈 문자열만 반환해요. 레코드 수, 제목, 구분선을 보여주려면 오버라이드하세요.
  • formatFooter(records) — 레코드 목록의 푸터를 반환해요. 기본 구현은 빈 문자열.
  • format(records) — 레코드 목록의 포맷된 텍스트를 반환해요. 레코드가 없으면 빈 문자열, 있으면 헤더 + 각 레코드(줄 포매터로 포맷) + 푸터를 연결해요.

Filter 객체

Filter는 레벨보다 정교한 필터링을 위해 Handler와 Logger에서 쓸 수 있어요. 기본 필터 클래스는 로거 계층의 특정 지점 아래 이벤트만 허용해요. 예를 들어 'A.B'로 초기화된 필터는 'A.B', 'A.B.C', 'A.B.C.D', 'A.B.D' 등 로거가 기록한 이벤트는 허용하지만 'A.BB', 'B.A.B' 등은 허용하지 않아요. 빈 문자열로 초기화하면 모든 이벤트를 통과시켜요.

class logging.Filter(name='') — Filter 클래스 인스턴스를 반환해요. name을 지정하면 그 로거와 자식 로거의 이벤트를 필터가 통과시켜요. 빈 문자열이면 모든 이벤트를 허용해요.

  • filter(record) — 지정한 레코드를 기록할지 여부. 아니오면 거짓, 예면 참을 반환해요. 필터는 로그 레코드를 제자리에서 수정하거나, 원본을 대체할 완전히 다른 레코드 인스턴스를 반환할 수도 있어요.

핸들러에 붙은 필터는 이벤트가 핸들러에 의해 출력되기 전에 검사되고, 로거에 붙은 필터는 이벤트가 기록될 때(debug(), info() 등) 핸들러로 보내기 전에 검사돼요. 이 말은 하위 로거가 생성한 이벤트는 필터가 그 하위 로거에도 적용되지 않는 한 로거의 필터 설정으로 걸러지지 않는다는 뜻이에요.

실제로 Filter를 하위 분류할 필요는 없어요. 같은 의미의 filter 메서드를 가진 어떤 인스턴스든 넘길 수 있어요.

버전 3.2에서 변경: 함수(또는 callable)를 필터로 쓸 수 있게 됨. 필터 객체에 filter 속성이 있으면 Filter로 보고 해당 filter() 메서드를 호출하고, 아니면 callable로 간주해 레코드를 유일한 매개변수로 호출해요. 버전 3.12에서 변경: 필터에서 LogRecord 인스턴스를 반환해 레코드를 제자리에서 수정하는 대신 교체할 수 있게 됨. Handler에 붙은 필터가 다른 핸들러에 부수 효과 없이 출력 전에 레코드를 수정할 수 있어요.

필터는 주로 레벨보다 정교한 기준으로 레코드를 걸러내는 데 쓰지만, 붙은 핸들러나 로거가 처리하는 모든 레코드를 볼 수 있어서 레코드 개수 세기, 처리 중인 LogRecord의 속성 추가·변경·제거 같은 작업에도 유용해요.

LogRecord 객체

LogRecord 인스턴스는 무언가 기록될 때마다 Logger가 자동으로 만들고, makeLogRecord()로 수동으로 만들 수도 있어요(예: 네트워크로 받은 피클된 이벤트).

class logging.LogRecord(name, level, pathname, lineno, msg, args, exc_info, func=None, sinfo=None) — 기록되는 이벤트와 관련된 모든 정보를 담아요. 핵심 정보는 msgargs로 전달되며, msg % args로 합쳐져 레코드의 message 속성이 만들어져요.

매개변수:

  • name (str) — 이 LogRecord가 나타내는 이벤트를 기록한 로거 이름. 다른(조상) 로거에 붙은 핸들러가 출력해도 LogRecord의 로거 이름은 항상 이 값이에요.

  • level (int) — 로깅 이벤트의 숫자 레벨(예: DEBUG는 10, INFO는 20). LogRecord의 두 속성으로 변환돼요: 숫자 값 levelno와 이름 levelname.

  • pathname (str) — 로깅 호출이 일어난 소스 파일의 전체 문자열 경로.

  • lineno (int) — 로깅 호출이 일어난 소스 파일의 줄 번호.

  • msg (Any) — 이벤트 설명 메시지. 변수 데이터를 위한 %-포맷 문자열이거나 임의의 객체일 수 있어요.

  • args (tuple | dict[str, Any]) — msg 인자에 합쳐져 이벤트 설명을 얻는 변수 데이터.

  • exc_info (tuple[type[BaseException], BaseException, types.TracebackType] | None) — sys.exc_info()가 반환하는 현재 예외 정보의 예외 튜플, 또는 예외 정보가 없으면 None.

  • func (str | None) — 로깅 호출이 발생한 함수/메서드 이름.

  • sinfo (str | None) — 현재 스레드의 스택 바닥부터 로깅 호출까지의 스택 정보를 나타내는 텍스트 문자열.

  • getMessage() — 사용자가 제공한 인자를 메시지에 합친 뒤 이 LogRecord 인스턴스의 메시지를 반환해요. 메시지가 문자열이 아니면 str()로 변환해요. 사용자 정의 클래스를 메시지로 쓰면 __str__ 메서드가 실제 포맷 문자열을 반환할 수 있어요.

버전 3.2에서 변경: 레코드를 만드는 팩토리를 제공해 LogRecord 생성을 더 설정 가능하게 만듦. 팩토리는 getLogRecordFactory()setLogRecordFactory()로 설정할 수 있어요. 생성 시점에 자신만의 값을 LogRecord에 넣을 수 있어요:

old_factory = logging.getLogRecordFactory()

def record_factory(*args, **kwargs):
    record = old_factory(*args, **kwargs)
    record.custom_attribute = 0xdecafbad
    return record

logging.setLogRecordFactory(record_factory)

이 패턴으로 팩토리를 여러 개 이어 붙일 수 있어요. 서로의 속성이나 위의 표준 속성을 덮어쓰지만 않으면 문제없어요.

LogRecord 속성

LogRecord는 여러 속성을 가지며, 대부분 생성자 매개변수에서 파생돼요. 이 속성들은 레코드의 데이터를 포맷 문자열에 합치는 데 쓰여요. 다음 표는 속성 이름, 의미, %-스타일 포맷 문자열에서의 placeholder를 알파벳순으로 나열해요.

{}-포매팅(str.format())을 쓰면 {attrname}을, $-포매팅(string.Template)을 쓰면 ${attrname} 형식을 placeholder로 써요. {}-포매팅에서는 콜론으로 구분해 속성 이름 뒤에 포매팅 플래그를 지정할 수 있어요. 예: {msecs:03.0f}는 밀리초 값 4를 004로 포맷해요.

속성 이름 포맷 설명
args (직접 포맷할 필요 없음) message를 만들기 위해 msg에 합쳐진 인자 튜플, 또는 병합에 쓰이는 값의 딕셔너리(인자가 하나뿐이고 딕셔너리일 때).
asctime %(asctime)s LogRecord가 생성된 사람이 읽을 수 있는 시간. 기본 형식은 '2003-07-08 16:49:45,896'(쉼표 뒤는 밀리초).
created %(created)f LogRecord가 생성된 시간(time.time_ns() / 1e9 반환값).
exc_info (직접 포맷할 필요 없음) 예외 튜플(sys.exc_info 방식), 예외가 없었으면 None.
exc_text (직접 포맷할 필요 없음) 문자열로 포맷된 예외 정보. Formatter.format()이 호출될 때 설정되며, 예외가 없으면 None.
filename %(filename)s pathname의 파일 이름 부분.
funcName %(funcName)s 로깅 호출을 담고 있는 함수 이름.
levelname %(levelname)s 메시지의 텍스트 로깅 레벨('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
levelno %(levelno)s 메시지의 숫자 로깅 레벨(DEBUG, INFO, WARNING, ERROR, CRITICAL).
lineno %(lineno)d 로깅 호출이 발행된 소스 줄 번호(가능한 경우).
message %(message)s msg % args로 계산된 기록된 메시지. Formatter.format()이 호출될 때 설정됨.
module %(module)s 모듈(filename의 이름 부분).
msecs %(msecs)d LogRecord가 생성된 시간의 밀리초 부분.
msg (직접 포맷할 필요 없음) 원래 로깅 호출에서 전달된 포맷 문자열. args와 합쳐져 message가 되거나, 임의의 객체.
name %(name)s 호출을 기록한 로거 이름.
pathname %(pathname)s 로깅 호출이 발행된 소스 파일의 전체 경로(가능한 경우).
process %(process)d 프로세스 ID(가능한 경우).
processName %(processName)s 프로세스 이름(가능한 경우).
relativeCreated %(relativeCreated)d logging 모듈이 로드된 시점을 기준으로 LogRecord가 생성된 시간(밀리초).
stack_info (직접 포맷할 필요 없음) 현재 스레드의 스택 바닥부터, 이 레코드를 만든 로깅 호출의 스택 프레임까지의 스택 프레임 정보(가능한 경우).
thread %(thread)d 스레드 ID(가능한 경우).
threadName %(threadName)s 스레드 이름(가능한 경우).
taskName %(taskName)s asyncio.Task 이름(가능한 경우).

버전 3.1에서 processName 추가, 버전 3.12에서 taskName 추가.

LoggerAdapter 객체

LoggerAdapter 인스턴스는 문맥 정보를 로깅 호출에 편리하게 전달하는 데 쓰여요.

class logging.LoggerAdapter(logger, extra=None, merge_extra=False) — 기본 Logger 인스턴스, 선택적 딕셔너리류 객체(extra), 그리고 개별 로그 호출의 extra 인자를 LoggerAdapterextra와 병합할지 여부를 나타내는 선택적 불리언(merge_extra)으로 초기화된 인스턴스를 반환해요. 기본 동작은 개별 로그 호출의 extra 인자를 무시하고 LoggerAdapter 인스턴스의 것만 사용해요.

  • process(msg, kwargs) — 문맥 정보를 넣기 위해 로깅 호출에 전달되는 메시지/키워드 인자를 수정해요. 이 구현은 생성자에서 extra로 넘긴 객체를 키 'extra'kwargs에 추가해요. (수정된) 인자 버전의 (msg, kwargs) 튜플을 반환해요.
  • manager — 기본 loggermanager에 위임해요.
  • _log — 기본 logger_log() 메서드에 위임해요.

이 외에도 LoggerAdapter는 Logger의 debug(), info(), warning(), error(), exception(), critical(), log(), isEnabledFor(), getEffectiveLevel(), setLevel(), hasHandlers() 메서드를 지원해요. 이 메서드들은 Logger 쪽과 시그니처가 같아서 두 인스턴스를 서로 바꿔 쓸 수 있어요.

버전 3.2에서 isEnabledFor(), getEffectiveLevel(), setLevel(), hasHandlers() 추가. 버전 3.6에서 manager 속성과 _log() 메서드 추가(중첩 어댑터 허용). 버전 3.10에서 extra 인자가 선택적이 됨. 버전 3.13에서 merge_extra 매개변수 추가.

스레드 안전성

logging 모듈은 클라이언트가 특별히 할 것 없이 스레드 안전하도록 설계됐어요. threading 락으로 이를 달성하는데, 모듈의 공유 데이터 접근을 직렬화하는 락 하나와, 각 핸들러가 자신의 기본 I/O 접근을 직렬화하는 락 하나가 있어요. signal 모듈로 비동기 시그널 핸들러를 구현한다면 그 핸들러 안에서 로깅을 못 쓸 수도 있어요. threading 모듈의 락 구현이 항상 재진입 가능한 건 아니라서, 시그널 핸들러에서 호출할 수 없기 때문이에요.

모듈 레벨 함수

  • logging.getLogger(name=None) — 지정한 이름의 로거를 반환하거나, nameNone이면 계층의 루트 로거를 반환해요. 이름은 보통 'a', 'a.b', 'a.b.c.d' 같은 점으로 구분된 계층 이름이에요. 특별한 이유가 없으면 __name__을 쓰길 권장해요. 같은 이름으로 이 함수를 호출하면 항상 같은 로거 인스턴스를 반환해요. 즉 로거 인스턴스를 애플리케이션의 서로 다른 부분 사이에 전달할 필요가 없어요.

  • logging.getLoggerClass() — 표준 Logger 클래스나 setLoggerClass()로 전달된 마지막 클래스를 반환해요. 새 클래스 정의 안에서 호출해, 커스텀 Logger 클래스를 설치해도 다른 코드가 적용한 커스터마이징을 되돌리지 않도록 할 수 있어요:

    class MyLogger(logging.getLoggerClass()):
        # ... 여기서 동작 오버라이드
    
  • logging.getLogRecordFactory() — LogRecord를 만드는 데 쓰는 callable을 반환해요. (버전 3.2 추가.)

  • logging.debug(msg, *args, **kwargs) — 루트 로거에서 Logger.debug()를 호출하는 편의 함수예요. 인자 처리는 그 메서드와 완전히 동일해요. 차이는 루트 로거에 핸들러가 없으면 debug 호출 전에 basicConfig()가 호출된다는 점이에요. 짧은 스크립트나 로깅 기능의 빠른 시연에는 편리하지만, 대부분의 프로그램은 로깅 설정을 명시적으로 제어하고 싶어 하므로 모듈 레벨 로거를 만들어 Logger.debug()를 호출하길 권장해요.

  • logging.info(msg, *args, **kwargs) — 루트 로거에 레벨 INFO로 기록. 다른 동작은 debug()와 동일.

  • logging.warning(msg, *args, **kwargs) — 레벨 WARNING으로. (debug()와 동일)

    참고: 폐기 예정인 구식 함수 warn이 이와 기능적으로 동일해요. warn 대신 warning을 사용하세요.

  • logging.error(msg, *args, **kwargs) — 레벨 ERROR로. (debug()와 동일)

  • logging.critical(msg, *args, **kwargs) — 레벨 CRITICAL로. (debug()와 동일)

  • logging.exception(msg, *args, **kwargs) — 레벨 ERROR로, 예외 정보를 추가해요. 예외 핸들러 안에서만 호출해야 해요.

  • logging.log(level, msg, *args, **kwargs) — 루트 로거에 레벨 level로. (debug()와 동일)

  • logging.disable(level=CRITICAL) — 모든 로거에 대해 로거 자체의 레벨보다 우선하는 오버라이드 레벨을 제공해요. 전체 애플리케이션의 로깅 출력을 일시적으로 줄일 때 유용해요. level 이하의 심각도 로깅 호출을 모두 비활성화해요. 예를 들어 INFO 값으로 호출하면 모든 INFO와 DEBUG 이벤트는 버려지고, WARNING 이상은 로거의 유효 레벨에 따라 처리돼요. logging.disable(logging.NOTSET)을 호출하면 이 오버라이드 레벨이 제거돼요. CRITICAL보다 높은 커스텀 로깅 레벨을 정의했다면(권장하지 않아요) 기본값에 의존하지 말고 적절한 값을 직접 전달해야 해요.

    버전 3.7에서 변경: level 매개변수의 기본값이 CRITICAL이 됨 (bpo-28524).

  • logging.addLevelName(level, levelName) — 내부 딕셔너리에서 레벨 level을 텍스트 levelName과 연결해요. 숫자 레벨을 텍스트 표현으로 매핑하는 데 쓰이며, 예를 들어 Formatter가 메시지를 포맷할 때 사용해요. 자기만의 레벨을 정의하는 데도 쓸 수 있어요. 모든 레벨은 이 함수로 등록돼야 하고, 양의 정수여야 하며, 심각도가 증가하는 순서로 증가해야 해요.

    참고: 자기만의 레벨을 정의하려면 Custom Levels 섹션을 보세요.

  • logging.getLevelNamesMapping() — 레벨 이름을 해당 로깅 레벨로 매핑한 것을 반환해요. 예: 문자열 "CRITICAL"CRITICAL에 매핑돼요. 반환된 매핑은 매 호출 시 내부 매핑에서 복사돼요. (버전 3.11 추가.)

  • logging.getLevelName(level) — 로깅 레벨 level의 텍스트 또는 숫자 표현을 반환해요. 미리 정의된 CRITICAL, ERROR, WARNING, INFO, DEBUG 중 하나면 해당 문자열을 반환해요. addLevelName()으로 이름을 연결했다면 그 이름을 반환해요. 정의된 레벨에 해당하는 숫자 값을 넣으면 해당 문자열 표현을 반환해요. level 매개변수는 'INFO' 같은 문자열 표현도 받으며 그 경우 해당 숫자 값을 반환해요. 일치하는 값이 없으면 'Level %s' % level 문자열을 반환해요.

    참고: 레벨은 내부적으로 정수예요(로깅 로직에서 비교해야 하므로). 이 함수는 정수 레벨과 %(levelname)s 포맷 지정자로 표시되는 레벨 이름 사이를 변환해요. 버전 3.4에서 변경: 3.4 이전에는 텍스트 레벨을 넘기면 해당 숫자 값을 반환했어요. 이 미문서화된 동작은 실수로 간주돼 3.4에서 제거됐지만, 하위 호환을 위해 3.4.2에서 복원됐어요.

  • logging.getHandlerByName(name) — 지정한 이름의 핸들러를 반환하거나, 그런 이름의 핸들러가 없으면 None을 반환해요. (버전 3.12 추가.)

  • logging.getHandlerNames() — 알려진 모든 핸들러 이름의 불변 집합을 반환해요. (버전 3.12 추가.)

  • logging.makeLogRecord(attrdict) — 속성이 attrdict로 정의된 새 LogRecord 인스턴스를 만들어 반환해요. 소켓으로 보내진 피클된 LogRecord 속성 딕셔너리를 받는 쪽에서 LogRecord 인스턴스로 되살리는 데 유용해요.

  • logging.basicConfig(**kwargs) — 기본 Formatter를 가진 StreamHandler를 만들어 루트 로거에 추가함으로써 로깅 시스템의 기본 설정을 해요. debug(), info(), warning(), error(), critical() 함수는 루트 로거에 핸들러가 없으면 자동으로 basicConfig()를 호출해요. 루트 로거에 이미 핸들러가 설정돼 있으면, force 키워드 인자가 True가 아닌 한 아무것도 하지 않아요.

    참고: 이 함수는 다른 스레드를 시작하기 전에 메인 스레드에서 호출해야 해요. 여러 스레드에서 호출하면 루트 로거에 핸들러가 두 번 이상 추가되어 메시지가 중복될 수 있어요.

    지원되는 키워드 인자는 다음과 같아요.

    포맷 설명
    filename StreamHandler 대신 지정한 filename으로 FileHandler를 만들도록 지정.
    filemode filename이 지정되면 그 모드로 파일을 엶. 기본값 'a'.
    format 핸들러에 지정한 포맷 문자열 사용. 기본값은 levelname, name, message 속성을 콜론으로 구분한 것.
    datefmt time.strftime()이 받는 형태의 지정한 날짜/시간 포맷 사용.
    style format이 지정되면 그 포맷 문자열에 쓸 스타일. printf 스타일·str.format()·string.Template에 대해 각각 '%', '{', '$' 중 하나. 기본값 '%'.
    level 루트 로거 레벨을 지정한 레벨로 설정.
    stream StreamHandler를 초기화하는 데 지정한 스트림 사용. filename과 호환되지 않으며 둘 다 있으면 ValueError.
    handlers 루트 로거에 추가할 이미 만들어진 핸들러의 iterable. 포매터가 설정되지 않은 핸들러에는 이 함수에서 만든 기본 포매터가 할당됨. filename이나 stream과 호환되지 않음.
    force 참으로 지정하면 다른 인자에 따라 설정을 수행하기 전에 루트 로거에 붙은 기존 핸들러를 제거하고 닫음.
    encoding filename과 함께 지정하면 FileHandler가 생성될 때(즉 출력 파일을 열 때) 그 값 사용.
    errors filename과 함께 지정하면 FileHandler가 생성될 때 그 값 사용. 지정하지 않으면 'backslashreplace'. None을 지정하면 그대로 open()에 전달되어 'errors'를 넘기는 것과 동일하게 취급됨.

    버전 3.2에서 style 추가, 버전 3.3에서 handlers 추가(호환되지 않는 인자 감지 검사 추가), 버전 3.8에서 force 추가, 버전 3.9에서 encodingerrors 추가.

  • logging.shutdown() — 모든 핸들러를 플러시하고 닫아 로깅 시스템이 질서 있게 종료하도록 해요. 애플리케이션 종료 시 호출해야 하고, 이 호출 이후에는 로깅 시스템을 더 사용하면 안 돼요. logging 모듈은 임포트될 때 이 함수를 종료 핸들러(atexit 참고)로 등록하므로 보통 수동으로 할 필요는 없어요.

  • logging.setLoggerClass(klass) — 로거를 인스턴스화할 때 클래스 klass를 쓰라고 알려줘요. 클래스는 __init__()name 인자 하나만 요구하도록 정의해야 하고, __init__()Logger.__init__()을 호출해야 해요. 보통 커스텀 로거 동작이 필요한 애플리케이션이 로거를 만들기 전에 호출해요. 이후에도 하위 클래스로 직접 로거를 인스턴스화하지 말고 계속 logging.getLogger() API로 얻으세요.

  • logging.setLogRecordFactory(factory) — LogRecord를 만드는 데 쓸 callable을 설정해요.

    매개변수: factory — 로그 레코드를 인스턴스화할 팩토리 callable.

    버전 3.2 추가. 팩토리 시그니처는 다음과 같아요.

    factory(name, level, fn, lno, msg, args, exc_info, func=None, sinfo=None, **kwargs)
    
    • name — 로거 이름.
    • level — (숫자) 로깅 레벨.
    • fn — 로깅 호출이 일어난 파일의 전체 경로.
    • lno — 로깅 호출이 일어난 파일의 줄 번호.
    • msg — 로깅 메시지.
    • args — 로깅 메시지의 인자.
    • exc_info — 예외 튜플 또는 None.
    • func — 로깅 호출을 발생시킨 함수/메서드 이름.
    • sinfotraceback.print_stack()이 제공하는 것 같은, 호출 계층을 보여주는 스택 트레이스백.
    • kwargs — 추가 키워드 인자.

모듈 레벨 속성

  • logging.lastResort — '마지막 수단의 핸들러'가 이 속성으로 제공돼요. sys.stderrWARNING 레벨로 쓰는 StreamHandler로, 로깅 설정이 전혀 없는 상태에서 로깅 이벤트를 처리해요. 결과적으로 메시지를 sys.stderr에 출력하는 거죠. 이전의 "로거 XYZ에 대해 핸들러를 찾을 수 없습니다" 오류 메시지를 대체해요. 이전 동작이 필요하면 lastResortNone으로 설정하면 돼요. (버전 3.2 추가.)
  • logging.raiseExceptions — 처리 중 예외를 전파할지 여부. 기본값 True. False면 예외가 조용히 무시돼요.

warnings 모듈과의 통합

captureWarnings() 함수는 logging을 warnings 모듈과 통합하는 데 쓸 수 있어요.

  • logging.captureWarnings(capture) — warnings의 로깅 캡처를 켜고 끄는 함수예요. captureTrue면 warnings 모듈이 발행한 경고가 로깅 시스템으로 리디렉션돼요. 구체적으로, 경고는 warnings.formatwarning()으로 포맷되고 결과 문자열은 'py.warnings'라는 로거에 WARNING 심각도로 기록돼요. False면 리디렉션이 멈추고 경고는 원래 목적지로 되돌아가요.

더 알아보기

  • logging.config 모듈 — logging 모듈의 설정 API.
  • logging.handlers 모듈 — logging 모듈에 포함된 유용한 핸들러.
  • PEP 282 - A Logging System — Python 표준 라이브러리에 이 기능을 포함시키기 위한 제안서.
  • 원본 Python logging 패키지 — logging 패키지의 원본 소스. 표준 라이브러리에 logging이 없는 Python 1.5.2, 2.1.x, 2.2.x에서 쓸 수 있어요.