簡介
生活中的日志是記錄你生活的點點滴滴,讓它把你內心的世界表露出來,更好的詮釋自己的內心世界,而電腦里的日志是有價值的信息寶庫。
日志文件是專門用于記錄系統操作事件的記錄文件或文件集合,操作系統有操作系統日志文件,數據庫系統有數據庫系統日志文件,等等。
系統日志文件是包含關于系統消息的文件,包括內核、服務、在系統上運行的應用程序等。不同的日志文件記載不同的信息。例如,有的是默認的系統日志文件,有的記載特定任務。
在數據庫中用事務日志文件記錄數據的修改操作,其中的每條日志記錄或者記錄所執行的邏輯操作,或者記錄已修改數據的前像和后像。前像是操作執行前的數據復本;后像是操作執行后的數據復本。
問題思考
在自動化腳本運行過程中, IDE控制臺一般都會輸出運行日志。但是如果測試項目是在liunx服務器上面運行,沒有IDE控制臺輸出log,那么我們該如何采集日志? 元芳,你怎么看?
日志概述
日志作用
不管是在項目開發還是測試過程中,項目運行一旦出現問題日志信息就非常重要了。日志是定位問題的重要手段,就像偵探人員要根據現場留下的線索來推斷案情。
日志級別
腳本運行會有很多的情況,比如調試信息、報錯異常信息等。日志要根據這些不同的情況來繼續分級管理,不然對于排查問題的篩選會有比較大的干擾。 。日志一般定位的級別如下:
?
級別 |
何時使用 |
DEBUG |
調試信息,也是最詳細的日志信息。 |
INFO |
證明事情按預期工作。 |
WARNING |
表明發生了一些意外,或者不久的將來會發生問題(如‘磁盤滿了’)。軟件還是在正常工作。 |
ERROR |
由于更嚴重的問題,軟件已不能執行一些功能了。 |
CRITICAL |
嚴重錯誤,表明軟件已不能繼續運行了。 |
首先我們日志需要按照 info、debug、error等級別來進行區分的。當然這個級別可以自己去設置。在一般的情況下我們普通的輸出我們直接用info類型,調試的時候用debug類型,如果預計有錯誤時那么我們就需要用error類型的日志,一般情況去info級別最為合適。
日志格式
日志格式化是為了提高日志的可閱讀性,比如: 時間 +模塊+行數+日志具體信息 ?的內容格式。如果日志信息雜亂無章的全部輸出來,這樣也不利于定位問題。如下所示就是日志格式化輸出,非常便于閱讀查看。
2019 - 08 - 14 22 : 02 : 35 , 633 backup.py[line: 18 ] INFO ============test backup================ 2019 - 08 - 14 22 : 02 : 39 , 253 backup.py[line: 20 ] INFO click backup button 2019 - 08 - 14 22 : 02 : 54 , 025 backup.py[line: 23 ] INFO click next button 2019 - 08 - 14 22 : 03 : 09 , 280 common_fun.py[line: 83 ] INFO Start send Email.. 2019 - 08 - 14 22 : 03 : 11 , 840 common_fun.py[line: 91 ] INFO Send Email finish! 2019 - 08 - 14 22 : 03 : 13 , 305 common_fun.py[line: 168 ] INFO get backup screenshot 2019 - 08 - 14 23 : 36 : 00 , 238 backup.py[line: 17 ] INFO ============test backup================ 2019 - 08 - 14 23 : 36 : 04 , 530 backup.py[line: 19 ] INFO click backup button 2019 - 08 - 14 23 : 37 : 20 , 107 backup.py[line: 17 ] INFO ============test
日志位置
一個項目中會有很多的日志采集點,而日志采集點必須結合業務屬性來設置。比如在登錄代碼執行前可以插入 “準備登錄..”日志信息,如果登錄完成之后,再設置登錄的提示日志就會給人造成誤解,無法判斷到底是登錄之前的問題還是登錄之后的問題,因此日志采集點的位置很重要。
logging模塊
簡介
Python的logging模塊提供了通用的日志系統,這個模塊提供不同的日志級別,并可以采用不同的方式記錄日志,比如文件,HTTP GET/POST,SMTP,Socket等,甚至可以自己實現方式記錄日志。
# 導入 logging 模塊
import?logging
logging模塊官方文檔
logging構成
logging模塊包括 logger,Handler,Filter,Formatter 四個部分。
- Logger 記錄器,用于設置日志采集。
- Handler 處理器,將日志記錄發送至合適的路徑。
- Filter 過濾器,提供了更好的粒度控制,它可以決定輸出哪些日志記錄。
- Formatter 格式化器,指明了最終輸出中日志的格式。
Logger 記錄器
Logger是一個樹形層級結構,在使用接口debug,info,warn,error,critical;使用之前必須創建Logger實例,即創建一個記錄器,如果沒有顯式的進行創建,則默認創建一個root logger,并應用默認的日志級別(WARN),處理器Handler(StreamHandler,即將日志信息打印輸出在標準輸出上),和格式化器Formatter(默認的格式即為第一個簡單使用程序中輸出的格式)。
方法:
basicConfig(**kwargs) 為日志記錄系統做基本配置。
部分參數
filename ?指定日志文件名稱
filemode ? 指定打開文件的模式,如果指定了 filename(如果文件模式未指定,則默認為'a)
Tips:文件讀寫模式
- w 以寫方式打開,
- W 文件若存在,首先要清空,然后(重新)創建
- a 以追加模式打開 (從 EOF 開始, 必要時創建新文件)
- r+ 以讀寫模式打開
- w+ 以讀寫模式打開 (參見 w )
- a+ 以讀寫模式打開 (參見 a )
format ?為處理程序使用指定的格式字符串。
datefmt ? 使用指定的日期 /時間格式。樣式如果指定了格式字符串,則使用它來指定 格式字符串的類型.
level ?將根記錄器級別設置為指定級別。
logging_test.py
# coding=utf- 8 # 1 .先設置編碼,utf- 8可支持中英文,如上,一般放在第一行 # 2 .注釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019 - 8 - 14 @author: 北京 -宏哥 QQ交流群: 707699217 Project:學習和使用appium自動化測試 -代碼和數據分離- 日志收集 ''' # 3 .導入模塊 import logging # logging.basicConfig(level = logging.DEBUG) logging.basicConfig(level = logging.INFO) logging.debug( ' debug info ' ) logging.info( ' hello 宏哥 ' ) logging.warning( ' warning info ' ) logging.error( ' error info ' ) logging.critical( ' critical info ' )
Handler 處理器
Handler 處理器,將日志記錄發送至合適的路徑,Handler處理器類型有很多種,比較常用的有三個:
1.StreamHandler
將日志記錄輸出發送到諸如 sys.stdout,sys.stderr或任何類似文件流的對象。上面例子就是輸出到控制臺
2.FileHandler
將日志記錄輸出發送到磁盤文件。 它繼承了 StreamHandler的輸出功能。
logging.basicConfig(filename= ' runlog.log ' ,level=logging.DEBUG)
3.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(filename= ' runlog.log ' ,level= logging.DEBUG, format = ' %(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s ' )? ? ? ? ? ? ? ?
輸出結果:
2019 - 08 - 14 14 : 35 : 19 , 430 logging_test.py[line: 6 ]DEBUGdebug info 2019 - 08 - 14 14 : 35 : 19 , 430 logging_test.py[line: 7 ]INFOhello hongge 2019 - 08 - 14 14 : 35 : 19 , 430 logging_test.py[line: 8 ]WARNINGwarning info 2019 - 08 - 14 14 : 35 : 19 , 430 logging_test.py[line: 9 ]ERRORerror info 2019 - 08 - 14 14 : 35 : 19 , 430 logging_test.py[line: 10 ]CRITICALcritical info
Logging實戰操作
測試場景
將前面所學的啟動考研幫 App的腳本增加log采集功能,設置指定的日志格式輸出,并將日志保存到指定文件。
代碼實現
kyb_logger.py
# coding=utf- 8 # 1 .先設置編碼,utf- 8可支持中英文,如上,一般放在第一行 # 2 .注釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019 - 8 - 14 @author: 北京 -宏哥 QQ交流群: 707699217 Project:學習和使用appium自動化測試 -代碼和數據分離- 日志收集 ''' # 3 .導入模塊 from appium import webdriver import yaml import logging from selenium.common.exceptions import NoSuchElementException file =open( ' ./desired_caps.yaml ' , ' r ' ) data = yaml.load(file) logging.basicConfig(level =logging.INFO,filename= ' runlog.log ' , format = ' %(asctime)s %(filename)s[line:%(lineno)d]%(levelname)s%(message)s ' ) desired_caps = {} desired_caps[ ' platformName ' ]=data[ ' platformName ' ] desired_caps[ ' platformVersion ' ]=data[ ' platformVersion ' ] desired_caps[ ' deviceName ' ]=data[ ' deviceName ' ] desired_caps[ ' app ' ]=data[ ' app ' ] desired_caps[ ' appPackage ' ]=data[ ' appPackage ' ] desired_caps[ ' appActivity ' ]=data[ ' appActivity ' ] desired_caps[ ' noReset ' ]=data[ ' noReset ' ] logging.info( ' start app... ' ) driver =webdriver.Remote( ' http:// ' +str(data[ ' ip ' ])+ ' : ' +str(data[ ' port ' ])+ ' /wd/hub ' ,desired_caps) def check_cancelBtn(): logging.info( ' check cancelBtn ' ) try : cancelBtn = driver.find_element_by_id( ' android:id/button2 ' ) except NoSuchElementException: logging.info( ' no cancelBtn ' ) else : cancelBtn.click() def check_skipBtn(): logging.info( ' check skipBtn ' ) try : skipBtn = driver.find_element_by_id( ' com.tal.kaoyan:id/tv_skip ' ) except NoSuchElementException: logging.info( ' no skipBtn ' ) else : skipBtn.click() check_cancelBtn() check_skipBtn()
runlog.log
2019 - 08 - 14 15 : 27 : 38 , 964 kyb_logger.py[line: 32 ]INFOstart app... 2019 - 08 - 14 15 : 27 : 47 , 641 poolmanager.py[line: 358 ]INFORedirecting http: // 127.0.0.1:4723/wd/hub/session -> http://127.0.0.1 :4723/wd/hub/session/dfc8e7e7-71cc-4f0b-9aa6-5db0fdc98a84 2019 - 08 - 14 15 : 27 : 47 , 644 kyb_logger.py[line: 36 ]INFOcheck cancelBtn 2019 - 08 - 14 15 : 27 : 49 , 442 kyb_logger.py[line: 46 ]INFOcheck skipBtn
問題思考
前面我們已經實現了在代碼中增添 log,log也按照預期的采集到了,看似一切完美無瑕。但是該log配置的作用域也只是控制當前的腳本 。 然而一個自動化項目中通常有很多模塊腳本,難道我們需要每一個腳本都這樣配置嗎? 元芳,你怎么看?
?
解決思路
回大人,以我跟隨大人多年的斷案經驗: 將這些日志配置的參數抽離出來,各個模塊需要使用則直接引用即可。
日志格式配置
將 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
在需要調用的模塊增加如下代碼:
import logging import logging.config CON_LOG = ' log.conf ' logging.config.fileConfig(CON_LOG) logging =logging.getLogger()
方法:
fileConfig(fname, defaults=None, disable_existing_loggers=True)
該放在作用是從 ConfigParser格式的文件中讀取日志配置,同時如果當前腳本有配置log參數,則覆蓋當前log配置選項。
代碼實現
kyb_logconf.py
# coding=utf- 8 # 1 .先設置編碼,utf- 8可支持中英文,如上,一般放在第一行 # 2 .注釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019 - 8 - 14 @author: 北京 -宏哥 QQ交流群: 707699217 Project:學習和使用appium自動化測試 -代碼和數據分離- 日志收集 ''' # 3 .導入模塊 from appium import webdriver import yaml import logging import logging.config from selenium.common.exceptions import NoSuchElementException file =open( ' ./desired_caps.yaml ' , ' r ' ) data = yaml.load(file) CON_LOG = ' log.conf ' logging.config.fileConfig(CON_LOG) logging = logging.getLogger() desired_caps = {} desired_caps[ ' platformName ' ]=data[ ' platformName ' ] desired_caps[ ' platformVersion ' ]=data[ ' platformVersion ' ] desired_caps[ ' deviceName ' ]=data[ ' deviceName ' ] desired_caps[ ' app ' ]=data[ ' app ' ] desired_caps[ ' appPackage ' ]=data[ ' appPackage ' ] desired_caps[ ' appActivity ' ]=data[ ' appActivity ' ] desired_caps[ ' noReset ' ]=data[ ' noReset ' ] logging.info( ' start app... ' ) driver =webdriver.Remote( ' http:// ' +str(data[ ' ip ' ])+ ' : ' +str(data[ ' port ' ])+ ' /wd/hub ' ,desired_caps) def check_cancelBtn(): logging.info( ' check cancelBtn ' ) try : cancelBtn = driver.find_element_by_id( ' android:id/button2 ' ) except NoSuchElementException: logging.info( ' no cancelBtn ' ) else : cancelBtn.click() def check_skipBtn(): logging.info( ' check skipBtn ' ) try : skipBtn = driver.find_element_by_id( ' com.tal.kaoyan:id/tv_skip ' ) except NoSuchElementException: logging.info( ' no skipBtn ' ) else : skipBtn.click() check_cancelBtn() check_skipBtn()
?小結
元芳,今天分享的知識快要結束,你給總結一下,把結案文書寫一下,交給我。元芳,你怎么看?日志的收集。
?好了好了,大人,元芳今天太累了,所以說出如此大逆不道的話,求大人原諒他,結案文書我稍后交給大人。
結案文書:
1.Logger是一個樹形層級結構
Logger可以包含一個或多個Handler和Filter,即Logger與Handler或Fitler是一對多的關系;
一個Logger實例可以新增多個Handler,一個Handler可以新增多個格式化器或多個過濾器,而且日志級別將會繼承。
?
?
2.Logging工作流程
logging模塊使用過程
- 第一次導入logging模塊或使用reload函數重新導入logging模塊,logging模塊中的代碼將被執行,這個過程中將產生logging日志系統的默認配置。
- 自定義配置(可選)。logging標準模塊支持三種配置方式: dictConfig,fileConfig,listen。其中,dictConfig是通過一個字典進行配置Logger,Handler,Filter,Formatter;fileConfig則是通過一個文件進行配置;而listen則監聽一個網絡端口,通過接收網絡數據來進行配置。當然,除了以上集體化配置外,也可以直接調用Logger,Handler等對象中的方法在代碼中來顯式配置。
- 使用logging模塊的全局作用域中的getLogger函數來得到一個Logger對象實例(其參數即是一個字符串,表示Logger對象實例的名字,即通過該名字來得到相應的Logger對象實例)。
- 使用Logger對象中的debug,info,error,warn,critical等方法記錄日志信息。

?
您的肯定就是我進步的動力。
如果你感覺還不錯,就請鼓勵一下吧!記得點波?
推薦?
哦!!!(點擊右邊的小球即可!(
^__^
) 嘻嘻……)
? ? ? ?個人公眾號? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 微信群 ?(微信群已滿100,可以加宏哥的微信拉你進群,請備注:進群)? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
