python logging是一个非常好用的日志记录包, 但是使用起来也比较麻烦, 这个教程会以最简单的方法构建一个完整的示例,来尽可能解决所有工作中遇到的情况.
logging整体有几个机制是需要了解的:
- 信息等级 level
- format
- Handler
信息等级
主要分为了 DEBUG, INFO, WARNING, ERROR, CRITICAL 5 个等级. 这5 个等级是越来越高的, 我们可以对输出的信息进行分级制度过滤, 如果 level 的设置是 INFO 的话就不会输出 DEBUG 级别的信息, 如果 level 是 DEBUG 的话, 所有的信息都会输出. 每个等级都有一个对应的数值用于比较大小, 所以也可以人工构建一些新的等级并设定 levelno. 实践中 CRITICAL 应该是最影响程序运行结果的信息, 但是个人认为里程碑式的简要信息也可以放在这里, 这样的分级可以保证 ERROR 级别的输出可以简明的快速了解一个大项目运行到了那一步或者是在哪一步停止了. INFO 级别的信息就太碎了.
format
一个控制输出格式的方法, 可以显示日志输出的时间, 文件定位, 使用者, 日志级别以及使用者等相关信息, 方便查看日志的时候快速判断相关信息
Handler
比较复杂但是也是 logger 相对于 print 最有用的信息, handler 是可以处理 logger 输出内容的处理器, 可以把日志写进文件, 输出到 console 或者是发送到微信 pushover 等 app 中(需要自行实现). 并且这些可以共存. 不同的 handler 可以有着不同的 format 以及日志输出等级. 算是 logging 模块的核心.
最佳实践
主要 logger 构建
import logging
from notification import PushoverHandler
def log_init(log_file='log_file.log'):
stream_formatter = "%(asctime)s - %(filename)s - %(levelname)s]:%(message)s"
# logging.Formatter()
#PUSHOVER handler,用于发送到手机
pushover_handler = PushoverHandler('LoggerHandler')
pushover_handler.setLevel(logging.ERROR)
pushover_formatter = logging.Formatter("[%(levelname)s]:%(message)s")
pushover_handler.setFormatter(pushover_formatter)
file_handler = logging.FileHandler(log_file)
# file_handler = RotatingFileHandler('log_file.log', maxBytes=1024 * 1024 * 10, backupCount=5)
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(logging.Formatter(stream_formatter))
logging.basicConfig(format=stream_formatter, level=logging.INFO)
logger = logging.getLogger()
logger.addHandler(pushover_handler)
logger.addHandler(file_handler)
return logger
PushoverHandler定义(如果不需要使用 可以不看)
async def pushover_message(session, text, priority=0):
url = "https://api.pushover.net/1/messages.json"
payload = {
"token": PUSHOVER_KEY,
"user": PUSHOVER_USER_KEY,
"message": text,
"priority": priority,
}
async with session.post(url, data=payload) as response:
pass # 处理响应,如果需要的话
class PushoverHandler(logging.Handler, object):
"""
自定义日志handler
"""
def __init__(self, name, other_attr=None, **kwargs):
logging.Handler.__init__(self)
async def async_emit(self, record):
try:
msg = self.format(record)
priority = 0
if record.levelname == 'ERROR':
priority = 1
async with aiohttp.ClientSession() as session:
await pushover_message(session, msg, priority=priority)
except Exception as e:
print(e)
self.handleError(record)
def emit(self, record):
loop = asyncio.get_event_loop()
loop.run_until_complete(self.async_emit(record))
发送信息以及在其他文件中获取 logger
logger = log_init()
logger.info('hello,world')
# 其他文件
import logging
logger = logging.getLogger(__name__) #主logger 不能填入__name__ 其他文件获取 logger 就填入__name__就好
logger.info('test info')
logger.error('test error')