5.12 logging 日志模块
-
报警等级
CRITICAL = 50 # 最高
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0 # 最低 -
日志处理本质:Logger/FileHandler/Formatter
应用:统计用;做故障排除debug;记录错误,完成代码优化
# 示例一 import logging file_handler1 = logging.FileHandler('x2.log', 'a', encoding='utf-8') # 构造参数 fmt1 = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s") file_handler1.setFormatter(fmt1) # file_handler2 = logging.FileHandler('x2.log', 'a', encoding='utf-8') # fmt2 = logging.Formatter(fmt="%(asctime)s: %(message)s") # file_handler2.setFormatter(fmt2) logger = logging.Logger('xxxxxx', level=logging.ERROR) logger.addHandler(file_handler1) # logger.addHandler(file_handler2) # 示例二 import logging logging.basicConfig( # 函数各参数 filename='cmdb1.log', # 日志文件名称 format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', # 指定日志输出格式和内容 datefmt='%Y-%m-%d %H:%M:%S %p', # 指定时间格式 level=logging.ERROR # 日志报警等级 ) # 无效 日志只配置一次 logging.basicConfig( filename='cmdb2.log', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', level=logging.ERROR ) logging.error('alex') # 报警内容 logging.basicConfig函数各参数: filename: 指定日志文件名 filemode: 和file函数意义相同,指定日志文件的打开模式,'w'或'a' format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示: %(levelno)s: 打印日志级别的数值 %(levelname)s: 打印日志级别名称 %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0] %(filename)s: 打印当前执行程序名 %(funcName)s: 打印日志的当前函数 %(lineno)d: 打印日志的当前行号 %(asctime)s: 打印日志的时间 %(thread)d: 打印线程ID %(threadName)s: 打印线程名称 %(process)d: 打印进程ID %(message)s: 打印日志信息 datefmt: 指定时间格式,同time.strftime() level: 设置日志级别,默认为logging.WARNING stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略 ---------------------
logging.basicconfig
-
使用方便
-
不能实现编码问题;不能同时向文件和屏幕输出
-
logging.debug logging.warning
logger对象 复杂的创建流程
-
创建一个logger对象
-
创建一个文件操作符
-
创建一个屏幕操作符
-
创建一个格式
操作;
-
给logger对象绑定 文件操作符
-
给logger对象绑定 屏幕操作符
-
给文件操作符设定格式
-
给屏幕操作符设定格式
import logging
logger = logging.getLogger() # 创建一个logger对象
fh = logging.FileHandler('log.log') # 创建一个文件操作符
sh = logging.StreamHandler() # 创建一个屏幕操作符
logger.addHandler(fh) # 给logger对象绑定 文件操作符
logger.addHandler(sh) # 给logger对象绑定 屏幕操作符
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # 创建一个格式
fh.setFormatter(formatter) # 给文件操作符设定格式
sh.setFormatter(formatter) # 给屏幕操作符设定格式
logger.warning('message') #
-
-
推荐处理日志方式
import logging
file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',)
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
handlers=[file_handler,],
level=logging.ERROR
)
logging.error('你好')# 日志切割
import time
import logging
from logging import handlers
# file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',)
file_handler = handlers.TimedRotatingFileHandler(filename='x3.log', when='s', interval=5, encoding='utf-8')
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
handlers=[file_handler,],
level=logging.ERROR
)
for i in range(1,100000):
time.sleep(1)
logging.error(str(i)) -
注意事项
# 在应用日志时,如果想要保留异常的堆栈信息。
import logging
import requests
logging.basicConfig(
filename='wf.log',
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level=logging.ERROR
)
try:
requests.get('http://www.xxx.com')
except Exception as e:
msg = str(e) # 调用e.__str__方法
logging.error(msg,exc_info=True)
5.13 copy
-
转义符
正则表达式中的转义符在python的字符串中也刚好有转移的作用但是正则表达式中的转义符和字符串中的转义符并没关系,且还容易有冲突,为了避免这种冲突,我们所有的正则都以在工具中的测试结果为结果,然后只需要在正则和待匹配的字符串外面都加r即可
print('\\\\n') # //n
print('\\n') # /n
print(r'\\n') # //n
print(r'\n') # /n -
re.findall 匹配字符串中所有规则的项,返回一个列表;未匹配返回一个空列表
import re
ret = re.findall('\d+','asadf451sdfdfb645d')
print(ret) # ['451', '645'] -
re.search 会从头到尾从带匹配,匹配字符串取出第一个符合条件的项,如果匹配到了,返回一个对象,用group取值;如果没匹配到,返回None,不能用group,会报错
import re
ret = re.search('\d+','asadf451sdfdfb645d')
print(ret) # <_sre.SRE_Match object; span=(5, 8), match='451'> span 是索引 match 是匹配到的项
if ret:
print(ret.group()) # 451
-
re.match 会从头匹配字符串中取出从第一个字符开始是否符合规则,如果符合,就返回对象,用group取值;如果不符合,就返回None,相当于 match = search + ^正则
import re
ret = re.match('\d+','45adf451sdfdfb645d')
print(ret)
if ret:
print(ret.group()) -
re.finditer 在查询的结果超过1个的情况下,能够有效的节省内存,降低空间复杂度,从而也降低了时间复杂度
import re
ret = re.finditer("\d+",'cdfz56x31d144df'*1000)
print(ret) # <callable_iterator object at 0x000002541A7874A8> 迭代器
for i in ret: # 循环迭代出每个元素
print(i.group()) # 56 31 144 ...... -
compile 在同一个正则表达式重复使用多次的时候使用能够减少时间的开销,属于内置函数
import re
ret = re.compile('\d+')
print(ret) # re.compile('\\d+')
r1 = ret.search('alex83')
print(r1) # <_sre.SRE_Match object; span=(4, 6), match='83'>
r2 = ret.findall('wusir74')
print(r2) # ['74']
r3 = ret.finditer('taibai40')
for i in r3:
print(i.group()) # 40 -
re.split() 分割,根据正则规则切割,返回列表,默认不保留切掉的内容
import re
ret1 = re.split('\d\d','alex83wusir74taibai') # 默认自动保留分组中的内容
print(ret1) # ['alex', 'wusir', 'taibai']
ret2 = re.split('\d(\d)','alex83wusir74taibai')
print(ret2) # ['alex', '3', 'wusir', '4', 'taibai'] -
re.sub() 替换,默认替换所有,可以使用替换深度参数
re.subn() 替换,返回元祖
import re
ret1 = re.sub('\d','D','alex83wusir74taibai')
print(ret1) # alexDDwusirDDtaibai
ret2 = re.sub('\d','D','alex83wusir74taibai',1)
print(ret2) # alexD3wusir74taibai
ret3 = re.subn('\d','D','alex83wusir74taibai')
print(ret3) # ('alexDDwusirDDtaibai', 4) -
分组
-
findall遇到正则表达式中的分组,会优先显示分组中的内容
import re
ret = re.findall('\d(\d)','sdfgfgvbnk83')
print(ret) # ['3'] -
split遇到正则表达式中的分组,会保留分组中本来应该被切割掉的内容
import re
ret1 = re.split('(\d\d)','alex83wusir74taibai') # 默认自动保留分组中的内容
print(ret1) # ['alex', '83', 'wusir', '74', 'taibai'] -
group(加参数)
s1 = '<h1>wahaha</h1>'
ret = re.search('<(\w+)>(.*?)</\w+>',s1)
print(ret) # <_sre.SRE_Match object; span=(0, 15), match='<h1>wahaha</h1>'>
print(ret.group(0)) # group参数默认为0 表示取整个正则匹配的结果 <h1>wahaha</h1>
print(ret.group(1)) # 取第一个分组中的内容 h1
print(ret.group(2)) # 取第二个分组中的内容 wahaha -
分组命名 (?P<名字>正则表达式)
search 取分组中的内容 通过索引;通过组名取
s1 = '<h1>wahaha</h1>'
ret = re.search('<(?P<tag>\w+)>(?P<cont>.*?)</\w+>',s1)
print(ret) # <_sre.SRE_Match object; span=(0, 15), match='<h1>wahaha</h1>'>
print(ret.group(0)) # group参数默认为0 表示取整个正则匹配的结果 <h1>wahaha</h1>
pprint(ret.group('tag')) # 取tag分组中的内容
print(ret.group('cont')) # 取cont分组中的内容 -
分组引用 (?P=组名) 这个组中的内容必须完全和之前已经存在的组匹配到的内容一模一样
import re
s1 = '<h1>wahaha</h1>'
ret = re.search('<(?P<tag>\w+)>.*?</(?P=tag)>',s1)
print(ret.group('tag')) # h1 -
取消分组优先 (?:)
# 有的时候我们想匹配的内容包含在不相匹配的内容当中,这个时候只需要把不想匹配的先匹配出来,再通过手段去掉
import re
ret=re.findall(r"\d+\.\d+|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
print(ret) # ['1', '2', '60', '', '5', '4', '3']
ret.remove('')
print(ret) # ['1', '2', '60', '5', '4', '3']
-
-
[] 和 [^] 带有特殊意义的元字符到字符组内大部分都会取消它的特殊含义
-
[()+*.]
-
-
[(
\-
)] -的位置决定了它的意义,写在字符组的第一位位置或者最后一个位置就表示一个普通的横杠 -
写在字符组的其他任何位置都会表示一个范围
-
-
练习
# 检测用户输入的内容是否是一个合法的身份证号 网页的合法输入(手机号码 qq号码 银行卡号 邮箱地址)
'^[1-9]\d{14}(\d{2}[\dx])?$'
import re
inp = input('>>>').strip()
re.match('[1-9]\d{14}(\d{2}[\dx])?$',inp) # 首选
re.search('^[1-9]\d{14}(\d{2}[\dx])?$',inp)
re.findall('^[1-9]\d{14}(\d{2}[\dx])?$',inp)
-