python logging 是一套灵活强大的日志输出框架,具体功能在这里就不赘述了。本文通过gist上的一份共享代码介绍在各种不同使用场景下如何复用一套logging配置入口来高效地使用python logging.
源码
源代码分两部分,一部分是python入口,log.py
可以放置在脚本文件夹下,也可以放置在包中。
import os
import yaml
import logging.config
import logging
import coloredlogs
def setup_logging(default_path='logging.yaml', default_level=logging.INFO, env_key='LOG_CFG'):
"""
| **@author:** Prathyush SP
| Logging Setup
"""
path = default_path
value = os.getenv(env_key, None)
if value:
path = value
if os.path.exists(path):
with open(path, 'rt') as f:
try:
config = yaml.safe_load(f.read())
logging.config.dictConfig(config)
coloredlogs.install()
except Exception as e:
print(e)
print('Error in Logging Configuration. Using default configs')
logging.basicConfig(level=default_level)
coloredlogs.install(level=default_level)
else:
logging.basicConfig(level=default_level)
coloredlogs.install(level=default_level)
print('Failed to load configuration file. Using default configs')
配置文件可以在部署时按需修改,解耦了日志编写逻辑和日志输出方式。配置文件用yaml格式编写,具有较好的可读性,对编辑也较为友好。默认从当前运行文件夹下加载logging.yaml
。注意使用yaml需要安装额外的包pyaml
version: 1
disable_existing_loggers: false
formatters:
standard:
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
error:
format: "%(levelname)s <PID %(process)d:%(processName)s> %(name)s.%(funcName)s(): %(message)s"
handlers:
console:
class: logging.StreamHandler
level: DEBUG
formatter: standard
stream: ext://sys.stdout
info_file_handler:
class: logging.handlers.RotatingFileHandler
level: INFO
formatter: standard
filename: /tmp/info.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
error_file_handler:
class: logging.handlers.RotatingFileHandler
level: ERROR
formatter: error
filename: /tmp/errors.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
debug_file_handler:
class: logging.handlers.RotatingFileHandler
level: DEBUG
formatter: standard
filename: /tmp/debug.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
critical_file_handler:
class: logging.handlers.RotatingFileHandler
level: CRITICAL
formatter: standard
filename: /tmp/critical.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
warn_file_handler:
class: logging.handlers.RotatingFileHandler
level: WARN
formatter: standard
filename: /tmp/warn.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
root:
level: NOTSET
handlers: [console]
propogate: yes
loggers:
<module>:
level: INFO
handlers: [console, info_file_handler, error_file_handler, critical_file_handler, debug_file_handler, warn_file_handler]
propogate: no
<module.x>:
level: DEBUG
handlers: [info_file_handler, error_file_handler, critical_file_handler, debug_file_handler, warn_file_handler]
propogate: yes
说明
disable_existing_loggers
由于logger在程序包import时就会实例化,可能会早于对logging模块配置的时间,启用此选项可能导致config之前实例的logger没有输出操作。
propogate
可以根据需要自行编写logger,python logging logger采用包名完全限定名的全部或部分匹配,如果当前包名没有指定的logger,怎会寻找上一级包名对应的logger。logger配置上有一个propogate参数可以控制logEntry是否继续向下传送到上级包对应的logger,直至root。
使用
import logging
from log import setup_logging
logger = logging.getLogger(__name__)
def main():
setup_logging()
logger.info('hello world')
命令行调试
python -c "from log import setup_logging; setup_logging(); import logging; logger = logging.getLogger(); logger.info('abc'); logger.error('error')" >info.txt 2>err.txt
参考资料
https://docs.python.org/3/library/logging.config.html#module-logging.config