Python 之日志处理(logging 模块)详解
logging 模块简介
logging 模块是 Python 内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比 print,具备如下优点
1、可以通过设置不同的日志等级,在 release 版本中只输出重要信息,而不必显示大量的调试信息
2、print 将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;logging 则可以由开发者决定将信息输出到什么地方,以及怎么输出
日志等级(level)
DEBUG < INFO < WARNING < ERROR < CRITICAL
- DEBUG 最详细的日志信息,典型应用场景是 问题诊断
- INFO 信息详细程度仅次于 DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作
- WARNING 当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的
- ERROR 由于一个更严重的问题导致某些功能不能正常运行时记录的信息
- CRITICAL 当发生严重错误,导致应用程序不能继续运行时记录的信息
logging 模块可以指定日志记录器的日志级别,只有级别大于或等于该指定日志级别的日志记录才会被输出,小于该等级的日志记录将会被丢弃
logger
logger:日志对象,logging 模块中最基础的对象,用 logging.getLogger(name) 方法进行初始化,name 可以不填。通常 logger 的名字我们对应模块名,如聊天模块、数据库模块、验证模块等
为程序提供记录日志的接口
判断日志所处级别,并判断是否要过滤
根据其日志级别将该条日志分发给不同 handler
其常用函数有:
Logger.setLevel() 设置日志级别
Logger.addHandler() 和 Logger.removeHandler() 添加和删除一个 Handler
Logger.addFilter() 添加一个 Filter
setLevel:设置日志等级
logger=logging.getLogger()
logger.setLevel(logging.DEBUG) # 设置日志等级
logging
1、Formatter 用于控制日志信息的最终输出格式
logging.Formatter(参数)
formatter=logging.Formatter('[%(asctime) s]-%(filename) s]-%(levelname) s:%(message) s')
- %(name) s Logger 的名字
- %(levelno) s 数字形式的日志级别
- %(levelname) s 文本形式的日志级别
- %(pathname) s 调用日志输出函数的模块的完整路径名,可能没有
- %(filename) s 调用日志输出函数的模块的文件名
- %(module) s 调用日志输出函数的模块名
- %(funcName) s 调用日志输出函数的函数名
- %(lineno) d 调用日志输出函数的语句所在的代码行
- %(created) f 当前时间,用 UNIX 标准的表示时间的浮 点数表示
- %(relativeCreated) d 输出日志信息时的,自 Logger 创建以 来的毫秒数
- %(asctime) s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
- %(thread) d 线程 ID。可能没有
- %(threadName) s 线程名。可能没有
- %(process) d 进程 ID。可能没有
- %(message) s 用户输出的消息
2、Handler 基于日志级别对日志进行分发,如设置为 WARNING 级别的 Handler 只会处理 WARNING 及以上级别的日志。具体的应用如一个应用要把所有的日志打在文件中,并把 ERROR 以上级别的日志打印到屏幕,把 CRITICAL 级别的日志发邮件
常用函数有:
- setLevel() 设置级别
- setFormatter() 设置 Formatter
- logging.FileHandler(参数) 创建一个 FileHandler
- logger.addHandler(fh) 添加
- logging.StreamHandler() 创建一个 StreamHandler
- logger.addHandler(ch) 添加
创建一个 FileHandler,用于写到本地
fh=logging.FileHandler(logname,'a',"utf-8")
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
logger.addHandler(fh)
创建一个 StreamHandler,用于输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
logger.addHandler(ch)
import os,time,logging
#日志存放路径
log_path=os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))),'logs')
# 如果不存在这个logs文件夹,就自动创建一个
if not os.path.exists(log_path):os.mkdir(log_path)
class Log():
def __init__(self):
#在日志路径下添加日志文件名
self.logname=os.path.join(log_path,'%s.log'%time.strftime('%Y_%m_%d'))
#logger日志对象初始化
self.logger=logging.getLogger()
#设置日志等级
self.logger.setLevel(logging.DEBUG)
#日志输出格式
self.formatter=logging.Formatter('[%(asctime)s]-%(filename)s]-%(levelname)s:%(message)s')
def __console(self,level,message):
# 创建一个 FileHandler,用于写到本地
fh=logging.FileHandler(self.logname,'a',"utf-8")
fh.setLevel(logging.DEBUG)
fh.setFormatter(self.formatter)
self.logger.addHandler(fh)
# 创建一个 StreamHandler,用于输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(self.formatter)
self.logger.addHandler(ch)
if level=='info':
self.logger.info(message)
elif level=='debug':
self.logger.debug(message)
elif level=='warning':
self.logger.warning(message)
elif level=='error':
self.logger.error(message)
# 这两行代码是为了避免日志输出重复问题
self.logger.removeHandler(ch)
self.logger.removeHandler(fh)
# 关闭打开的文件
fh.close()
def debug(self, message):
self.__console('debug', message)
def info(self, message):
self.__console('info', message)
def warning(self, message):
self.__console('warning', message)
def error(self, message):
self.__console('error', message)
if __name__ == "__main__":
log=Log()
log.info("---测试开始---")
log.info("操作步骤1,2,3")
log.warning("---测试结束---")
C:\Users\wangli\PycharmProjects\AutoMation\venv\Scripts\python.exe C:/Users/wangli/PycharmProjects/AutoMation/case/test.py
[2019-04-10 17:17:18,025]-test.py]-INFO:---测试开始---
[2019-04-10 17:17:18,026]-test.py]-INFO:操作步骤1,2,3
[2019-04-10 17:17:18,028]-test.py]-WARNING:---测试结束---
Process finished with exit code 0