欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Python 記錄日志的靈活性和可配置性介紹

系統 1633 0

對一名開發者來說最糟糕的情況,莫過于要弄清楚一個不熟悉的應用為何不工作。有時候,你甚至不知道系統運行,是否跟原始設計一致。

在線運行的應用就是黑盒子,需要被跟蹤監控。最簡單也最重要的方式就是記錄日志。記錄日志允許我們在開發軟件的同時,讓程序在系統運行時發出信息,這些信息對于我們和系統管理員來說都是有用的。

就像為將來的程序員寫代碼文檔一樣,我們應該讓新軟件產生足夠的日志供系統的開發者和管理員使用。日志是關于應用運行狀態的系統文件的關鍵部分。給軟件加日志產生句時,要向給未來維護系統的開發者和管理員寫文檔一樣。

一些純粹主義者認為一個受過訓練的開發者使用日志和測試的時候幾乎不需要交互調試器。如果我們不能用詳細的日志解釋開發過程中的應用,那么當代碼在線上運行的時候,解釋它們會變得更困難。

這篇文章介紹了 Python 的 logging 模塊,包括它的設計以及針對更多復雜案例的適用方法。這篇文章不是寫給開發者的文檔,它更像是一個指導手冊,來說明 Python 的 logging 模板是如何搭建的,并且激發感興趣的人深入研究。

為什么使用 logging 模塊?

也許會有開發者會問,為什么不是簡單的 print 語句呢? Logging 模塊有很多優勢,包括:

1.多線程支持

2.通過不同級別的日志分類

3.靈活性和可配置性

4.將如何記錄日志與記錄什么內容分離

最后一點,將我們記錄內容從記錄方式中真正分離,保證了軟件不同部分的合作。舉個例子,它允許一個框架或庫的開發者增加日志并且讓系統管理員或負責運行配置的人員決定稍后應該記錄什么。

Logging 模塊中有什么

Logging 模塊完美地將它的每個部分的職責分離(遵循 Apache Log4j API 的方法)。讓我們看看一個日志線是如何通過這個模塊的代碼,并且研究下它的不同部分。

記錄器(Logger)

記錄器是開發者經常交互的對象。那些主要的 API 說明了我們想要記錄的內容。

舉個記錄器的例子,我們可以分類請求發出一條信息,而不用擔心它們是如何從哪里被發出的。

比如,當我們寫下 logger.info(“Stock was sold at %s”, price) 我們在頭腦中就有如下模塊:

Python 記錄日志的靈活性和可配置性介紹_第1張圖片

我們需要一條線。假設有些代碼在記錄器中運行,讓這條線出現在控制臺或文件中。但是在內部實際發生了什么呢?

日志記錄

日志記錄是 logging 模塊用來滿足所有需求信息的包。它們包含了需要記錄日志的地方、變化的字符串、參數、請求的信息隊列等信息。

它們都是被記錄的對象。每次我們調用記錄器時,都會生成這些對象。但這些對象是如何序列化到流中的呢?通過處理器!

處理器

處理器將日志記錄發送給其他輸出終端,他們獲取日志記錄并用相關函數中處理它們。

比如,一個文件處理器將會獲取一條日志記錄,并且把它添加到文件中。

標準的 logging 模塊已經具備了多種內置的處理器,例如:

多種文件處理器(TimeRotated, SizeRotated, Watched),可以寫入文件中

1.StreamHandler 輸出目標流比如 stdout 或 stderr

2.SMTPHandler 通過 email 發送日志記錄

3.SocketHandler 將日志文件發送到流套接字

4.SyslogHandler、NTEventHandler、HTTPHandler及MemoryHandler等

目前我們有個類似于真實情況的模型:

Python 記錄日志的靈活性和可配置性介紹_第2張圖片

大部分的處理器都在處理字符串(SMTPHandler和FileHandler等)。或許你想知道這些結構化的日志記錄是如何轉變為易于序列化的字節的。

格式器

格式器負責將豐富的元數據日志記錄轉換為字符串,如果什么都沒有提供,將會有個默認的格式器。

一般的格式器類由 logging 庫提供,采用模板和風格作為輸入。然后占位符可以在一個 LogRecord 對象中聲明所有屬性。

比如:'%(asctime)s %(levelname)s %(name)s: %(message)s' 將會生成日志類似于 2017-07-19 15:31:13,942 INFO parent.child: Hello EuroPython.

請注意:屬性信息是通過提供的參數對日志的原始模板進行插值的結果。(比如,對于 logger.info(“Hello %s”, “Laszlo”) 這條信息將會是 “Hello Laszlo”)

所有默認的屬性都可以在日志文檔中找到。

好了,現在我們了解了格式器,我們的模型又發生了變化:

Python 記錄日志的靈活性和可配置性介紹_第3張圖片

過濾器

我們日志工具的最后一個對象就是過濾器。

過濾器允許對應該發送的日志記錄進行細粒度控制。多種過濾器能同時應用在記錄器和處理器中。對于一條發送的日志來說,所有的過濾器都應該通過這條記錄。

用戶可以聲明他們自己的過濾器作為對象,使用 filter 方法獲取日志記錄作為輸入,反饋 True / False 作為輸出。

出于這種考慮,以下是當前的日志工作流:

Python 記錄日志的靈活性和可配置性介紹_第4張圖片

記錄器層級

此時,你可能會對大量復雜的內容和巧妙隱藏的模塊配置印象深刻,但是還有更需要考慮的:記錄器分層。

我們可以通過 logging.getLogger() 創建一個記錄器。這條字符向 getLogger 傳遞了一個參數,這個參數可以通過使用圓點分隔元素來定義一個層級。

舉個例子, logging.getLogger(“parent.child”) 將會創建一個 “child” 的記錄器,它的父級記錄器叫做 “parent.” 記錄器是被 logging 模塊管理的全局對象,所以我們可以方便地在項目中的任何地方檢索他們。

記錄器的例子通常也被認為是渠道。層級允許開發者去定義渠道和他們的層級。

在日志記錄被傳遞到所有記錄器內的處理器時,父級處理器將會進行遞歸處理,直到我們到達頂級的記錄器(被定義為一個空字符串),或者有一個記錄器設置了 propagate = False。我們可通過更新的圖中看出:

Python 記錄日志的靈活性和可配置性介紹_第5張圖片

請注意父級記錄器沒有被調用,只有它的處理器被調用。這意味著過濾器和其他在記錄器類中的代碼不會在父級中被執行。當我們在記錄器中增加過濾器時,這通常是個陷阱。

工作流小結

我們已經闡明過職責的劃分以及我們是如何微調日志過濾。然而還是有兩個其他的屬性我們沒有提及:

1.記錄器可以是殘缺的,從而不允許任何記錄從這被發出。

2.一個有效的層級可以同時在記錄器和處理器中被設置。

舉個例子,當一個記錄器被設置為 INFO 的等級,只有 INFO 等級及以上的才會被傳遞,同樣的規則適用于處理器。

基于以上所有的考慮,最后的日志記錄的流程圖看起來像這樣:

Python 記錄日志的靈活性和可配置性介紹_第6張圖片

如何使用日志記錄模塊

現在我們已經了解了 logging 模塊的部分及設計,是時候去了解一個開發者是如何與它交互的了。以下是一個代碼例子:

            
import logging
def sample_function(secret_parameter):
logger = logging.getLogger(__name__) # __name__=projectA.moduleB
logger.debug("Going to perform magic with '%s'", secret_parameter)
...
try:
result = do_magic(secret_parameter)
except IndexError:
logger.exception("OMG it happened again, someone please tell Laszlo")
except:
logger.info("Unexpected exception", exc_info=True)
raise
else:
logger.info("Magic with '%s' resulted in '%s'", secret_parameter, result, stack_info=True)
          

它用模塊 __name__ 創建了一個日志記錄器。它會基于項目結構創建渠道和等級,正如 Pyhon 模塊用圓點連接一樣。

記錄器變量引用記錄器的 “module” ,用 “projectA” 作為父級, “root” 作為父級的父級。

在第五行,我們看到如何執行調用去發送日志。我們可以用 debug 、 info 、error 或 critical 這些方法之一在合適的等級上去記錄日志。

當記錄一條信息時,除了模板參數,我們可以通過特殊的含義傳遞密碼參數,最有意思的是 exc_info 和 stack_info。它們將會分別增加關于當前異常和棧幀的信息。為了方便起見,在記錄器對象中有一個方法異常,正如這個錯誤調用 exc_info=True 。

這些是如何使用記錄器模塊的基礎,但是有些通常被認為是不良操作的做法同樣值得說明。

過度格式化字符串

應該盡量避免使用 loggger.info(“string template {}”.format(argument)) ,可能的話盡量使用 logger.info(“string template %s”, argument) 。 這是個更好的實踐,因為只有當日志被發送時,字符串才會發生真正改變。當我們記錄的層級在 INFO 之上時,不這么做會導致浪費周期,因為這個改變仍然會發生。

捕捉和格式化異常

通常,我們想記錄在抓取模塊異常的日志信息,如果這樣寫會很直觀:

            
try:
..
except Exception as error:
logger.info("Something bad happened: %s", error)
          

但是這樣的代碼會給我們顯示類似于 Something bad happened: “secret_key.” 的日志行,這并不是很有用。如果我們使用 exc_info 作為事先說明,那么它將會如下顯示:

            
try:
..
except Exception:
logger.info("Something bad happened", exc_info=True)
Something bad happened
Traceback (most recent call last):
File "sample_project.py", line 10, in code
inner_code()
File "sample_project.py", line 6, in inner_code
x = data["secret_key"]
KeyError: 'secret_key'
          

這不僅僅會包含異常的準確資源,同時也會包含它的類型。

設置記錄器

裝備我們的軟件很簡單,我們需要設置日志棧,并且制定這些記錄是如何被發出的。

以下是設置日志棧的多種方法

基礎設置

這是至今最簡單的設置日志記錄的方法。使用 logging.basicConfig(level=”INFO”) 搭建一個基礎的 StreamHandler ,這樣就會記錄在 INFO 上的任何東西,并且到控制臺以上的級別。以下是編寫基礎設置的一些參數:

Python 記錄日志的靈活性和可配置性介紹_第7張圖片

請注意, basicConfig 僅僅在運行的一開始可以這么調用。如果你已經設置了你的根記錄器,調用 basicConfig 將不會奏效。

字典設置

所有元素的設置以及如何連接它們可以作為字典來說明。這個字典應當由不同的部分組成,包括記錄器、處理器、格式化以及一些基本的通用參數。

例子如下:

            
config = {
'disable_existing_loggers': False,
'version': 1,
'formatters': {
'short': {
'format': '%(asctime)s %(levelname)s %(name)s: %(message)s'
},
},
'handlers': {
'console': {
'level': 'INFO',
'formatter': 'short',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'': {
'handlers': ['console'],
'level': 'ERROR',
},
'plugins': {
'handlers': ['console'],
'level': 'INFO',
'propagate': False
}
},
}
import logging.config
logging.config.dictConfig(config)
          

當被引用時, dictConfig 將會禁用所有運行的記錄器,除非 disable_existing_loggers 被設置為 false。這通常是需要的,因為很多模塊聲明了一個全球記錄器,它在 dictConfig 被調用之前被導入的時候將會實例化。

你可以查看 schema that can be used for the dictConfig method(鏈接)。通常,這些設置將會存儲在一個 YAML 文件中,并且從那里設置。很多開發者會傾向于使用這種方式而不是使用 fileConfig(鏈接),因為它為定制化提供了更好的支持。

拓展 logging

幸虧設計了這種方式,拓展 logging 模塊很容易。讓我們來看些例子:

logging JSON | 記錄 JSON

只要我們想要記錄,我們可以通過創建一種自定義格式化來記錄 JSON ,它會將日志記錄轉化為 JSON 編碼的字符串。

            
import logging
import logging.config
import json
ATTR_TO_JSON = ['created', 'filename', 'funcName', 'levelname', 'lineno', 'module', 'msecs', 'msg', 'name', 'pathname', 'process', 'processName', 'relativeCreated', 'thread', 'threadName']
class JsonFormatter:
def format(self, record):
obj = {attr: getattr(record, attr)
for attr in ATTR_TO_JSON}
return json.dumps(obj, indent=4)
handler = logging.StreamHandler()
handler.formatter = JsonFormatter()
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.error("Hello")
          

添加更多上下文

在格式化中,我們可以指定任何日志記錄的屬性。

我們可以通過多種方式增加屬性,在這個例子中,我們用過濾器來豐富日志記錄。

            
import logging
import logging.config
GLOBAL_STUFF = 1
class ContextFilter(logging.Filter):
def filter(self, record):
global GLOBAL_STUFF
GLOBAL_STUFF += 1
record.global_data = GLOBAL_STUFF
return True
handler = logging.StreamHandler()
handler.formatter = logging.Formatter("%(global_data)s %(message)s")
handler.addFilter(ContextFilter())
logger = logging.getLogger(__name__)
logger.addHandler(handler)
logger.error("Hi1")
logger.error("Hi2")
          

這樣有效地在所有日志記錄中增加了一個屬性,它可以通過記錄器。格式化會在日志行中包含這個屬性。

請注意這會在你的應用中影響所有的日志記錄,包含你可能用到以及你發送日志的庫和其他的框架。它可以用來記錄類似于在所有日志行里的一個獨立請求 ID ,去追蹤請求或者去添加額外的上下文信息。

從 Python 3.2 開始,你可以使用 setLogRecordFactory 去獲得所有日志的創建記錄和增加額外的信息。這個 extra attribute 和 LoggerAdapter class 或許同樣是有趣的。

緩沖日志

有時候當錯誤發生時,我們想要排除日志故障。創建一個緩沖的處理器,來記錄當錯誤發生時的最新故障信息是一種可行的辦法。下面的代碼是個非人為策劃的例子:

            
import logging
import logging.handlers
class SmartBufferHandler(logging.handlers.MemoryHandler):
def __init__(self, num_buffered, *args, **kwargs):
kwargs["capacity"] = num_buffered + 2 # +2 one for current, one for prepop
super().__init__(*args, **kwargs)
def emit(self, record):
if len(self.buffer) == self.capacity - 1:
self.buffer.pop(0)
super().emit(record)
handler = SmartBufferHandler(num_buffered=2, target=logging.StreamHandler(), flushLevel=logging.ERROR)
logger = logging.getLogger(__name__)
logger.setLevel("DEBUG")
logger.addHandler(handler)
logger.error("Hello1")
logger.debug("Hello2") # This line won't be logged
logger.debug("Hello3")
logger.debug("Hello4")
logger.error("Hello5") # As error will flush the buffered logs, the two last debugs will be logged
          

總結

以上所述是小編給大家介紹的Python 記錄日志的靈活性和可配置性,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

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

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 色综合天天综合网国产成人网 | 免费看一级视频 | 奇米影视在线观看 | 日本久久久久久久 | 91tm视频| 欧美激烈精交gif动态图18p | 国产精品视频99 | www色综合 | 日韩免费在线视频 | 日韩国产成人资源精品视频 | 偶像练习生在线免费观看 | 天天做天天爱夜夜大爽完整 | 九色91 | 澳门特级 片免费观看视频 久草最新在线 | 色综合久久天天综合网 | 国产日韩中文字幕 | 新婚少妇小倩给老许泄火 | 久久99综合国产精品亚洲首页 | 日韩在线网址 | 亚洲午夜在线 | 国产精品1区2区3区 一级电影免费 | 精品国产精品三级精品av网址 | 精品综合 | av在线在线 | 亚洲一区视频在线 | 尤物国产在线精品福利一区 | 欧美激情综合色综合啪啪五月 | 富二代精品视频 | 国产日韩综合 | 在线视频 中文字幕 | 日韩欧美亚洲综合久久99e | 日本不卡中文字幕一区二区 | 亚洲精品在线视频 | 草草免费 | 亚洲午夜成激人情在线影院 | 久草www| 欧美日韩一二三区 | 成人网免费视频 | 色欲AV蜜臀AV在线观看麻豆 | 亚洲成人在线免费 | 艹逼|