print()는 빠르게 확인할 때 좋지만, 운영 코드에서는 질문이 달라집니다.
이때는 문자열 출력보다 "레벨이 있는 이벤트 기록"으로 봐야 하고, basicConfig, getLogger(__name__), 레벨, handler를 각각 어떤 역할로 읽는지가 중요합니다.
빠른 설정
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
logger.info("start processing")
logger.warning("retrying request")
logger.error("request failed")기본 흐름
기본형은 설정, logger 생성, 레벨별 호출을 함께 보면 됩니다.
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
logger.info("started")기본 설정
빠른 운영 로그 시작은 basicConfig
처음에는 basicConfig()만으로도 충분한 경우가 많습니다.
콘솔에 최소한의 레벨과 포맷을 붙여 로그를 남길 수 있기 때문입니다.
import logging
logging.basicConfig(level=logging.INFO)즉 logging 입문에서는 "복잡한 설정"보다 "print 대신 레벨을 붙여 남긴다"가 먼저입니다.
# 빠른 확인용 출력
print("user login failed")
# 운영 로그
logger.warning("user login failed")한 번 보고 버릴 스크립트 출력이라면 print()도 괜찮지만, 운영 흐름을 남기려면 레벨과 출처가 있는 logging이 훨씬 낫습니다.
logger와 레벨
모듈별 출처는 getLogger(__name__)
logging.getLogger(__name__) 패턴은 모듈 이름을 로그 출처로 남겨 줍니다.
프로젝트가 커질수록 이 차이가 큽니다.
logger = logging.getLogger(__name__)
logger.info("loading users")어느 파일에서 찍힌 메시지인지 추적하기 쉬워지고, 나중에 특정 모듈 로그만 조절하기도 편해집니다.
레벨은 메시지 중요도를 뜻한다
기본 감각은 아래 정도로 잡으면 충분합니다.
DEBUG: 개발 중 세부 정보INFO: 정상 진행 기록WARNING: 이상 징후, 재시도, 예상 밖 상황ERROR: 작업 실패
logger.debug("raw payload: %s", payload)
logger.info("job started")
logger.warning("retrying request")
logger.error("job failed")즉 logging은 "무슨 말을 남기냐"보다 "어느 심각도로 남기냐"가 중요합니다.
출력 구조
logger / handler / level을 역할로 나눠 읽는다
구조는 생각보다 단순합니다.
- logger: 로그를 보내는 출처
- handler: 어디에 기록할지
- level: 어느 정도 중요한 메시지만 통과시킬지
처음에는 basicConfig로 시작하고, 파일 로그나 포맷 분리가 필요해질 때 handler를 직접 붙이면 됩니다.
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)문자열을 미리 만들지 않고 포맷 인자를 넘긴다
logging은 레벨이 꺼져 있을 때 불필요한 문자열 계산을 줄일 수 있도록 포맷 인자를 받습니다.
그래서 f-string보다 %s 포맷 인자를 넘기는 패턴이 실무에서 더 자주 권장됩니다.
user_id = 42
status = "retry"
logger.info("user=%s status=%s", user_id, status)즉 로그 메시지는 "문자열을 미리 완성한다"보다 "메시지 템플릿과 값"으로 넘긴다고 읽는 편이 좋습니다.
주의할 점
문자열을 미리 포매팅해 두기보다 logging의 포맷 인자를 쓰는 편이 좋습니다. 레벨이 꺼져 있을 때 불필요한 문자열 계산을 줄일 수 있습니다.
# ❌ f-string을 먼저 계산
logger.debug(f"payload: {payload}")
# ✅ logging이 필요할 때만 포맷
logger.debug("payload: %s", payload)참고 링크
2 sources