在 python 要列印除錯資訊,最簡單的方式是使用 print,但如果要區分 log 的等級,或是將不同的 log 資訊放到不同的檔案,這時就需要使用 logging module,但 loggin module 的設定會比較複雜一些,以下紀錄使用 logging module 的方式。
在 project 最常被呼叫及使用的 util.py 裡面,初始化 logging module,如果只需要簡單的 logging 設定,可直接在 util 裡面初始化 logging,複雜的設定可以用設定檔的方式處理。
直接在程式裡面初始化 logging 的範例
使用 TimedRotatingFileHandler,搭配 when='midnight',在每天午夜更換log 檔案,並將舊的 log 檔加上日期 postfix,backupCount 是控制保留幾個舊的 log file。formatter 是設定每一行 log 的 pattern。最後將 file handler 以及 console handler 新增到 rootLogger 裡面。
rootLogger = logging.getLogger()
# 用 rootLogger 的 handler 數量判斷是否已經有初始化 logging print( "len(logger.handlers)="+str(len(logger.handlers)) )
if len(rootLogger.handlers) == 0:
from logging.handlers import TimedRotatingFileHandler
logger.setLevel(logging.DEBUG)
log_file_path = os.path.join('.', logs_directory+'/'+'project.log').replace('\\', '/')
fh = TimedRotatingFileHandler(log_file_path,when='midnight',interval=1,backupCount=30)
fh.suffix = "%Y-%m-%d"
datefmt = '%Y-%m-%d %H:%M:%S'
# datefmt = '%Y-%m-%d'
# format_str = '%(asctime)s %(levelname)s %(message)s '
format_str = '%(asctime)s %(levelname)s %(module)s.%(funcName)s %(lineno)d: %(message)s'
# formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
formatter = logging.Formatter(format_str, datefmt)
fh.setFormatter(formatter)
logger.addHandler(fh)
# 定義 handler 輸出 sys.stderr
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
console.setFormatter(formatter)
logger.addHandler(console)
使用時只需要 import logging
預設就會取得 root logger
import logging
logging.info("test")
logging 設定檔
如果需要複雜一些的 logging,例如某個 module 的 log 放到某些特別的檔案中,區分 module 讓不同 module 的 log 不會全部混在一個 log file 裡面。可利用設定檔的方式處理。
logging.cfg 設定檔,定義了四個 logger,root logger 有兩個 handler,module logger 有兩個 handler,其中 console handler 是一樣的,不同的是對應到不同 log 檔案的 file handler,至於 log 的 pattern 樣式跟上面的範例設定一樣。
[loggers]
keys=root,consoleLog,projectFileHandler,moduleLog
[formatters]
keys=consoleFormatter,fileFormatter
[handlers]
keys=consoleHandler,projectFileHandler,moduleFileHandler
[logger_root]
level=DEBUG
handlers=projectFileHandler,consoleHandler
[logger_moduleLog]
level=DEBUG
qualname=moduleLog
handlers=moduleFileHandler,consoleHandler
propagate=0
[logger_consoleLog]
level=NOTSET
handlers=consoleHandler
qualname=consoleLog
propagate=0
[formatter_consoleFormatter]
format=%(asctime)s %(levelname)s {%(process)d,%(processName)s} {%(filename)s} [%(funcName)s] %(lineno)d - %(message)s
datefmt=
[formatter_fileFormatter]
format=%(asctime)s %(levelname)s {%(process)d,%(processName)s} {%(filename)s} {%(module)s} [%(funcName)s] %(lineno)d - %(message)s
datefmt=
[handler_consoleHandler]
class=StreamHandler
level=NOTSET
formatter=consoleFormatter
args=(sys.stdout,)
[handler_projectFileHandler]
class=handlers.TimedRotatingFileHandler
level=NOTSET
formatter=fileFormatter
args=('%(projectlogpath)s','midnight',1,30)
[handler_moduleFileHandler]
class=handlers.TimedRotatingFileHandler
level=NOTSET
formatter=fileFormatter
args=('%(modulelogpath)s','midnight',1,30)
在 util.py 初始化 logging
# logging
from logging import config
import logging
rootLogger = logging.getLogger()
# print( "len(logger.handlers)="+str(len(logger.handlers)) )
if len(rootLogger.handlers) == 0:
logging_cfg_file_path = os.path.join('.', 'conf/logging.cfg')
# print("logging_cfg_file_path="+logging_cfg_file_path)
# create logs directory
logs_directory = "logs"
if not os.path.exists(logs_directory):
try:
os.makedirs(logs_directory)
except OSError:
if not os.path.isdir(logs_directory):
raise
project_log_file = 'project.log'
module_log_file = 'module.log'
project_log_path = os.path.join('.', logs_directory+'/'+ project_log_file).replace('\\', '/')
module_log_path = os.path.join('.', logs_directory+'/'+ module_log_file).replace('\\', '/')
logging.config.fileConfig(logging_cfg_file_path,
defaults={'projectlogpath': project_log_path,
'modulelogpath': module_log_path},
disable_existing_loggers=False)
在使用時,如果直接用 logging,會對應使用到 root logger
import logging
logging.info("test")
但如果是透過 logging.getLogger(name="moduleLog")
可取得 moduleLog 的 logger,這時候的 log 會寫入到 module 的 log file
import logging
logger = logging.getLogger(name="moduleLog")
logger.info("test")
沒有留言:
張貼留言