ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 로그 분리 법칙
    FastAPI 2025. 10. 20. 00:31

    [로그 레코드의 구조 및 동작 원리]

     

    Python의 로깅 시스템은 트리형 계층 구조로 되어있다.

    (root)
     ├── app
     │    ├── api
     │    │    └── chat
     │    └── service
     │         └── user

     

    root 로거가 존재하고 각 모듈 (파일) 별로 로거를 지정할 수 있다.

     

    이때 로그가 하위 모듈(한 개의 파일)에서 발생했을 시, 해당 로그 레코드는 root logger까지 전달된다.

    이때 로그 레코드는 로그를 발생시킨 실제 위치(파일명, 함수명, 라인번호)만 기록되고,

    root logger까지 가는 도중 거친 부모 로거의 파일명/함수명은 찍히지 않는다.

     

    즉, LogRecord 객체는 발생 시점의 컨텍스트만 담는다.

    로그 발생 그 순간의 컨텍스트(파일, 함수, 라인, 모듈명)만 캡쳐하는 것이다!

    # app/service/user.py
    import logging
    
    logger = logging.getLogger(__name__)
    
    def create_user():
        logger.info("User created")

     

    예를 들어, 해당 함수가 실행되면 내부적으로 아래와 같은 LogRecord가 생성된다.

     

    {
        "name": "app.service.user",     # logger 이름 (getLogger(__name__))
        "levelname": "INFO",
        "pathname": "/app/service/user.py",  # 실제 파일 경로
        "filename": "user.py",               # 파일명만
        "funcName": "create_user",           # 함수명
        "lineno": 5,                         # 코드 라인
        "msg": "User created"
    }

     

    해당 LogRecord는 그대로 부모에게 전달되고

    부모 로거는 그걸 그대로 핸들러에게 전달해서 포맷팅만 수행한다.

     


    [basicConfig]

     

    basicConfig는 root로거에 대한 설정을 세팅하는 함수이다.

    root logger의 핸들러, 레벨, 포맷터를 설정하는 것이다.

    # main.py
    import logging
    
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] [%(name)s:%(filename)s:%(funcName)s:%(lineno)d] %(message)s",
        handlers=[
            logging.FileHandler("logs/app.log"),
            logging.StreamHandler(),
        ],
    )

    [모듈별 로거 설정]

     

    # app.api.chat.py
    
    logger = logging.getLogger(__name__)

     

    여기서 __name__은 Python이 각 파일을 인식하는 모듈 이름이다.

    위와 같이 하면 해당 파일 안에서 "app.api.chat" 이름의 로거가 생성된다.

     

    만약 하위 로거에서 로그를 찍으면 해당 로그는 root로더까지 전파된다.

    여기서 로그 레코드의 전파를 propagate라고 지칭한다.

     

    만약 특정 모듈에서의 로그를 root logger까지 전달하기 싫으면 propagate 필드를 False로 설정해주면 된다.

    logger = logging.getLogger(__name__)
    logger.propagate = False

     

    이와 같이 하면 해당 모듈의 로그는 부모(root)로 전파되지 않는다.

    하지만 root까지 전파되지 않아 root의 basicConfig 설정정보로 로그를 찍을 수 없으니 별도의 설정을 해줘야한다.

    'FastAPI' 카테고리의 다른 글

    aiohttp  (0) 2025.10.17
    Logging  (0) 2025.10.11
    CPU Bound vs I/O Bound  (0) 2025.10.10
    single thread event loop vs multi processing  (0) 2025.09.28
    동시성 vs 병렬성  (0) 2025.09.28