python的logging模块是用来设置日志的,是python的标准模块。html
python模块分析之random(一)python
DEBUG:优先级10,记录调试的详细信息,只在调试时开启;ide
INFO:优先级20,记录普通的消息,包括错误和警告等等;函数
WARNING:优先级30,记录相关的警告信息;测试
ERROR:优先级40,记录错误信息,程序崩溃;
CRITICAL:优先级50,记录错误信息;
若是不设置级别的话,默认为warning,系统记录设置的日志级别优先级以上的日志信息。
查看logging的源码,可知主要有四个类实现功能;
Loggers:提供应用程序直接使用的接口,如相关的配置设置;
Handlers:将Loggers产生的日志传到指定位置,设置日志保存的位置;
Filters:对输出日志进行过滤操做;
Formatters:控制日志的输出格式;
Formatter对象定义了日志的输出格式,有多种可选参数。
%(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 用户输出的消息 # 定义一个输出格式的对象 formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s',datefmt='%Y-%m-%d %H:%M:%S', style='%') # Formatter参数: fmt:定义输出的日志信息的格式; datefmt:定义时间信息的格式,默认为'%Y-%m-%d %H:%M:%S'; style:定义格式化输出的占位符,默认是%(name)格式,可选{}或$格式
日志处理器用来处理日志的具体流向,是输出到文件中仍是到标准输出等,它经过设置Formatter控制输出格式,添加filters过滤日志;
StreamHandler:用于向控制台打印日志;
FileHandler:用于向日志文件打印日志;
RotatingHandler:logging.handlers.RotatingHandler;日志回滚方式,支持日志文件最大数量和日志文件回滚 TimeRotatingHandler:logging.handlers.TimeRotatingHandler;日志回滚方式,在必定时间区域内回滚日志文件 SocketHandler:logging.handlers.SocketHandler;远程输出日志到TCP/IP sockets DatagramHandler:logging.handlers.DatagramHandler;远程输出日志到UDP sockets SMTPHandler:logging.handlers.SMTPHandler;远程输出日志到邮件地址 SysLogHandler:logging.handlers.SysLogHandler;日志输出到syslog NTEventLogHandler:logging.handlers.NTEventLogHandler;远程输出日志到Windows NT/2000/XP的事件日志 MemoryHandler:logging.handlers.MemoryHandler;日志输出到内存中的指定buffer HTTPHandler:logging.handlers.HTTPHandler;经过"GET"或者"POST"远程输出到HTTP服务器
from logging import Handler handler = Handler() # 全部上述处理器的父类 print(handler.level) # 处理日志的等级 print(handler.name) # 处理日志的名字 print(handler.filters) # 处理器的日志过滤器 print(handler.formatter) # 日志的格式 handler.get_name() handler.set_name('') handler.createLock() # 建立线程锁 handler.acquire() # 获取线程锁 handler.release() # 释放线程锁 handler.setLevel('info') # 设置日志处理器的记录级别 handler.setFormatter(fmt='') # 设置日志的输出格式 handler.addFilter('') # 往处理器中添加过滤器 handler.removeFilter('') # 往处理器中移除过滤器 handler.emit('') # 日志记录的处理逻辑,由子类实现
Logger管理着全部记录日志的方法。
logger = getLogger(__name__) # 返回一个Logger实例 # logger = getLogger('root') # 以'root'为名字的日志对象在Logger对象中只有一个实例 # 若是是想调用以'root'为名字的日志对象输出日志,能够直接导入 from logging import error, debug, warning, info, fatal, critical print(logger.root) # 获取根日志对象 print(logger.manager) # 获取manager print(logger.name) # 日志对象的名字 print(logger.level) # 日志记录水平 print(logger.filters) # 日志过滤器列表 print(logger.handlers) # 日志处理器列表 print(logger.disabled) logger.setLevel('info') # 设置日志记录水平 logger.info('this is %s', 'info', exc_info=1) # 输出日志信息,格式化输出 logger.warning('') # 记录warning信息 logger.error('') # 记录error信息 logger.exception('') # 等价于logger.error('', exc_info=1) logger.debug('') # 记录debug信息 logger.critical('') # 记录critical信息 logger.log('info','') # 直接指定级别 logger.addHandler('') # 添加处理器 logger.removeHandler('') # 移除处理器 logger.hasHandlers() # 判断是否有处理器
import logging import sys def get_logger(appname): # 获取logger实例,若是参数为空则返回root logger logger = logging.getLogger(appname) # 建立日志输出格式 formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s') # 设置文件处理器,加载处理格式 file_handler = logging.FileHandler("test.log") # 指定输出的文件路径 file_handler.setFormatter(formatter) # 控制台日志 console_handler = logging.StreamHandler(sys.stdout) console_handler.formatter = formatter # 为logger添加的日志处理器 logger.addHandler(file_handler) logger.addHandler(console_handler) # 指定日志的最低输出级别,默认为WARN级别 logger.setLevel(logging.INFO) if __name__ == "__main__": logger = get_logger('test') logger.debug('this is debug info') logger.info('this is information') logger.warn('this is warning message') logger.error('this is error message') logger.fatal('this is fatal message, it is same as logger.critical') logger.critical('this is critical message')
记录日志经过调用logger.debug等方法;
首先判断本条记录的日志级别是否大于设置的级别,若是不是,直接pass,再也不执行;
将日志信息当作参数建立一个LogRecord日志记录对象;
将LogRecord对象通过logger过滤器过滤,若是被过滤掉则pass;
日志记录对象被Handler处理器的过滤器过滤;
判断本条记录的日志级别是否大于Handler处理器设置的级别,若是不是,直接pass,再也不执行,最后调用处理器的emit方法处理日志记录;
# logging.conf [loggers] # 定义日志的对象名称是什么,注意必须定义root,不然报错。 keys=root,main [handlers] # 定义处理器的名称是什么,能够有多个,用逗号隔开 keys=consoleHandler [formatters] # 定义输出格式对象的名称,能够有多个,用逗号隔开 keys=simpleFormatter [logger_root] # 配置root对象的日志记录级别和使用的处理器 level=INFO handlers=consoleHandler [logger_main] # 配置main对象的日志记录级别和使用的处理器,qualname值得就是日志对象的名字 level=INFO handlers=consoleHandler qualname=main propagate=0 # logger对象把日志记录传递给全部相关的handler的时候,会(逐级向上)寻找这个logger和它全部的父logger的所有handler,propagate=1表示会继续向上搜寻;propagate=0表示中止搜寻,这个参数涉及重复打印的坑。 [handler_consoleHandler] # 配置处理器consoleHandler class=StreamHandler level=WARNING formatter=simpleFormatter args=(sys.stdout,) [formatter_simpleFormatter] # 配置输出格式过滤器simpleFormatter format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
字典形式配置功能更增强大,也更加灵活。经过dictConfig函数,咱们能够将其余格式的配置文件先转化成字典,如json、YAML等。
import yaml from logging.config import dictConfig import os filename = os.path.dirname(os.path.abspath(__file__)) with open(filename + '\logging.yml', 'r') as f: log = yaml.load(f.read()) dictConfig(log)
# logging.yaml version: 1 formatters: simple: format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s' handlers: console: class: logging.StreamHandler level: DEBUG formatter: simple stream: ext://sys.stdout console_err: class: logging.StreamHandler level: DEBUG formatter: simple stream: ext://sys.stderr loggers: simpleExample: level: DEBUG handlers: [console] propagate: no root: level: DEBUG handlers: [console_err]
logging.getLogger(appname),同一个appname获取到的logger对象是同一个,同时appname.name命名的logger继承了appname的全部的属性,能够不用从新配置logger。
try: raise except: logger.error('this is error message',exc_info = True) # 或 logger.exception("Failed to open sklearn.txt from logger.exception") # 设置exc_info为True后,会自动将错误的信息也发送到日志中; # 直接使用exception实现同样的功能。
import logging.config import logging import time logging.config.fileConfig("logging.conf") logger = logging.getLogger("test.listen") t = logging.config.listen(9999) t.setDaemon(True) t.start() # 启动监听服务器