Python에서는 logging 모듈을 기본적으로 제공
1-1. Log Level
- Python의 기본 레벨 = WARNING
https://docs.python.org/3.7/howto/logging.html#when-to-use-logging
1-2. Root Logger
import logging
logging.warning('This is a warning message')
# 아래와 같은 메시지가 콘솔에 출력됩니다
# WARNING:root:This is a warning message
logging.info('This is an info message')
# 아무 것도 프린트 되지 않습니다
import logging
logging.basicConfig(level=logging.INFO)
logging.info('This is an info message')
# 아래와 같은 메시지가 출력됩니다!
# INFO:root:This is an info message
import logging
logging.basicConfig(filename='dummy.log', level=logging.INFO)
logging.debug('this is a debug')
logging.info('this is an info')
logging.warning('this is a warning')
[dummy.log]
INFO:root:this is an info
WARNING:root:this is a warning
import logging
logging.basicConfig(
format = '%(asctime)s:%(levelname)s:%(message)s',
datefmt = '%m/%d/%Y %I:%M:%S %p',
level = logging.DEBUG
)
logging.debug('This is a formatted debug message')
# 03/12/2019 05:20:12 PM:DEBUG:This is a formatted debug message
Custom Logging Module
- Loggers : 어플리케이션 코드가 직접 사용할 수 있는 인터페이스를 제공합니다.
- Handlers : Loggers에 의해 생성된 LogRecord를 처리하여 적절한 위치로 보냅니다.
- Filters : 출력되어야 하는 로그를 필터링합니다.
- Formatters : LogRecord의 출력 형태를 지정합니다.
Logging HOWTO - Python 3.9.5 documentation
Logger
- 로그를 생성할 수 있는 method를 제공해줍니다. (Logger.debug(), Logger.info(), …)
- 로그 레벨과 Logger에 적용된 filter를 바탕으로 처리해야 할 메시지를 판단합니다.
- 적절한 Handler들에게 로그 메시지에 부가정보가 더해진 LogRecord 인스턴스를 전달해줍니다.
logger Object = logging.getLogger(name)
- name이 주어진 경우, 해당 이름에 해당하는 logger를, name이 주어지지 않은 경우 root logger를 전달받습니다.
- name은 마침표(.)로 구분되는 계층구조를 가지고 있습니다. 예를 들어, getLogger('foo.bar')는 getLogger('foo')의 자식 logger를 반환합니다.
- Logger의 레벨이 정해지지 않은 경우 (logger.setLevel(...)을 설정해주지 않은 경우), 자신의 부모 logger의 레벨을 사용합니다.
- 자식 logger는 메시지를 자기 부모 logger의 handler에게 propagate합니다.
logging range
- Module-wise : Python에서는 하나의 파일이 하나의 모듈입니다. 따라서, 파일의 제일 위쪽에서 모듈명(__name__)으로 Logger를 만드는 방법이 있습니다.
- Instance-wise : __init__() method 내에서 Logger를 생성하는 방법으로, 각 인스턴스마다 고유한 Logger를 가지게 됩니다.
- Class-wise : __class__.__qualname__에 해당하는 Logger를 생성하는 방법입니다. 클래스별로 고유한 Logger를 가지게 됩니다.
- Function-wise : 함수 내에서 Logger를 생성할 수도 있습니다. (e.g. main())
Handler
Handler는 로그 메시지를 출력하는 역할
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
stream_handler = logging.StreamHandler()
logger.addHandler(stream_handler)
logger.info('This is an INFO message')
# This is an INFO message
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
file_handler = logging.FileHandler('dummy.log')
logger.addHandler(file_handler)
logger.info('This is an INFO message. Hello dummy!')
Formatter
Formatter는 최종적으로 출력 될 로그 메시지의 formatting에 관여
import logging
logging.Formatter(
fmt = None, # 메시지 출력 형태. None일 경우 raw 메시지를 출력.
datefmt = None, # 날짜 출력 형태. None일 경우 '%Y-%m-%d %H:%M:%S'.
style = '%' # '%', '{', '$' 중 하나. `fmt`의 style을 결정.
)
Example
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG) # 모든 레벨의 로그를 Handler들에게 전달해야 합니다.
formatter = logging.Formatter('%(asctime)s:%(module)s:%(levelname)s:%(message)s', '%Y-%m-%d %H:%M:%S')
# INFO 레벨 이상의 로그를 콘솔에 출력하는 Handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
# DEBUG 레벨 이상의 로그를 `debug.log`에 출력하는 Handler
file_debug_handler = logging.FileHandler('debug.log')
file_debug_handler.setLevel(logging.DEBUG)
file_debug_handler.setFormatter(formatter)
logger.addHandler(file_debug_handler)
# ERROR 레벨 이상의 로그를 `error.log`에 출력하는 Handler
file_error_handler = logging.FileHandler('error.log')
file_error_handler.setLevel(logging.ERROR)
file_error_handler.setFormatter(formatter)
logger.addHandler(file_error_handler)
ToJson
{
"version": 1,
"disable_existing_loggers": false,
"formatters": {
"basic": {
"format": "%(asctime)s:%(module)s:%(levelname)s:%(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S"
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": "INFO",
"formatter": "basic"
},
"file_debug": {
"class": "logging.FileHandler",
"level": "DEBUG",
"formatter": "basic",
"filename": "debug.log"
},
"file_error": {
"class": "logging.FileHandler",
"level": "ERROR",
"formatter": "basic",
"filename": "error.log"
}
},
"loggers": {
"__main__": {
"level": "DEBUG",
"handlers": ["console", "file_debug", "file_error"],
"propagate": true
}
}
}
import logging
import logging.config
import json
config = json.load(open('./logger.json'))
logging.config.dictConfig(config)
logger = logging.getLogger(__name__)
Daily Log File 생성
handler = TimedRotatingFileHandler('log/flask_server.log', when="D", interval=1)
handler.suffix = "%Y-%m-%d_%H-%M-%S"