前言
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:mima@127.0.0.1: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不指定日志模板,則默認選擇第幾個模板
- 各種日志截圖
釘釘
控制台日志模板之一
控制台日子模板之二
郵件日志
文件日志
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日志的使用和理解上,能夠和風神打成平手的,國內沒有幾人。