keil debug如何在watch直接修改变量值_python日志记录系列教程,内置logging模块(一),直接使用logging模块的基础日志记录
前言:成熟的軟件開發(fā)不可避免的要進(jìn)行日志記錄,python內(nèi)置模塊logging提供了強(qiáng)大的日志記錄能力,本文將從多個(gè)角度,由淺入深的介紹logging的常見使用方法和一些基本概念,本此系列文章分為兩篇,本文為系列文章第一篇,介紹實(shí)用logging模塊進(jìn)行基本的日志記錄操作。本文主要都是直接使用 logging.xxxx() 的方式,這是最簡單初步的日志記錄,不涉及任何復(fù)雜的類和對象,這些將會(huì)在下一篇文章中來說明。
一、什么是日志記錄
所謂的日志記錄就是對軟件執(zhí)行時(shí)所發(fā)生事件的一種追蹤方式。軟件開發(fā)人員對他們的代碼添加日志調(diào)用,借此來指示某事件的發(fā)生。一個(gè)事件通過一些包含變量數(shù)據(jù)的描述信息來描述(比如:每個(gè)事件發(fā)生時(shí)的數(shù)據(jù)都是不同的)。開發(fā)者還會(huì)區(qū)分事件的重要性,重要性也被稱為 等級(jí) 或 嚴(yán)重性
1.1 什么時(shí)候使用 Logging
對于簡單的日志使用來說日志功能提供了一系列便利的函數(shù)。它們是 debug(),info(),warning(),error() 和 critical()。想要決定何時(shí)使用日志,請看下表,其中顯示了對于每個(gè)通用任務(wù)集合來說最好的工具。
| 對于命令行或程序的應(yīng)用,結(jié)果顯示在控制臺(tái)。 | print(),這是我們自己常用的,顯示某一些信息,直接打印結(jié)果,但是比較低級(jí) |
| 在對程序的普通操作發(fā)生時(shí)提交事件報(bào)告(比如:狀態(tài)監(jiān)控和錯(cuò)誤調(diào)查) | http://logging.info() 函數(shù)(當(dāng)有診斷目的需要詳細(xì)輸出信息時(shí)使用 logging.debug() 函數(shù)) |
| 提出一個(gè)警告信息基于一個(gè)特殊的運(yùn)行時(shí)事件 | warnings.warn() 位于代碼庫中,該事件是可以避免的,需要修改客戶端應(yīng)用以消除告警 logging.warning() 不需要修改客戶端應(yīng)用,但是該事件還是需要引起關(guān)注 |
| 對一個(gè)特殊的運(yùn)行時(shí)事件報(bào)告錯(cuò)誤 | 引發(fā)異常 |
| 報(bào)告錯(cuò)誤而不引發(fā)異常(如在長時(shí)間運(yùn)行中的服務(wù)端進(jìn)程的錯(cuò)誤處理) | logging.error(), logging.exception() 或 logging.critical() 分別適用于特定的錯(cuò)誤及應(yīng)用領(lǐng)域 |
1.2 日志記錄的5個(gè)等級(jí)
日志功能應(yīng)以所追蹤事件級(jí)別或嚴(yán)重性而定。各級(jí)別適用性如下(以嚴(yán)重程度遞增):
| DEBUG | 細(xì)節(jié)信息,僅當(dāng)診斷問題時(shí)適用。 |
| INFO | 確認(rèn)程序按預(yù)期運(yùn)行,但是要提示一些相關(guān)的信息, |
| WARNING | 表明有已經(jīng)或即將發(fā)生的意外(例如:磁盤空間不足)。程序仍按預(yù)期進(jìn)行,但是會(huì)有警告,可能出現(xiàn)什么錯(cuò)誤。 |
| ERROR | 由于嚴(yán)重的問題,程序的某些功能已經(jīng)不能正常執(zhí)行 |
| CRITICAL | 嚴(yán)重的錯(cuò)誤,表明程序已不能繼續(xù)執(zhí)行 |
以及嚴(yán)重程度排序?yàn)?#xff1a;
debug<info<warning<error<critical默認(rèn)的級(jí)別是``WARNING``,意味著只會(huì)追蹤該級(jí)別以及該級(jí)別以上的事件,當(dāng)然我們可以更改日志配置,重新設(shè)置默認(rèn)值。
另外,我們需要查看所記錄的日志,一般日志輸出會(huì)有兩種形式,
所追蹤事件可以以不同形式處理。最簡單的方式是輸出到控制臺(tái)。另一種常用的方式是寫入磁盤文件。默認(rèn)情況下,日志輸出信息會(huì)顯示在控制臺(tái)上。下面也會(huì)以這兩種方式來加以說明。
1.3 logging模塊初識(shí)
二、logging模塊的常規(guī)基礎(chǔ)操作
2.1 logging日志記錄的基本配置
函數(shù)原型如下:
該函數(shù)支持以下關(guān)鍵字參數(shù)。
| filename | 使用指定的文件名而不是 StreamHandler 創(chuàng)建 FileHandler。在需要將日志寫入到日志文件的時(shí)候使用 |
| filemode | 日志文件的寫入模式.,默認(rèn)的是"a",默認(rèn)是追加的方式,若要每一次都重新寫入,則使用"w" |
| format | 使用的指定格式字符串。 |
| datefmt | 時(shí)間格式的字符串 |
| style | If format is specified, use this style for the format string. One of '%', '{' or '$' for printf-style, str.format() or string.Template respectively. Defaults to '%'. 字符串的格式化方式的選擇,參考下面的style參數(shù)詳解。 |
| level | 設(shè)置根記錄器級(jí)別去指定 level.默認(rèn)的是warning,可以重新指定,比如http://logging.INFO logging.DEBUG 等等, |
| stream | Use the specified stream to initialize the StreamHandler. Note that this argument is incompatible with filename - if both are present, a ValueError is raised.(后面用到了再說) |
| handlers | If specified, this should be an iterable of already created handlers to add to the root logger. Any handlers which don't already have a formatter set will be assigned the default formatter created in this function. Note that this argument is incompatible with filename or stream - if both are present, a ValueError is raised.(后面用到了再說) |
對basicConfig的調(diào)用應(yīng)該在 debug、info等函數(shù)的前面。因?yàn)樗辉O(shè)計(jì)為一次性的配置,只有第一次調(diào)用會(huì)進(jìn)行操作,隨后的調(diào)用不會(huì)產(chǎn)生有效操作。
2.2 將日志寫入文件
2.3 多個(gè)模塊中使用日志記錄
如果你的程序包含多個(gè)模塊,這里有一個(gè)如何組織日志記錄的示例:
如果你運(yùn)行 myapp.py ,你應(yīng)該在 myapp.log 中看到:
我們發(fā)現(xiàn),不同模塊中所記錄的日志信息都被保存到了同一個(gè)日志文件里面了。
2.4 格式化輸出以及記錄相關(guān)的變量值到日志文件
前面有文章專門介紹了python中的字符串格式化的幾種方法,包括使用百分號(hào)%、str.format、string.Template模板等方法,可以參考前面的文章:
python字符串格式化深入詳解(四種方法)
所以,要定義自己的字符串輸出格式,要記錄相關(guān)的變量到字符串中,我們可以這樣做。
要記錄變量數(shù)據(jù),請使用格式字符串作為事件描述消息,并將變量數(shù)據(jù)作為參數(shù)附加。 例如:
如你所見,
logging日志記錄的字符串格式化,將數(shù)據(jù)合并到字符串中所采用的方式是 百分號(hào)% 的形式,但是如果我想要使用其他的字符串格式化的方法怎么辦呢?就需要通過指定style參數(shù)來決定了,style的取值可以是三個(gè),即
- '%':這是默認(rèn)的,即默認(rèn)使用百分號(hào)%格式的字符串格式化方法;
- '{':表示使用str.format()的字符串格式化方法;
- '$':表示使用string.Template的格式化方法;
為什么是默認(rèn)使用百分號(hào) % 格式化工具呢?主要是因?yàn)閘ogging的出現(xiàn)時(shí)間比這兩種格式化方法要早一些,但是并不是說完全不支持,現(xiàn)在完全有其他的方法讓logging支持str.format()和string.Template()這些格式,只需要設(shè)置不同的style參數(shù)值即可。
三、logging模塊的格式化設(shè)置以及時(shí)間格式化
當(dāng)我們看之前的記錄日志的時(shí)候,我們發(fā)現(xiàn),記錄的日志總是下面的格式,如下:
即所謂的:
日志類別嚴(yán)重程度:root:message這樣的格式,那么能不能進(jìn)行更改呢?這個(gè)自然是可以的,怎么更改呢,如下:
3.1 消息顯示的格式設(shè)置——basicConfig的 format 參數(shù)
要更改用于顯示消息的格式,你需要指定要使用的格式:
這將輸出:
請注意,前面示例中出現(xiàn)的“root”已消失。
對于可以出現(xiàn)在格式字符串中的全部內(nèi)容,你可以參考以下文檔 LogRecord 屬性 ,在后面的系列文章第二篇中,還會(huì)深入探討日志記錄的高級(jí)主題,來說明的。
下面是常見的格式設(shè)置的字段標(biāo)識(shí):
- %(asctime)s:日志創(chuàng)建時(shí)的普通時(shí)間;
- %(created)f:日志創(chuàng)建時(shí)的時(shí)間(由time.time()返回);
- %(filename)s:文件名;
- %(funcName)s:調(diào)用日志記錄的函數(shù);
- %(levelname)s:日志消息的文本級(jí)別;
- %(levelno)s:日志消息的數(shù)字級(jí)別;
- %(lineno)d:調(diào)用日志消息的行號(hào);
- %(msecs)d:創(chuàng)建時(shí)間的毫秒部分;
- %(message)s:日志消息;
- %(name)s:日志器的名稱;
- %(pathname)s:記錄日志的源文件的路徑名;
- %(process)d:進(jìn)程ID;
- %(processName)s:進(jìn)程名;
- %(thread)d:線程ID;
- %(threadName)s:線程名;
- %(relativeCreated)d:創(chuàng)建日志記錄的時(shí)間(以毫秒為單位)
借助于這些格式,我們可以自定義日志記錄,比如顯示時(shí)間:
這樣,日志中除了記錄消息等級(jí)、消息信息外,還會(huì)記錄上消息創(chuàng)建的時(shí)間。
3.2 設(shè)置日志記錄的時(shí)間顯示的格式——basicConfig的datefmt參數(shù)
那我們可不可以更改時(shí)間顯示的格式呢?這個(gè)自然是能的,
日期/時(shí)間顯示的默認(rèn)格式(如上所示)類似于 ISO8601 或 RFC 3339 。 如果你需要更多地控制日期/時(shí)間的格式,請為 basicConfig 提供 datefmt 參數(shù),
需要格外注意的是:datefmt 參數(shù)的格式與 time.strftime() 支持的格式相同。如下例所示:
那到底有哪一些格式呢?可以參考官網(wǎng):https://docs.python.org/zh-cn/3.7/library/time.html#time.strftime
函數(shù)原型為:
轉(zhuǎn)換一個(gè)元組或 struct_time 表示的由 gmtime() 或 localtime() 返回的時(shí)間到由 format 參數(shù)指定的字符串。如果未提供 t ,則使用由 localtime() 返回的當(dāng)前時(shí)間。 format 必須是一個(gè)字符串。如果 t 中的任何字段超出允許范圍,則引發(fā) ValueError 。
0是時(shí)間元組中任何位置的合法參數(shù);如果它通常是非法的,則該值被強(qiáng)制改為正確的值。
以下指令可以嵌入 format 字符串中。它們顯示時(shí)沒有可選的字段寬度和精度規(guī)范,并被 strftime() 結(jié)果中的指示字符替換:
| %a | 本地化的縮寫星期中每日的名稱。 | |
| %A | 本地化的星期中每日的完整名稱。 | |
| %b | 本地化的月縮寫名稱。 | |
| %B | 本地化的月完整名稱。 | |
| %c | 本地化的適當(dāng)日期和時(shí)間表示。 | |
| %d | 十進(jìn)制數(shù) [01,31] 表示的月中日。 | |
| %H | 十進(jìn)制數(shù) [00,23] 表示的小時(shí)(24小時(shí)制)。 | |
| %I | 十進(jìn)制數(shù) [01,12] 表示的小時(shí)(12小時(shí)制)。 | |
| %j | 十進(jìn)制數(shù) [001,366] 表示的年中日。 | |
| %m | 十進(jìn)制數(shù) [01,12] 表示的月。 | |
| %M | 十進(jìn)制數(shù) [00,59] 表示的分鐘。 | |
| %p | 本地化的 AM 或 PM 。 | (1) |
| %S | 十進(jìn)制數(shù) [00,61] 表示的秒。 | (2) |
| %U | 十進(jìn)制數(shù) [00,53] 表示的一年中的周數(shù)(星期日作為一周的第一天)作為。在第一個(gè)星期日之前的新年中的所有日子都被認(rèn)為是在第0周。 | (3) |
| %w | 十進(jìn)制數(shù) [0(星期日),6] 表示的周中日。 | |
| %W | 十進(jìn)制數(shù) [00,53] 表示的一年中的周數(shù)(星期一作為一周的第一天)作為。在第一個(gè)星期一之前的新年中的所有日子被認(rèn)為是在第0周。 | (3) |
| %x | 本地化的適當(dāng)日期表示。 | |
| %X | 本地化的適當(dāng)時(shí)間表示。 | |
| %y | 十進(jìn)制數(shù) [00,99] 表示的沒有世紀(jì)的年份。 | |
| %Y | 十進(jìn)制數(shù)表示的帶世紀(jì)的年份。 | |
| %z | 時(shí)區(qū)偏移以格式 +HHMM 或 -HHMM 形式的 UTC/GMT 的正或負(fù)時(shí)差指示,其中H表示十進(jìn)制小時(shí)數(shù)字,M表示小數(shù)分鐘數(shù)字 [-23:59, +23:59] 。 | |
| %Z | 時(shí)區(qū)名稱(如果不存在時(shí)區(qū),則不包含字符)。 | |
| %% | 字面的 '%' 字符。 |
注釋:
下面是一個(gè)示例,一個(gè)與 RFC 2822 Internet電子郵件標(biāo)準(zhǔn)以兼容的日期格式。
個(gè)人總結(jié):
個(gè)人習(xí)慣使用的格式為,年月日,時(shí)分秒,星期數(shù),如下:
四、日志記錄的堆棧追蹤
前面都是一些最簡單的日志記錄操作與格式設(shè)置,但是我們在編寫python代碼的時(shí)候,往往涉及到多個(gè)函數(shù)之間的調(diào)用,我們需要跟蹤函數(shù)調(diào)用的堆棧信息,這樣才能定位到到底是哪一個(gè)函數(shù)的哪一個(gè)位置出現(xiàn)了錯(cuò)誤,這才更加合理。
再次回顧日志記錄實(shí)際上是做一件什么事?
- 即當(dāng)滿足什么條件的時(shí)候、或者是當(dāng)某一件事情發(fā)生的時(shí)候,開始記錄日志,明白這思想很重要
- 現(xiàn)在我們要做的就是,在程序執(zhí)行出發(fā)了異常的時(shí)候,就開始記錄日志,并且記錄程序的堆棧信息,思想是相通的,只不過條件現(xiàn)在變成了,在異常發(fā)生的時(shí)候。
首先其實(shí)我們發(fā)現(xiàn),http://logging.xxx()的幾個(gè)函數(shù)(info、debug、warning、error、critical)他們的參數(shù)格式是一樣的,以error為例:
有兩個(gè)非常關(guān)鍵的參數(shù),它們是
- stack_info:
- exc_info:
下面將分別來說明這兩個(gè)參數(shù)各自的作用
(1)exc_info=True——出現(xiàn)異常時(shí)記錄堆棧調(diào)用信息
先從一個(gè)簡單的函數(shù)調(diào)用例子來看
有一個(gè)math_func.py模塊,實(shí)現(xiàn)了兩個(gè)函數(shù),如下:
然后有一個(gè)operation_func.py模塊,再進(jìn)一步對這兩個(gè)函數(shù)進(jìn)行包裝,以便進(jìn)行選擇性的調(diào)用哪一個(gè)函數(shù),如下:
最后再主模塊main.py里面進(jìn)行調(diào)用,如下:
運(yùn)行之后,打開日志文件,得到如下的結(jié)果
從上面我們發(fā)現(xiàn),錯(cuò)誤信息以及堆棧信息全部清楚地記錄在了里面。這對于程序調(diào)試是至關(guān)重要的。
以上就是出現(xiàn)錯(cuò)誤的時(shí)候logging堆棧追蹤的全部實(shí)現(xiàn),一般的調(diào)用模板如下:
前面提到了由兩個(gè)參數(shù),那么這兩個(gè)參數(shù)到底有什么區(qū)別呢?現(xiàn)總結(jié)如下:
- exe_info參數(shù):在搜索異常處理程序時(shí),跟蹤異常而打開的堆棧幀的信息,這個(gè)是專門針對異常發(fā)生的時(shí)候記錄日志的;
- stack_info參數(shù):默認(rèn)為 False。如果為 True,則將堆棧信息添加到日志消息中,包括實(shí)際的日志調(diào)用。請注意,這與通過指定 exc_info 顯示的堆棧信息不同:他主要是從堆棧底部到當(dāng)前線程中的日志記錄調(diào)用的堆棧幀,什么意思呢?即使在未引發(fā)任何異常的情況下,也可以顯示如何到達(dá)代碼中的特定點(diǎn)。堆棧幀在標(biāo)題行(即每一句日志記錄行)之后打印:
- stack_info:簡單來說就是,根據(jù)每一個(gè)日志記錄語句所在的位置,打印出這一句日志記錄信息,并且在后面顯示這句日志記錄所在的函數(shù)堆棧的位置是在哪里。
(2)stack_info=True——記錄每一句日志記錄語句所在代碼中的堆棧信息
參考下面的例子:
調(diào)用b函數(shù),b中有調(diào)用a函數(shù),得到下面的日志信息:
從上面可以看出,stack_info它會(huì)詳細(xì)記錄每一條日志打印語句所在的位置,然后在日志信息后面加以顯示,這跟exe_info是有顯著區(qū)別的。
(3)補(bǔ)充參數(shù)說明——extra參數(shù)的說明
前面的3.1中在說明日志記錄的格式的時(shí)候,給出了很多預(yù)先定義好的格式,比如
- %(asctime)s:日志創(chuàng)建時(shí)的普通時(shí)間;
- %(created)f:日志創(chuàng)建時(shí)的時(shí)間(由time.time()返回);
- %(filename)s:文件名;
等等,有時(shí)候我們想定義自己的信息怎么辦呢?可以采用下面的方式,extra參數(shù)接受的參數(shù)是一個(gè)字典類型,如下例子所示:
我們發(fā)現(xiàn),自己定義的clientip、user、work都顯示了出來!
實(shí)際上,上面的這種操作稱之為,向日志輸出中添加上下文信息
除了傳遞給日志記錄函數(shù)的參數(shù)外,有時(shí)候我們還想在日志輸出中包含一些額外的上下文信息。比如,在一個(gè)網(wǎng)絡(luò)應(yīng)用中,可能希望在日志中記錄客戶端的特定信息,如:遠(yuǎn)程客戶端的IP地址和用戶名。這里我們來介紹以下幾種實(shí)現(xiàn)方式:
- 通過向日志記錄函數(shù)傳遞一個(gè)extra參數(shù)引入上下文信息
- 使用LoggerAdapters引入上下文信息
- 使用Filters引入上下文信息
具體說明請參考博文 《Python之向日志輸出中添加上下文信息》
關(guān)于Python logging的更多高級(jí)用法,請參考文檔<< Logging CookBook >>。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的keil debug如何在watch直接修改变量值_python日志记录系列教程,内置logging模块(一),直接使用logging模块的基础日志记录的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 来自网页的消息服务器繁处理忙,Event
- 下一篇: python怎么导入os模块_pytho