警告
本文最后更新于 2019-01-13 ,文中内容可能已过时。
最近一直想自己的批量框架,参考了POC-T框架和sqlmap的框架结构,发现logging模块被大量用来处理控制台输出以及日志记录,鉴于我自己也要写框架,那么本文就记录下我的logging模块学习记录。
在开发过程中,如果程序出现了问题,我们可以使用编辑器的Debug模式来检查bug,但是在发布之后,我们的程序相当于在一个黑盒状态去运行,我们只能看到运行效果,可是程序难免出错,这种情况的话我们就需要日志模块来记录程序当前状态、时间状态、错误状态、标准输出等,这样不论是正常运行还是出现报错,都有记录,我们可以针对性的快速排查问题。
因此,日志记录对于程序的运行状态以及debug都起到了很高效的作用。如果一个程序没有标准的日志记录,就不能算作一个合格的开发者。
logging对输出进行了分级,print没有 logging具有更灵活的格式化功能,比如运行时间、模块信息 print输出都在控制台上,logging可以输出到任何位置,比如文件甚至是远程服务器 模块 用途 Logger 记录日志时创建的对象,调用其方法来传入日志模板和信息生成日志记录 Log Record Logger对象生成的一条条记录 Handler 处理日志记录,输出或者存储日志记录 Formatter 格式化日志记录 Filter 日志过滤器 Parent Handler Handler之间存在分层关系
1
2
3
4
5
6
7
8
9
10
11
12
13
import logging
logger = logging . getLogger ( "Your Logger" )
logger . setLevel ( logging . DEBUG )
handler = logging . StreamHandler ()
formatter = logging . Formatter ( fmt = ' %(asctime)s - %(name)s - %(levelname)s - %(message)s ' , datefmt = '%Y/%m/ %d %H:%M:%S' )
handler . setFormatter ( formatter )
logger . addHandler ( handler )
logger . info ( "this is info msg" )
logger . debug ( "this is debug msg" )
logger . warning ( "this is warn msg" )
logger . error ( "this is error msg" )
输出
1
2
3
4
2019/01/13 13:21:17 - Your Logger - INFO - this is info msg
2019/01/13 13:21:17 - Your Logger - DEBUG - this is debug msg
2019/01/13 13:21:17 - Your Logger - WARNING - this is warn msg
2019/01/13 13:21:17 - Your Logger - ERROR - this is error msg
我们来理解下这个实例。
首先创建了一个logger
对象作为生成日志记录的对象,然后设置输出级别为DEBUG
,然后创建了一个StreamHandler
对象handler
,来处理日志,随后创建了一个formatter
对象来格式化输出日志记录,然后把formatter
赋给handler
,最后把handler
处理器添加到我们的logger
对象中,完成了整个处理流程。
知道整个流程之后我们来看一些细的东西。
logging
模块中自带了几个日志级别
等级 数值 对应方法 CRITICAL 50 logger.critical(“msg”) FATAL 50 logger.fatal(“msg”) ERROR 40 logger.error(“msg”) WARNING 30 logger.warning(“msg”) WARN 30 ~~logger.warn(“msg”)~~废弃 INFO 20 logger.info(“msg”) DEBUG 10 logger.debug(“msg”) NOTSET 0 无
在我们的实例中我们设置了输出级别为DEBUG
1
logger . setLevel ( logging . DEBUG )
那么在DEBUG
级别之下的也就是NOTSET
级别的不会被输出。
如果我们把级别设置为INFO
,那么我们实例的输出应该是
1
2
3
2019 / 01 / 13 13 : 21 : 17 - Your Logger - INFO - this is info msg
2019 / 01 / 13 13 : 21 : 17 - Your Logger - WARNING - this is warn msg
2019 / 01 / 13 13 : 21 : 17 - Your Logger - ERROR - this is error msg
只会输出比INFO级别高的日志。
4.2 Handler logging提供的Handler有很多,我简单列举几种
种类 位置 用途 StreamHandler logging.StreamHandler 日志输出到流,可以是 sys.stderr,sys.stdout 或者文件 FileHandler logging.FileHandler 日志输出到文件 SMTPHandler logging.handlers.SMTPHandler 远程输出日志到邮件地址 SysLogHandler logging.handlers.SysLogHandler 日志输出到syslog HTTPHandler logging.handlers.HTTPHandler 通过”GET”或者”POST”远程输出到HTTP服务器
fmt参数和datefmt两个参数分别对应日志记录的格式化和时间的格式化。
fmt可用的占位符简单列举几种,更多请参考这里
占位符 作用 %(levelname)s 打印日志级别的名称 %(pathname)s 打印当前执行程序的路径,其实就是sys.argv[0]。 %(filename)s 打印当前执行程序名。 %(funcName)s 打印日志的当前函数。 %(lineno)d 打印日志的当前行号。 %(asctime)s 打印日志的时间。 %(thread)d 打印线程ID。 %(threadName)s 打印线程名称。 %(process)d 打印进程ID。 %(processName)s 打印线程名称。 %(module)s 打印模块名称。 %(message)s 打印日志信息。
1
2
3
4
5
6
7
try :
result = 10 / 0
except Exception :
logger . error ( 'Faild to get result' , exc_info = True )
# 或者用下面这个
# logging.exception('Error')
logger . info ( 'Finished' )
输出
1
2
3
4
5
6
2019/01/13 14:11:18 - Your Logger - ERROR - Faild to get result
Traceback ( most recent call last) :
File "E:/Python/test.py" , line 22, in <module>
result = 10 / 0
ZeroDivisionError: division by zero
2019/01/13 14:11:18 - Your Logger - INFO - Finished
这样会更合理的捕获异常信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import logging
INFO , WARN , ERROR , SUCCESS = range ( 1 , 5 )
# print(SYSINFO, WARN, ERROR, SUCCESS)
logging . addLevelName ( INFO , '*' )
logging . addLevelName ( WARN , '!' )
logging . addLevelName ( ERROR , 'x' )
logging . addLevelName ( SUCCESS , '+' )
logger = logging . getLogger ( 'LOGGER' )
handler = logging . StreamHandler ()
formatter = logging . Formatter ( fmt = ' %(asctime)s [ %(levelname)s ] %(message)s ' , datefmt = '%Y/%m/ %d %H:%M:%S' )
handler . setFormatter ( formatter )
logger . addHandler ( handler )
logger . setLevel ( INFO )
logger . log ( INFO , "INFO" )
logger . log ( WARN , "WARN" )
logger . log ( ERROR , "ERROR" )
logger . log ( SUCCESS , "SUCCESS" )
输出
1
2
3
4
2019/01/13 14:17:59 [ *] INFO
2019/01/13 14:17:59 [ !] WARN
2019/01/13 14:17:59 [ x] ERROR
2019/01/13 14:17:59 [ +] SUCCESS
先定义级别和数值,然后调用addLevelName(级别名,'输出名')
。记得数值不能小于等于0 ,注意输出日志的级别。
用到了一个第三方的脚本ansistrm.py
,下载地址https://gist.github.com/Y4er/6300ccff3a6628ea7bda24e514013476 原作者脚本不支持win10,我修复了一下。
将这个脚本ansistrm.py
和你的log.py
放到同一目录,然后log.py
如下内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2019/1/12 21:01
# @Author : Y4er
# @Site : http://Y4er.com
# @File : log.py
import logging
INFO , WARN , ERROR , SUCCESS = range ( 1 , 5 )
# print(SYSINFO, WARN, ERROR, SUCCESS)
logging . addLevelName ( INFO , '*' )
logging . addLevelName ( WARN , '!' )
logging . addLevelName ( ERROR , 'x' )
logging . addLevelName ( SUCCESS , '+' )
logger = logging . getLogger ( 'YOUR LOGGER' )
try :
from ansistrm import ColorizingStreamHandler
handle = ColorizingStreamHandler ()
handle . level_map [ logging . getLevelName ( '*' )] = ( None , 'cyan' , False )
handle . level_map [ logging . getLevelName ( '+' )] = ( None , 'green' , False )
handle . level_map [ logging . getLevelName ( 'x' )] = ( None , 'red' , False )
handle . level_map [ logging . getLevelName ( '!' )] = ( None , 'yellow' , False )
except Exception as e :
print ( e )
handle = logging . StreamHandler ()
formatter = logging . Formatter ( ' %(asctime)s - [ %(levelname)s ] %(message)s ' , '%Y/%m/ %d %H:%M:%S' )
handle . setFormatter ( formatter )
logger . addHandler ( handle )
logger . setLevel ( INFO )
class LOGGER :
@staticmethod
def info ( msg ):
return logger . log ( INFO , msg )
@staticmethod
def warning ( msg ):
return logger . log ( WARN , msg )
@staticmethod
def error ( msg ):
return logger . log ( ERROR , msg )
@staticmethod
def success ( msg ):
return logger . log ( SUCCESS , msg )
LOGGER . info ( "INFO msg" )
LOGGER . warning ( "warning msg" )
LOGGER . error ( "error msg" )
LOGGER . success ( "success msg" )
在这个脚本中,我写了一个类以及其下的四个静态方法,那么可以这么调用
1
2
3
4
LOGGER . info ( "INFO msg" )
LOGGER . warning ( "warning msg" )
LOGGER . error ( "error msg" )
LOGGER . success ( "success msg" )
运行效果:
是时候抛弃print
了!
参考链接
Python中logging模块的基本用法 - 崔庆才老师
原版ansistrm.py - vsajip
修复ansistrm.py以支持win10