1. 程式人生 > 實用技巧 >python筆記46-史上最強大最好用的python日誌模組nb_log

python筆記46-史上最強大最好用的python日誌模組nb_log

前言

python的日誌模組如何封裝一值都是一個頭疼的問題,封裝的不好總是會出現重複列印等頭疼問題。
現在終於找到一個最好用的日誌模組nb_log,此日誌模組由這位大佬開發的https://www.cnblogs.com/ydf0509/

環境安裝

使用pip即可安裝使用

pip install nb_log

1.功能介紹

0)自動轉換print效果,再也不怕有人在專案中隨意print,導致很難找到是從哪裡冒出來的print。
只要import nb_log,專案所有地方的print自動現型並在控制檯可點選幾精確跳轉到print的地方。

1)相容性
使用的是python的內建logging封裝的,返回的logger物件的型別是py官方內建日誌的Logger型別,相容性強,
保證了第三方各種handlers擴充套件數量多和方便,和一鍵切換現有專案的日誌。

比如logru和logbook這種三方庫,完全重新寫的日誌,
它裡面主要被使用者使用的logger變數型別不是python內建Logger型別,
造成logger說擁有的屬性和方法有的不存在或者不一致,這樣的日誌和python內建的經典日誌相容性差,
只能相容(一鍵替換logger型別)一些簡單的debug info warning errror等方法,。

2) 日誌記錄到多個地方
內建了一鍵入參,每個引數是獨立開關,可以把日誌同時記錄到8個常用的地方的任意幾種組合,
包括 控制檯 檔案 釘釘 郵件 mongo kafka es 等等 。在第8章介紹實現這種效果的觀察者模式。

3) 日誌名稱空間獨立,採用了多例項logger,按日誌名稱空間區分。
名稱空間獨立意味著每個logger單獨的日誌界別過濾,單獨的控制要記錄到哪些地方。

logger_aa = LogManager('aa').get_logger_and_add_handlers(10,log_filename='aa.log')
logger_bb = LogManager('bb').get_logger_and_add_handlers(30,is_add_stream_handler=False,
ding_talk_token='your_dingding_token')
logger_cc = LogManager('cc').get_logger_and_add_handlers(10,log_filename='cc.log')

那麼logger_aa.debug('哈哈哈')
將會同時記錄到控制檯和檔案aa.log中,只要debug及debug以上級別都會記錄。

logger_bb.warning('嘿嘿嘿')
將只會傳送到釘釘群訊息,並且logger_bb的info debug級別日誌不會被記錄,
非常方便測試除錯然後穩定了調高界別到生產。

logger_cc的日誌會寫在cc.log中,和logger_aa的日誌是不同的檔案。

4) 對內建looging包打了猴子補丁,使日誌永遠不會使用同種handler重複記錄

例如,原生的

from logging import getLogger,StreamHandler
logger = getLogger('hi')
getLogger('hi').addHandler(StreamHandler())
getLogger('hi').addHandler(StreamHandler())
getLogger('hi').addHandler(StreamHandler())
logger.warning('啦啦啦')

明明只warning了一次,但實際會造成 啦啦啦 在控制檯列印3次。
使用nb_log,對同一名稱空間的日誌,可以無懼反覆新增同類型handler,不會重複記錄。

5)支援日誌自定義,執行此包後,會自動在你的python專案根目錄中生成nb_log_config.py檔案,按說明修改。

2.最簡單的使用方式,這只是演示控制檯日誌

2.0)自動攔截改變專案中所有地方的print效果。(支援配置檔案自定義關閉轉化print)
2.1)控制檯日誌變成可點選,精確跳轉。(支援配置檔案自定義修改或增加模板,內建了7種模板,部分模板生成的日誌可以在pycharm控制檯點選跳轉)
2.2)控制檯日誌根據日誌級別自動變色。(支援配置檔案關閉彩色或者關閉背景色塊)

from nb_log import LogManager

logger = LogManager('lalala').get_logger_and_add_handlers()

logger.debug('綠色')
logger.info('藍色')
logger.warn('黃色')
logger.error('紫紅色')
logger.critical('血紅色')
print('print樣式被自動發生變化')

3 檔案日誌

3.1)這個檔案日誌的自定義filehandler是python史上效能最強大的 支援多程序下日誌檔案按大小自動切割。

在各種filehandler實現難度上 單程序永不切割 < 多程序按時間切割 < 單程序按大小切割 << 多程序按大小切割

因為每天日誌大小很難確定,如果每天所有日誌檔案以及備份加起來超過40g了,硬碟就會滿掛了,所以nb_log的檔案日誌filehandler採用的是按大小切割,不使用按時間切割。

檔案日誌自動使用的是多程序安全切割的自定義filehandler, logging包的RotatingFileHandler多程序執行程式碼時候,如果要實現向檔案寫入到規定大小時候並自動備份切割,win和linux都100%報錯。

支援多程序安全切片的知名的handler有ConcurrentRotatingFileHandler, 此handler能夠確保win和linux切割正確不出錯,此包在linux使用的是高效的fcntl檔案鎖, 在win上效能慘不忍睹,這個包在win的效能在三方包的英文說明註釋中,作者已經提到了。

nb_log是基於自動批量聚合,從而減少寫入次數(但檔案日誌的追加最多會有1秒的延遲),從而大幅度減少反覆給檔案加鎖解鎖, 使快速大量寫入檔案日誌的效能大幅提高,在保證多程序安全且排列的前提下,對比這個ConcurrentRotatingFileHandler 使win的日誌檔案寫入速度提高100倍,在linux上寫入速度提高10倍。
3.2)演示檔案日誌,並且直接演示最高實現難度的多程序安全切片檔案日誌

from multiprocessing import Process
from nb_log import LogManager

#指定log_filename不為None 就自動寫入檔案了,並且預設使用的是多程序安全的切割方式的filehandler。
#預設都添加了控制檯日誌,如果不想要控制檯日誌,設定is_add_stream_handler=False
#為了保持方法入場數量少,具體的切割大小和備份檔案個數有預設值,
#如果需要修改切割大小和檔案數量,在當前python專案根目錄自動生成的nb_log_config.py檔案中指定。
logger = LogManager('ha').get_logger_and_add_handlers(is_add_stream_handler=True,
log_filename='ha.log')

def f():
    for i in range(1000000000):
        logger.debug('測試檔案寫入效能,在滿足 1.多程序執行 2.按大小自動切割備份 3切割備份瞬間不出錯'
                    '這3個條件的前提下,驗證這是不是python史上檔案寫入速度遙遙領先 效能最強的python logging handler')
       
if __name__ == '__main__':
    [Process(target=f).start() for _ in range(10)]

4 釘釘日誌

from nb_log import LogManager
logger4 = LogManager('hi').get_logger_and_add_handlers(is_add_stream_handler=True,
    log_filename='hi.log',ding_talk_token='your_dingding_token')
logger4.debug('這條日誌會同時出現在控制檯 檔案 和釘釘群訊息')

5 其他handler包括kafka日誌,elastic日誌,郵件日誌,mongodb日誌

按照get_logger_and_add_handler函式的入參說明就可以了,和上面的2 3 4中的寫法方式差不多,都是一參 傻瓜式,設定了,日誌記錄就會記載在各種地方。

6 日誌優先預設配置

只要專案任意檔案運行了,帶有import nb_log的指令碼,就會在專案根目錄下生成nb_log_config.py配置檔案。 nb_log_config.py的內容如下,預設都是用#註釋了,如果放開某項配置則優先使用這裡的配置,否則使用nb_log_config_default.py中的配置。

配置示例如下:

  • 如果反對日誌有各種彩色,可以設定 DEFAULUT_USE_COLOR_HANDLER = False
  • 如果反對日誌有塊狀背景彩色,可以設定 DISPLAY_BACKGROUD_COLOR_IN_CONSOLE = False
  • 如果想遮蔽nb_log包對怎麼設定pycahrm的顏色的提示,可以設定 WARNING_PYCHARM_COLOR_SETINGS = False
  • 如果想改變日誌模板,可以設定 FORMATTER_KIND 引數,只帶了7種模板,可以自定義新增喜歡的模板
import logging
ELASTIC_HOST = '127.0.0.1'
ELASTIC_PORT = 9200

KAFKA_BOOTSTRAP_SERVERS = ['192.168.199.202:9092']
ALWAYS_ADD_KAFKA_HANDLER_IN_TEST_ENVIRONENT = False

MONGO_URL = 'mongodb://myUserAdmin:[email protected]:27016/admin'

DEFAULUT_USE_COLOR_HANDLER = True  # 是否預設使用有彩的日誌。
DISPLAY_BACKGROUD_COLOR_IN_CONSOLE = True  # 在控制檯是否顯示彩色塊狀的日誌。為False則不使用大塊的背景顏色。
AUTO_PATCH_PRINT = True  # 是否自動打print的猴子補丁,如果打了後指不定,print自動變色和可點選跳轉。
WARNING_PYCHARM_COLOR_SETINGS = True

DEFAULT_ADD_MULTIPROCESSING_SAFE_ROATING_FILE_HANDLER = False  # 是否默認同時將日誌記錄到記log檔案記事本中。
LOG_FILE_SIZE = 100  # 單位是M,每個檔案的切片大小,超過多少後就自動切割
LOG_FILE_BACKUP_COUNT = 3

LOG_LEVEL_FILTER = logging.DEBUG  # 預設日誌級別,低於此級別的日誌不記錄了。例如設定為INFO,那麼logger.debug的不會記錄,只會記錄logger.info以上級別的。
RUN_ENV = 'test'

FORMATTER_DICT = {
    1: logging.Formatter(
        '日誌時間【%(asctime)s】 - 日誌名稱【%(name)s】 - 檔案【%(filename)s】 - 第【%(lineno)d】行 - 日誌等級【%(levelname)s】 - 日誌資訊【%(message)s】',
        "%Y-%m-%d %H:%M:%S"),
    2: logging.Formatter(
        '%(asctime)s - %(name)s - %(filename)s - %(funcName)s - %(lineno)d - %(levelname)s - %(message)s',
        "%Y-%m-%d %H:%M:%S"),
    3: logging.Formatter(
        '%(asctime)s - %(name)s - 【 File "%(pathname)s", line %(lineno)d, in %(funcName)s 】 - %(levelname)s - %(message)s',
        "%Y-%m-%d %H:%M:%S"),  # 一個模仿traceback異常的可跳轉到列印日誌地方的模板
    4: logging.Formatter(
        '%(asctime)s - %(name)s - "%(filename)s" - %(funcName)s - %(lineno)d - %(levelname)s - %(message)s -               File "%(pathname)s", line %(lineno)d ',
        "%Y-%m-%d %H:%M:%S"),  # 這個也支援日誌跳轉
    5: logging.Formatter(
        '%(asctime)s - %(name)s - "%(pathname)s:%(lineno)d" - %(funcName)s - %(levelname)s - %(message)s',
        "%Y-%m-%d %H:%M:%S"),  # 我認為的最好的模板,推薦
    6: logging.Formatter('%(name)s - %(asctime)-15s - %(filename)s - %(lineno)d - %(levelname)s: %(message)s',
                         "%Y-%m-%d %H:%M:%S"),
    7: logging.Formatter('%(levelname)s - %(filename)s - %(lineno)d - %(message)s',"%Y-%m-%d %H:%M:%S"), # 一個只顯示簡短檔名和所處行數的日誌模板
}

FORMATTER_KIND = 5  # 如果get_logger_and_add_handlers不指定日誌模板,則預設選擇第幾個模板
  1. 各種日誌截圖

釘釘

控制檯日誌模板之一

控制檯日子模板之二

郵件日誌

檔案日誌

elastic日誌

mongo日誌

8 關於日誌的觀察者模式

不會擴充套件日誌記錄到什麼地方,主要是不懂什麼叫觀察者模式

# 例如 日誌想實現記錄到 控制檯、檔案、釘釘群、redis、mongo、es、kafka、發郵件其中的幾種的任意組合。
# low的人,會這麼寫,以下是虛擬碼,實現記錄到控制檯、檔案、釘釘群這三種的任意幾種組合。

def 記錄到控制檯(msg):
    """實現把msg記錄到控制檯"""

def 記錄到檔案(msg):
    """實現把msg記錄到檔案"""

def 記錄到釘釘(msg):
    """實現把msg記錄到釘釘"""

def 記錄到控制檯和檔案(msg):
    """實現把msg記錄到控制檯和檔案"""

def 記錄到控制檯和釘釘(msg):
    """實現把msg記錄到控制檯和釘釘"""

def 記錄到檔案和釘釘(msg):
    """實現把msg記錄到檔案和釘釘"""

def 記錄到控制檯和檔案和釘釘(msg):
    """實現把msg記錄到控制檯和檔案和釘釘"""

#當需要把msg記錄到檔案時候,呼叫函式 記錄到檔案(msg)
#當需要把msg記錄到控制檯時候,呼叫函式 記錄到控制檯(msg)
#當需要把msg記錄到釘釘時候,呼叫函式 記錄到釘釘(msg)
#當需要把msg記錄到控制檯和檔案,呼叫函式 記錄到控制檯和檔案(msg)
#當需要把msg記錄到控制檯和釘釘,呼叫函式 記錄到控制檯和釘釘(msg)
#當需要把msg記錄到控制檯和檔案和釘釘,呼叫函式 記錄到控制檯和檔案和釘釘(msg)

"""
這樣會造成,僅記錄到控制檯 檔案 釘釘這三種的任意幾個,需要寫6個函式,呼叫時候需要呼叫不同的函式名。
但是現在日誌可以記錄到8種地方,如果還這麼low的寫法,需要寫8的階乘個函式,呼叫時候根據場景需要會呼叫8的階乘個函式名。
8的階乘結果是 40320 ,如果很low不學設計模式做到靈活組合,需要多寫 4萬多個函式,不學設計模式會多麼嚇人。

"""

觀察者模式圖片

菜鳥教程的觀察者模式demo連線 觀察者模式demo

這個uml圖上分為Subject 和 基類Observer,以及各種繼承或者實現Observer的XxObserver類, 其中每個不同的Observer需要實現doOperation方法。

如果對應到python內建的logging日誌包的實現,那麼關係就是:

Logger是uml圖的Subject

loging.Handler類是uml圖的Observer類

StreamHandler FileHandler DingTalkHandler 是uml圖的各種XxObservers類。

StreamHandler FileHandler DingTalkHandler類的 emit方法是uml圖的doOperation方法

只有先學設計模式,才能知道經典固定套路達到快速看程式碼,能夠達到秒懂原始碼是怎麼規劃設計實現的。

如果不先學習經典設計模式,每次看包的原始碼,需要多浪費很多時間看他怎麼設計實現的,不懂設計模式,會覺得太難了看著就放棄了。

在python日誌的使用和理解上,能夠和風神打成平手的,國內沒有幾人。

轉自https://pypi.org/project/nb-log/