Python logging 중복 - Python logging jungbog

소개

FileHandler 를 사용하면 로그파일은 크기가 제한없이 커지는데요.

Show

    로그 파일 회전을 지원하는 RotatingFileHandler 을 알아보겠습니다.

    RotatingFileHandler

    • filename: 파일이름

    • mode: 쓰기 모드 (default: 'a')

    • maxBytes: 백업할 로그 파일의 최대 크기 (Bytes)

    • backupCount: 백업 로그 파일 개수

    예제 1

    다음 예제는 FileHandler 을 사용하여 로그파일 크기가 500 KB 까지 반복합니다.

    import logging
    import os
    
    def loop():
        i, file_size = 0, 0
        while file_size < 500*1024: # 500 KB
            file_size = os.path.getsize(log_file_path)
            logger.debug(i)
            i += 1
    
        print(f'{file_size} Byte')
    
    if __name__ == '__main__':
        log_dir = 'log'
        log_fname = 'debug.log'
        if not os.path.exists(log_dir):
            os.mkdir(log_dir)
    
        logger = logging.getLogger('jvv')
        logger.setLevel(logging.DEBUG)
        
        log_file_path = os.path.join(log_dir, log_fname)
    
        file_handler = logging.FileHandler(log_file_path)
        formatter = logging.Formatter('[%(levelname)s] :: %(asctime)s :: %(module)s :: %(name)s :: %(message)s\n')
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)
    
        loop()
    512064 Byte

    예제 2

    백업파일 크기 1KB, 백업파일 개수 5개로 지정했습니다.

    import logging
    from logging.handlers import RotatingFileHandler
    import os
    
    def loop():
        i = 0
        while len(os.listdir(log_dir)) < 5:
            logger.debug(i)
            i += 1
        
        for file in os.listdir(log_dir):
            _path = os.path.join(log_dir, file)
            _size = os.path.getsize(_path)
            print(f'{file} size: {_size}')
    
    if __name__ == '__main__':
        log_dir = 'log'
        log_fname = 'debug.log'
        if not os.path.exists(log_dir):
            os.mkdir(log_dir)
    
        logger = logging.getLogger('jvv')
        logger.setLevel(logging.DEBUG)
        
        path = os.path.join(log_dir, log_fname)
        rot_file_handler = RotatingFileHandler(path, mode='a', maxBytes=1024, backupCount=5)
        formatter = logging.Formatter('[%(levelname)s] :: %(asctime)s :: %(module)s ::%(name)s :: %(message)s\n')
        rot_file_handler.setFormatter(formatter)
        logger.addHandler(rot_file_handler)
    
        logger.debug('20200817')
    
        loop()
    debug.log size: 59
    debug.log.1 size: 1003
    debug.log.2 size: 1003
    debug.log.3 size: 1003
    debug.log.4 size: 999
    Python logging 중복 - Python logging jungbog

    다음과 같이 진행해보았습니다.

    while i < 1000:
        logger.debug(i)
        i += 1
    debug.log size: 960
    debug.log.1 size: 1020
    debug.log.2 size: 1020
    debug.log.3 size: 1020
    debug.log.4 size: 1020
    debug.log.5 size: 1020

    뒤로 밀면서 덮어쓰여지는 것을 확인할 수 있습니다.

    Python logging 중복 - Python logging jungbog

    참고

    logging.handlers — 로깅 처리기 — Python 3.8.5 문서

    소스 코드: Lib/logging/handlers.py 다음과 같은 유용한 처리기가 패키지에서 제공됩니다. 3개의 처리기(StreamHandler, FileHandler, NullHandler)는 실제로는 logging 모듈 자체에 정의되어 있지만, 다른 처리기들�

    docs.python.org


    Logging

    개발을 하면서 에러나는 부분이 어디인지, 왜 에러가 났는지 알아야 하는 경우가 대다수인데
    파이썬의 로깅모듈을 사용하면 따로 로깅 프로그램을 만들 필요 없이
    편리하게 로그를 찍어볼 수 있다.

    Logging모듈을 사용해서 간단하게 로그를 찍어보는 것을 해보았다.

    1. 로깅 모듈 import

    import logging

    따로 설치할 필요 없이 바로 lib사용하면 된다.

    2. 로깅 레벨 지정하기

    Logging의 디폴트 레벨은 'Warning'이고,
    DEBUG < INFO < WARNING < ERROR < CRITICAL 순으로 레벨을 설정할 수 있다.
    만약 레벨을 'Error'으로 지정했다면

    그 하위의 레벨(Debug, Info, Warning)은 출력이 되지 않는다.

    logging.error("에러발생")

    Logger

    Logging모듈을 사용해서 간단히 로그를 찍어볼 수도 있지만
    내 로깅 모듈을 따로 만들어서 사용할 수도 있다.

    import logging
    
    # logger
    logger = logging.getLogger("log")
    logger.setLevel(logging.INFO)
    handler= logging.StreamHandler()
    
    formatter = logging.Formatter('%(asctime)s|%(name)s|%(levelname)s:%(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    
    logger.info("server start!")

    1. logging.getLogger("log") : 생성"log"라는 특정 로거를 생성한다.

    2. logger.setLevel(logging.INFO) : 레벨 설정

    로거의 레벨을 'INFO'로 지정해서 그 이상만 출력하도록 했다.

    3. logging.StreamHandler() : 핸들러 설정

    핸들러 = 로깅한 정보가 출력되는 위치 설정

    아래와 같이 설종하면 여러 형식으로 로깅출력을 할 수 있다 :

    # Create Handlers == 로깅한 정보가 출력되는 위치 설정 
    streamHandler = logging.StreamHandler()
    streamHandler.setLevel(logging.DEBUG)
    streamHandler.setFormatter(formatter)
    
    fileHandler = logging.FileHandler(loggfile_path)
    fileHandler.setLevel(logging.DEBUG)
    fileHandler.setFormatter(formatter)
    
    logger.addHandler(streamHandler)
    logger.addHandler(fileHandler)

    StreamHandler = 임의의 파일류 객체와 같은 스트림으로 로깅 출력을 보낸다
    FileHandler = 디스크 파일로 로깅출력을 보낸다

    4. logging.Formatter : 출력 포맷 설정

    내가 원하는 형식으로 출력되게끔 설정해줄 수 있다.

    asctime 시간
    name 로거 이름
    levelname 로깅 레벨
    message 메세지

    + Exception 예외 메시지 내용 출력하기

    try:
    	main(args, logger)
    except:
    	logger.error("main error(1)")

    main에다가 logger을 보내주고,

    try: 
     
     ...
     
    except Exception as inst:
    	logger.error("main error(2): " + str(inst))

    예외 메시지를 출력해준다.

    print(type(inst)) --> 예외의 타입을 출력해줄 수도 있다.


    참고 :

    https://docs.python.org/ko/3/library/logging.handlers.html

    https://hamait.tistory.com/880