python_日誌模塊_logging

說明:

1.日誌模塊默認是直接輸出到終端的,除非在 logging.basicConfig()的參數中使用filename,使用filename後,日誌都會輸入到filename對應的日誌文件中,,

2.可以通過使用handler,將文件同時輸出到終端和文件中,但是值得注意的是:

當logging.basicConfig設置的日誌級別低於handler中設置的日誌級別,handler中顯示的日誌級別也只會按照logging.basicConfig中設置的級別顯示,

當logging.basicConfig設置的日誌級別高於handler中設置的日誌級別,handler中顯示的日誌級別根據自身(handler)中設置的級別顯示,

3.logging多線程,多進程場景:

按照官方文檔的介紹,logging 是線程安全的,也就是說,在一個進程內的多個線程同時往同一個文件寫日誌是安全的。但是(對,這裏有個但是)多個進程往同一個文件寫日誌不是安全的。官方的說法是這樣的:

Because there is no standard way to serialize access to a single file across multiple processes in Python. If you need to log to a single file from multiple processes, 
one way of doing this is to have all the processes log to a SocketHandler, and have a separate process which implements a socket server which reads from the socket and logs to file. 
(If you prefer, you can dedicate one thread in one of the existing processes to perform this function.)

有的人會說,那我不用多進程不就可以了。但是 Python 有一個 GIL 的大鎖(關於 GIL 的糾葛可以看這裏),使用多線程是沒法利用到多核 CPU 的,大部分情況下會改用多進程來利用多核 CPU,因此我們還是繞不開不開多進程下日誌的問題。

爲了解決這個問題,可以使用 ConcurrentLogHandler,ConcurrentLogHandler 可以在多進程環境下安全的將日誌寫入到同一個文件,並且可以在日誌文件達到特定大小時,分割日誌文件。在默認的 logging 模塊中,有個 TimedRotatingFileHandler 類,可以按時間分割日誌文件,可惜 ConcurrentLogHandler 不支持這種按時間分割日誌文件的方式。

重新修改下 handlers 中的 class。

logging.config.dictConfig({
    ...
    'handlers': {
        'file': {
            'level''DEBUG',
            # 如果沒有使用併發的日誌處理類,在多實例的情況下日誌會出現缺失
            'class''cloghandler.ConcurrentRotatingFileHandler',
            # 當達到10MB時分割日誌
            'maxBytes'1024 * 1024 * 10,
            # 最多保留50份文件
            'backupCount'50,
            # If delay is true,
            # then file opening is deferred until the first call to emit().
            'delay'True,
            'filename''logs/mysite.log',
            'formatter''verbose'
        }
    },
    ...
})
運行後可以發現,會自動創建一個.lock文件,通過鎖的方式來安全的寫日誌文件。

 

 

1.以配置文件的方式使用logging模塊

說明:使用logging.config.fileConfig("Logging.ini")載入後,啓動程序報錯.KeyError Formatters 在網上查了很久,說是日誌路徑的問題,結果就是路徑問題

[loggers]
keys=root,infoLogger,errorlogger
 
[logger_root]
level=DEBUG
handlers=infohandler,errorhandler
 
[logger_infoLogger]
handlers=infohandler
qualname=infoLogger
propagate=0
 
[logger_errorlogger]
handlers=errorhandler
qualname=errorlogger
propagate=0
 
###############################################
 
[handlers]
keys=infohandler,errorhandler
 
[handler_infohandler]
class=StreamHandler
level=INFO
formatter=form02
args=(sys.stdout,)
 
[handler_errorhandler]
class=FileHandler
level=ERROR
formatter=form01
args=('logs/mylog.log', 'a')
 
###############################################
 
[formatters]
keys=form01,form02
 
[formatter_form01]
format=%(asctime)s %(filename)s %(levelname)s  %(message)s
datefmt=%Y-%m-%d %H:%M:%S
 
[formatter_form02]
format=%(asctime)s %(filename)s %(levelname)s  %(message)s
datefmt=%Y-%m-%d %H:%M:%S
 
 
字段說明:
 
 
[loggers]
# 定義logger模塊,root是父類,必需存在的,其它的是自定義。
# logging.getLogger(NAME)便相當於向logging模塊註冊了一種日誌打印
# name 中用 . 表示 log 的繼承關係
 
[handlers]
# 定義handler
[formatters]
# 定義格式化輸出
  
[logger_root]
 
# 實現上面定義的logger模塊,必需是[logger_xxxx]這樣的形式
 
# [logger_xxxx] logger_模塊名稱
# level     級別,級別有DEBUG、INFO、WARNING、ERROR、CRITICAL
# handlers  處理類,可以有多個,用逗號分開
# qualname  logger名稱,應用程序通過 logging.getLogger獲取。對於不能獲取的名稱,則記錄到root模塊。
# propagate 是否繼承父類的log信息,0:否 1:是
 
[handler_infohandler]
# [handler_xxxx]
# class handler類名
# level 日誌級別
# formatter,上面定義的formatter
# args handler初始化函數參數
 
[formatter_form01]
 
# 日誌格式
#--------------------------------------------------
使用方式:
from logging.config import fileConfig
 
fileConfig('loggin_config.ini')
logger=logging.getLogger('infoLogger')
logger.info('test1')
logger_error=logging.getLogger('errorhandler')
logger_error.error('test5')

 

2.在code中直接使用logging模塊

 

# 模塊級函數
#
# logging.getLogger([name]):返回一個logger對象,如果沒有指定名字將返回root logger
# logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical():設定root logger的日誌級別
# logging.basicConfig():用默認Formatter爲日誌系統建立一個StreamHandler,設置基礎配置並加到root logger中
#
# Loggers
#
# Logger.setLevel(lel):指定最低的日誌級別,低於lel的級別將被忽略。debug是最低的內置級別,critical爲最高
# Logger.addFilter(filt)、Logger.removeFilter(filt):添加或刪除指定的filter
# Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或刪除指定的handler
# Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以設置的日誌級別
# Handlers
#
# handler對象負責發送相關的信息到指定目的地。可以通過addHandler()方法添加多個多handler
# Handler.setLevel(lel):指定被處理的信息級別,低於lel級別的信息將被忽略
# Handler.setFormatter():給這個handler選擇一個格式
# Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象
# Formatters
#
# Formatter對象設置日誌信息最後的規則、結構和內容,默認的時間格式爲%Y-%m-%d %H:%M:%S,下面是Formatter常用的一些信息
 
# %(name)s Logger的名字
#
# %(levelno)s 數字形式的日誌級別
#
# %(levelname)s 文本形式的日誌級別
#
# %(pathname)s 調用日誌輸出函數的模塊的完整路徑名,可能沒有
#
# %(filename)s 調用日誌輸出函數的模塊的文件名
#
# %(module)s 調用日誌輸出函數的模塊名
#
# %(funcName)s 調用日誌輸出函數的函數名
#
# %(lineno)d 調用日誌輸出函數的語句所在的代碼行
#
# %(created)f 當前時間,用UNIX標準的表示時間的浮 點數表示
#
# %(relativeCreated)d 輸出日誌信息時的,自Logger創建以 來的毫秒數
#
# %(asctime)s 字符串形式的當前時間。默認格式是 年-月-日 時-分-秒,毫秒 “2003-07-08 16:49:45,896”。逗號後面的是毫秒
#
# %(thread)d 線程ID。可能沒有
#
# %(threadName)s 線程名。可能沒有
#
# %(process)d       進程id
#
# %(processName)s   進程名
#
# %(message)s 用戶輸出的消息
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章