标签:info ict pat smtp 输出 重要 ctime ica 理解
logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比print,具备如下优点:
import logging
import logging logging.debug(‘debug message‘) logging.info(‘info message‘) logging.warning(‘warning message‘) logging.error(‘error message‘) logging.critical(‘critical message‘) # 输出为: # WARNING:root:warning message # ERROR:root:error message # CRITICAL:root:critical message
从这个例子中,我们可以看到默认情况下
关于logging的内容远不止这么简单,且慢慢看下去。
在后面分别会说明日志级别,模块级函数记录日志,logging模块日志流处理流程
日志级别分类
说明
logging模块中提供了两种记录日志的方式:
说明: logging模块提供的模块级别的那些函数实际上也是通过这几个组件的相关实现类来记录日志的,只是在创建这些类的实例时设置了一些默认值。
上面说到了logging的basicConfig函数进行参数的配置。
logging.basicConfig函数各个参数
%(asctime)s:日志事件发生的时间--人类可读时间,如:2003-07-08 16:49:45,896
%(created)f:日志事件发生的时间--时间戳,就是当时调用time.time()函数返回的值
%(relativeCreated)d:日志事件发生的时间相对于logging模块加载时间的相对毫秒数(目前还不知道干嘛用的)
%(msecs)d:日志事件发生事件的毫秒部分
%(levelname)s:该日志记录的文字形式的日志级别(‘DEBUG‘, ‘INFO‘, ‘WARNING‘, ‘ERROR‘, ‘CRITICAL‘)
%(levelno)s:该日志记录的数字形式的日志级别(10, 20, 30, 40, 50)
%(name)s:所使用的日志器名称,默认是‘root‘,因为默认使用的是 rootLogger
%(message)s:日志记录的文本内容,通过 msg % args计算得到的
%(pathname)s:调用日志记录函数的源码文件的全路径
%(filename)s:pathname的文件名部分,包含文件后缀
%(module)s:filename的名称部分,不包含后缀
%(lineno)d:调用日志记录函数的源代码所在的行号
%(funcName)s:调用日志记录函数的函数名
%(process)d:进程ID
%(processName)s:进程名称,Python 3.1新增
%(thread)d:线程ID
%(thread)s:线程名称
ValueError
异常;在一开始写的那个简单的例子其实就是用模块级函数写的日志。除了上面的那种写法,还有另一种写法。
import logging logging.log(logging.DEBUG, "This is a debug log.") logging.log(logging.INFO, "This is a info log.") logging.log(logging.WARNING, "This is a warning log.") logging.log(logging.ERROR, "This is a error log.") logging.log(logging.CRITICAL, "This is a critical log.") # 输出为: # WARNING:root:This is a warning log. # ERROR:root:This is a error log. # CRITICAL:root:This is a critical log.
正如前面一开始说的那样,日志的的默认日志级别为WARNING,只有它和它以上的日志记录被输出。而默认的输出格式是:日志级别:日志器名称:日志内容。而这样输出也是因为
logging模块提供的日志记录函数所使用的日志器设置的日志格式默认是BASIC_FORMAT,其值为:
"%(levelname)s:%(name)s:%(message)s"
详细的默认值可以看源码,当我们没有提供任何配置信息的时候,这些函数都会去调用logging.basicConfig(**kwargs)
方法,且不会向该方法传递任何参数。继续查看basicConfig()
方法的代码就可以找到上面这些问题的答案了。
import logging LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s" DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p" logging.basicConfig(filename=‘my.log‘, level=logging.DEBUG, format=LOG_FORMAT, datefmt=DATE_FORMAT) logging.debug("This is a debug log.") logging.info("This is a info log.") logging.warning("This is a warning log.") logging.error("This is a error log.") logging.critical("This is a critical log.") # 此时会在my.log日志文件中看到下面的输出结果 # 08/12/2018 21:54:39 PM - DEBUG - This is a debug log. # 08/12/2018 21:54:39 PM - INFO - This is a info log. # 08/12/2018 21:54:39 PM - WARNING - This is a warning log. # 08/12/2018 21:54:39 PM - ERROR - This is a error log. # 08/12/2018 21:54:39 PM - CRITICAL - This is a critical log.
会上面这些基本的日志记录就算是掌握了。
说明:
logging.basicConfig()
函数是一个一次性的简单配置工具使,也就是说只有在第一次调用该函数时会起作用,后续再次调用该函数时完全不会产生任何操作的,多次调用的设置并不是累加操作。RootLogger
类的实例,其名称为‘root‘,它是处于日志器层级关系最顶层的日志器,且该实例是以单例模式存在的。logging.warning(‘%s is %d years old.‘, ‘Tom‘, 10)
,输出内容为WARNING:root:Tom is 10 years old.
exc_info, stack_info, extra
,下面对这几个关键字参数作个说明。一个例子:
import logging LOG_FORMAT = "%(asctime)s - %(levelname)s - %(user)s[%(ip)s] - %(message)s" DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p" logging.basicConfig(format=LOG_FORMAT, datefmt=DATE_FORMAT) logging.warning("Some one delete the log file.", exc_info=True, stack_info=True, extra={‘user‘: ‘Tom‘, ‘ip‘:‘192.168.199.22‘}) # 打印结果为 # 08/12/2018 22:01:43 PM - WARNING - Tom[192.168.199.22] - Some one delete the log file. # NoneType: None # Stack (most recent call last): # File "D:/workspace/modue/bin.py", line 6, in <module> # logging.warning("Some one delete the log file.", exc_info=True, stack_info=True, extra={‘user‘: ‘Tom‘, ‘ip‘:‘192.168.199.22‘})
在说明用logging模块的四大组件记录日志之前, 很有必要对logging模块所包含的重要组件以及其工作流程做个全面、简要的介绍,这有助于我们更好的理解我们所写的代码(将会触发什么样的操作)。
logging模块的四大组件
logging模块就是通过这些组件来完成日志处理的,上面所使用的logging模块级别的函数也是通过这些组件对应的类来实现的。
简单点说就是:日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。
下面介绍下与logging四大组件相关的类:Logger,Handler,Filter,Formatter。
Logger对象有3个任务要做
logger对象最常用的方法分为两类:配置方法和消息发送。
创建一个Logger对象
logger = logging.Logger
logger = logging.getLogger()
当我们创建了一个Logger对象,其实它并没什么功能,需要我们给它配置添加。
常用的配置方法
(下面写的logger都是Logger类的实例化对象):
import logging logger = logging.getLogger() # 获得一个Logger实例化对象 fh = logging.FileHandler(‘my_log‘) # 创建一个FileHandler对象,用于写入日志文件,参数为日志写到哪个文件中 ch = logging.StreamHandler() # 创建一个StreamHandler对象,用于输出到控制台 logger.addHandler(fh) # 为Logger对象添加FileHandler对象 logger.addHandler(ch) # 为Logger对象添加StreamHandler对象 logger.removeHandler(fh) # 为Logger对象删除FileHandler对象 logger.removeHandler(ch) # 为Logger对象删除StreamHandler对象
创建日志记录
例如:
logger = logging.getLogger() # 获得一个Logger实例化对象 logger.debug(‘logger debug message‘) logger.info(‘logger info message‘) logger.warning(‘logger warning message‘) logger.error(‘logger error message‘) logger.critical(‘logger critical message‘)
说明:
关于logger的层级结构与有效等级的说明:
|
Handler对象的作用是(基于日志消息的level)将消息分发到handler指定的位置(文件、网络、邮件等)。在上面的Logger类中,我们使用了Handler类的一些知识。所以对Handler类应该有了一定的了解,这里会详细的介绍这个类。
Logger对象可以通过addHandler()方法为自己添加0个或者更多个handler对象。比如,一个应用程序可能想要实现以下几个日志需求:
这种场景就需要3个不同的handlers,每个handler复杂发送一个特定严重级别的日志到一个特定的位置。
常用的Handler
handle对象常用配置方法
Filter可以被Handler和Logger用来做比level更细粒度的、更复杂的过滤功能。Filter是一个过滤器基类,它只允许某个logger层级下的日志事件通过过滤。该类定义如下:
class logging.Filter(name=‘‘)
filter(record)
比如,一个filter实例化时传递的name参数值为‘A.B‘,那么该filter实例将只允许名称为类似如下规则的loggers产生的日志记录通过过滤:‘A.B‘,‘A.B,C‘,‘A.B.C.D‘,‘A.B.D‘,而名称为‘A.BB‘, ‘B.A.B‘的loggers产生的日志则会被过滤掉。如果name的值为空字符串,则允许所有的日志事件通过过滤。
filter方法用于具体控制传递的record记录是否能通过过滤,如果该方法返回值为0表示不能通过过滤,返回值为非0表示可以通过过滤。
Formater对象用于配置日志信息的最终顺序、结构和内容。与logging.Handler基类不同的是,应用代码可以直接实例化Formatter类。另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个Formatter的子类来完成。
Formatter类的构造方法定义如下:
logging.Formatter.__init__(fmt=None, datefmt=None, style=‘%‘)
可见,该构造方法接收3个可选参数:
下图大致表述了日志流的处理流程
我们来描述下上面这个图的日志流处理流程:
可见,一条日志信息要想被最终输出需要依次经过以下几次过滤:
需要说明的是:
1.关于上面第9个步骤,如果propagate值为1,那么日志消息会直接传递交给上一级logger的handlers进行处理,此时上一级logger的日志等级并不会对该日志消息进行等级过滤。
2.使用getLogger()方法的时候,如果要返回的日志器名字相同,返回的为同一个日志器,因为它的内部是用单例生成的,所以当多个对象使用同一日志器然后进行设置时,新的设置会覆盖旧的设置。而当输出的时候,有几个对象要显示,就显示几遍日志。
3.日志器是一个树形结构,比如:getLogger("mylogger.sontree")mylogger是root的孩子,sontree是mylogger的孩子,root的孙子。
4.当我们使用子层的日志器的时候,它会默认往上去找父级直到找到root,有几层显示几遍日志:
例如:
View Codeimport logging logger = logging.getLogger() # 获得一个Logger实例化对象,由于没写参数返回的root日志器 ch = logging.StreamHandler() # 创建一个StreamHandler对象,用于输出到控制台 logger.addHandler(ch) # 为Logger对象添加StreamHandler对象 logger.setLevel("ERROR") logger1 = logging.getLogger("my_log") # 获得一个名为Logger实例化对象 logger1.addHandler(ch) # # 为Logger对象添加StreamHandler对象 logger1.setLevel("DEBUG") logger.debug(‘logger debug message‘) logger.info(‘logger info message‘) logger.warning(‘logger warning message‘) logger.error(‘logger error message‘) logger.critical(‘logger critical message‘) logger1.debug(‘logger1 debug message‘) logger1.info(‘logger1 info message‘) logger1.warning(‘logger1 warning message‘) logger1.error(‘logger1 error message‘) logger1.critical(‘logger1 critical message‘) # 输出结果为: # logger error message # logger critical message # logger1 debug message # logger1 debug message # logger1 info message # logger1 info message # logger1 warning message # logger1 warning message # logger1 error message # logger1 error message # logger1 critical message # logger1 critical message例子中,logger不写参数获取的日志器为root,它是正常显示的,而logger1获取的则是名为my_log的日志器,它除了打印自己的,还向上去找,找到了它的父级就是顶级的root,所以也打印了一遍,这样就看到了后面打印了两遍的日志。你可以再按上面说到创建一个my_log日志器的子日志器进行测试。
5.上面提到了会重复打印的问题,那么我不想这样怎么办。那就是把例子中的logger.addHandler(ch) 注释了,不让父日志器的handler工作就行了。所以我们需要注意的就是每当一个日志器的父日志器有输出的时候,它就会重复输出一次。
现在,我们对logging模块的重要组件及整个日志流处理流程都应该有了一个比较全面的了解,下面我们来看一个例子。
现在有以下几个日志记录的需求:
import logging import logging.handlers import datetime logger = logging.getLogger(‘mylogger‘) logger.setLevel(logging.DEBUG) rf_handler = logging.handlers.TimedRotatingFileHandler(‘all.log‘, when=‘midnight‘, interval=1, backupCount=7, atTime=datetime.time(0, 0, 0, 0)) rf_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")) f_handler = logging.FileHandler(‘error.log‘) f_handler.setLevel(logging.ERROR) f_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s")) logger.addHandler(rf_handler) logger.addHandler(f_handler) logger.debug(‘debug message‘) logger.info(‘info message‘) logger.warning(‘warning message‘) logger.error(‘error message‘) logger.critical(‘critical message‘)
all.log文件输出
2018-08-13 11:00:58,246 - DEBUG - debug message
2018-08-13 11:00:58,247 - INFO - info message
2018-08-13 11:00:58,247 - WARNING - warning message
2018-08-13 11:00:58,247 - ERROR - error message
2018-08-13 11:00:58,247 - CRITICAL - critical message
error.log文件输出
2018-08-13 11:00:58,247 - ERROR - bin.py[:21] - error message
2018-08-13 11:00:58,247 - CRITICAL - bin.py[:22] - critical message
标签:info ict pat smtp 输出 重要 ctime ica 理解
原文地址:https://www.cnblogs.com/kuxingseng95/p/9464347.html