python3+Appium自动化10-日志收集
日志概述
日志作用
日志是定位问题的重要手段
日志级别
级别 | 何时使用 |
DEBUG | 调试信息,也是最详细的日志信息 |
INFO | 证明事情按预期工作 |
WARNING | 表明发生了一些意外,或者不就的将来(如磁盘满了)。软件还是正常工作 |
ERROR | 由于更严重的问题,软件已不能执行一些功能了 |
CRITICAL | 严重错误,表明软件已不能继续运行了 |
日志需要按照info、debug、error等级别来进行区分。一般情况,普通的输出直接用info类型,调试时用debug类型,如果预计有错误需要用error类型的日志,一般情况info级别最为合适。
logging模块
简介
Python中的logging模块提供了通用的日志系统,这个模块提供不同的日志级别,并可以采用不同的方式记录日志
#导入logging模块 import logging
logging构成
- Logger 记录器,用于设置日志采集
- Handler 处理器,将日志记录发送至合适的路径
- Filter 过滤器,提供了更好的控制,它可以决定输出哪些日志记录
- Formatter 格式化器,指明了最终输出中日志的格式
Logger记录器
Logger是一个树形层级结构,在使用接口debug,info,warn,error,critical;使用之前必须创建Logger实例,即创建一个记录器,如果没有显式的进行创建,则默认创建一个root logger,并应用默认的日志级别(WARN),Handler和Formatter。
方法:
basicConfig(**kwargs) 为日志记录系统做基本配置。
部分参数:
filename 指定日志文件名称
filemode 指定打开文件的模式,如果指定了filename(如果文件模式未指定,则默认为'a)
Tips:文件读写模式
- w 以写方式打开,
- W 文件若存在,首先要清空,然后(重新)创建
- a 以追加模式打开 (从 EOF 开始, 必要时创建新文件)
- r+ 以读写模式打开
- w+ 以读写模式打开 (参见 w )
- a+ 以读写模式打开 (参见 a )
format 为处理程序使用指定的格式字符串。
datefmt 使用指定的日期/时间格式。样式如果指定了格式字符串,则使用它来指定 格式字符串的类型.
level 将根记录器级别设置为指定级别。
演示代码如下:
1 import logging 2 3 # logging.basicConfig(level=logging.DEBUG) 4 logging.basicConfig(level=logging.INFO) 5 # logging.basicConfig() 6 7 logging.debug('debug info') 8 logging.info('hello log!') 9 logging.warning('warning info') 10 logging.error('error info') 11 logging.critical('critical info')
Handle处理器
Handler 处理器,将日志记录发送至合适的路径,Handler处理器类型有很多种,比较常用的有三个:
- StreamHandler
将日志记录输出发送到诸如sys.stdout,sys.stderr或任何类似文件流的对象。上面例子就是输出到控制台
- FileHanlder
将日志记录输出发送到磁盘文件。 它继承了StreamHandler的输出功能
logging.basicConfig(filename='runlog.log',level=logging.DEBUG)
- NullHandler
不做任何格式化或输出。 它本质上是一个开发人员使用的“无操作”处理程序。
Filter过滤器
Handlers和Loggers可以使用Filters来完成比级别更复杂的过滤。
Formatter
使用Formatter对象设置日志信息最后的规则、结构和内容,默认的时间格式为%Y-%m-%d %H:%M:%S
格式 |
描述 |
%(levelno)s |
打印日志级别的数值 |
%(levelname)s |
打印日志级别名称 |
%(pathname)s |
打印当前执行程序的路径 |
%(filename)s |
打印当前执行程序名称 |
%(funcName)s |
打印日志的当前函数 |
%(lineno)d |
打印日志的当前行号 |
%(asctime)s |
打印日志的时间 |
%(thread)d |
打印线程id |
%(threadName)s |
打印线程名称 |
%(process)d |
打印进程ID |
%(message)s |
打印日志信息 |
使用方法:
logging.basicConfig(level=logging.INFO,filename='runlog.log', format='%(asctime)s %(filename)s[line:%(lineno)d]%(levelname)s%(message)s')
实战操作:log.py
1 #coding=utf-8 2 from appium import webdriver 3 from selenium.common.exceptions import NoSuchElementException 4 import yaml 5 #导入logging模块 6 import logging 7 import time 8 9 file=open('desired_caps.yaml','r') 10 data=yaml.load(file) 11 #日志 12 logging.basicConfig(level=logging.INFO,filename='runlog.log', 13 format='%(asctime)s %(filename)s[line:%(lineno)d]%(levelname)s%(message)s') 14 logging.info('start app...') 15 16 driver = webdriver.Remote('http://'+str(data['ip'])+':'+str(data['port'])+'/wd/hub', data) 17 18 #检测跳过按钮 19 def check_skipBtn(): 20 print('check skipBtn') 21 try: 22 skipBtn=driver.find_element_by_id("com.baozhenart.artmall:id/tv_skip") 23 except NoSuchElementException: 24 print('no skipBtn') 25 else: 26 skipBtn.click() 27 #检测是否有叉号 28 def check_closeBtn(): 29 print('check closeBtn') 30 try: 31 closeBtn=driver.find_element_by_id("com.baozhenart.artmall:id/iv_close") 32 except NoSuchElementException: 33 print('no closeBtn') 34 else: 35 closeBtn.click() 36 check_skipBtn() 37 time.sleep(5) 38 check_closeBtn()
打印日志内容
2018-07-12 19:05:11,214 log.py[line:13]INFOstart app...
日志格式配置
将log输出格式,输出路径等参数抽离出来作为一个配置表,如下所示:
log.conf
[loggers] keys=root,infoLogger [logger_root] level=DEBUG handlers=consoleHandler,fileHandler [logger_infoLogger] handlers=consoleHandler,fileHandler qualname=infoLogger propagate=0 [handlers] keys=consoleHandler,fileHandler [handler_consoleHandler] class=StreamHandler level=INFO formatter=form02 args=(sys.stdout,) [handler_fileHandler] class=FileHandler level=INFO formatter=form01 args=('runlog.log', 'a') [formatters] keys=form01,form02 [formatter_form01] format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s [formatter_form02] format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
在需要调用的模块增加如下代码
1 import logging 2 import logging.config 3 4 CON_LOG='log.conf'#定义配置表的名称,将其放在常量中 5 #fileConfig(fname, defaults=None, disable_existing_loggers=True) 6 # 该放在作用是从ConfigParser格式的文件中读取日志配置,同时如果当前脚本有配置log参数,则覆盖当前log配置选项 7 logging.config.fileConfig(CON_LOG) 8 #定义采集器 9 logging=logging.getLogger()
实战代码:
1 #coding=utf-8 2 from appium import webdriver 3 from selenium.common.exceptions import NoSuchElementException 4 import yaml 5 import time 6 #导入logging模块 7 import logging 8 import logging.config 9 10 file=open('desired_caps.yaml','r') 11 data=yaml.load(file) 12 13 CON_LOG='log.conf'#定义配置表的名称,将其放在常量中 14 #fileConfig(fname, defaults=None, disable_existing_loggers=True) 15 # 该放在作用是从ConfigParser格式的文件中读取日志配置,同时如果当前脚本有配置log参数,则覆盖当前log配置选项 16 logging.config.fileConfig(CON_LOG) 17 #定义日志采集器 18 logging=logging.getLogger() 19 20 logging.info('start app...') 21 driver = webdriver.Remote('http://'+str(data['ip'])+':'+str(data['port'])+'/wd/hub', data) 22 23 #检测跳过按钮 24 def check_skipBtn(): 25 logging.info('check_skipBtn') 26 try: 27 skipBtn=driver.find_element_by_id("com.baozhenart.artmall:id/tv_skip") 28 except NoSuchElementException: 29 logging.info('no skipBtn') 30 else: 31 skipBtn.click() 32 #检测是否有叉号 33 def check_closeBtn(): 34 logging.info('check closeBtn') 35 try: 36 closeBtn=driver.find_element_by_id("com.baozhenart.artmall:id/iv_close") 37 except NoSuchElementException: 38 logging.info('no closeBtn') 39 else: 40 closeBtn.click() 41 check_skipBtn() 42 time.sleep(5) 43 check_closeBtn()