단일

import logging

# 로그 생성
logger = logging.getLogger()

# 로그의 출력 기준 설정
logger.setLevel(logging.INFO)

# log 출력 형식
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# log 출력
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)

# log를 파일에 출력
file_handler = logging.FileHandler('my.log')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)

for i in range(10):
	logger.info(f'{i}번째 방문입니다.')

Untitled

네 번째 키워드 인자는 extra 로, 로깅 이벤트용으로 만들어진 LogRecord의 dict 를 사용자 정의 어트리뷰트로 채우는 데 사용되는 딕셔너리를 전달.

FORMAT = '%(asctime)-15s %(clientip)s %(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)

로그 중복

예시

2022-11-08 07:54:49,120 - My logger - ERROR - 404 K2_20200430_002721_P007_RGB_PS.tif
2022-11-08 07:54:49,120 - My logger - ERROR - 404 K2_20200430_002721_P007_RGB_PS.tif
2022-11-08 07:54:49,120 - My logger - ERROR - 404 K2_20200430_002721_P007_RGB_PS.tif
2022-11-08 07:54:49,224 - My logger - ERROR - 404 WV2_20191116_100421_P000_RGB_PS.TIF
2022-11-08 07:54:49,224 - My logger - ERROR - 404 WV2_20191116_100421_P000_RGB_PS.TIF
2022-11-08 07:54:49,224 - My logger - ERROR - 404 WV2_20191116_100421_P000_RGB_PS.TIF
2022-11-08 07:54:49,634 - My logger - ERROR - 404 K3A_20170330_045311_P000_RGB_PS.tif
2022-11-08 07:54:49,634 - My logger - ERROR - 404 K3A_20170330_045311_P000_RGB_PS.tif
2022-11-08 07:54:49,634 - My logger - ERROR - 404 K3A_20170330_045311_P000_RGB_PS.tif

3번씩 중복되어 있다!

원인

같은 logger에 핸들러를 계속해서 붙이므로 한번 logging해도 여러 개의 핸들러가 작동하여 로그는 여러 개가 찍히는 것이다.

기존 코드

logger = logging.getLogger("My logger")
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# file_handler = logging.FileHandler('/var/log/Scene/tiled_status.log')
file_handler = logging.FileHandler('/nas/k8s/dev/data/shared-log/Scene/tiled_api_error.log')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)

수정 코드

def get_logger(log_path):
    # Create Logger
    logger = logging.getLogger("My logger")
    if len(logger.handlers) > 0:
        return logger
    logger.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    # file_handler = logging.FileHandler('/var/log/Scene/tiled_status.log')
    file_handler = logging.FileHandler(log_path)
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)
    return logger

log_path = 'logpath'
logger = get_logger(log_path)
# settings.py

LOGGING_CONFIG = { 
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': { 
        'standard': { 
            'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
        },
    },
    'handlers': { 
        'default': { 
            'level': 'INFO',
            'formatter': 'standard',
            'class': 'logging.StreamHandler',
            'stream': 'ext://sys.stdout',
        },
        'scene_processing': { 
            "level": "INFO",
            "class": "logging.handlers.RotatingFileHandler",
            "filename": f"/var/log/Scene/INDEX/LOG/{datetime.now().date()}_scene_migrate.log",
            "maxBytes": 1024 * 1024 * 5,
            "backupCount": 5,
            "formatter": "standard",
        },
        'scene_migration': { 
            "level": "INFO",
            "class": "logging.handlers.RotatingFileHandler",
            "filename": f"/var/log/Scene/INDEX/LOG/{datetime.now().date()}_scene_migrate.log",
            "maxBytes": 1024 * 1024 * 5,
            "backupCount": 5,
            "formatter": "standard",
        },
        'scene_indexing': { 
            "level": "INFO",
            "class": "logging.handlers.RotatingFileHandler",
            "filename": f"/var/log/Scene/INDEX/LOG/{datetime.now().date()}_scene_indexing.log",
            "maxBytes": 1024 * 1024 * 5,
            "backupCount": 5,
            "formatter": "standard",
        },
    },
    'loggers': { 
        '': {
            'handlers': ['default'],
            'level': 'WARNING',
            'propagate': False
        },
        'scene_processing': { 
            'handlers': ['scene_processing'],
            'level': 'INFO',
            'propagate': False
        },
        'scene_migration': { 
            'handlers': ['scene_migration'],
            'level': 'INFO',
            'propagate': False
        },
        'scene_indexing': { 
            'handlers': ['scene_indexing'],
            'level': 'INFO',
            'propagate': False
        },
        '__main__': {  # if __name__ == '__main__'
            'handlers': ['default'],
            'level': 'DEBUG',
            'propagate': False
        },
    } 
}