Python logging日志模塊 配置文件方式
在一些微服務(wù)或web服務(wù)中我們難免需要日志功能,用來記錄一些用戶的登錄記錄,操作記錄,以及一些程序的崩潰定位,執(zhí)行訪問定位等等;
Python內(nèi)置 非常強(qiáng)大的日志模塊 ==> logging 今天給大家分享一下以配置文件形式進(jìn)行配置log日志 ;
Centos6.7
Python3.6
logging0.5.1.2
logging模塊有三個(gè)比較重要的功能組件:
1、loggers 配置文件可定義一些輸出日志的appname
2、handler 過濾器,比如設(shè)置日志的分隔大小,輸出位置,日志文件創(chuàng)建等
3、formatters 指定日志輸出的格式
1: 創(chuàng)建一個(gè)文件,以.conf結(jié)尾 或以.ini結(jié)尾(PS: 其他的結(jié)尾沒試過,你可以試試)
vim log.conf
2: 定義日志輸出的APP名,指定過濾器這里用loggers功能
[loggers] #固定寫法 keys=root,error,info #創(chuàng)建三個(gè)app名,root是父類,必需存在的 [logger_root] #創(chuàng)建完的app名我們要定義一些規(guī)則,嚴(yán)格要求格式為"logger_appname" level=DEBUG #設(shè)置日志級別 qualname=root #這里在"root"appname下可以不填,所有沒獲取get的情況下默認(rèn)app名都是root handlers=debugs #設(shè)置指定過濾器,多個(gè)以逗號分隔,這個(gè)名字待會兒 我們會以固定格式"handler_(value)"創(chuàng)建 [logger_error] level=ERROR qualname=error #除了root appname以外,定義的app名必須要設(shè)置這個(gè)屬性,用于定義打印輸出時(shí)候的app名 handlers=errors [logger_info] level=INFO qualname=INFO handlers=infos
3: 定義日志過濾器這里用handler功能
[handlers] #固定格式 keys=infos,errors,debugs #定義過濾器名稱,下面定義以handler_keysname格式定義,上面引用名稱必須和keys一致 [handler_infos] class=FileHandler #指定過濾器組件,詳情請看官網(wǎng),這個(gè)是以文件方式創(chuàng)建 level=INFO #設(shè)置級別 formatter=form01 #定義日志打印格式,下面會創(chuàng)建formatters,格式也是嚴(yán)格要求formatter_keysname 創(chuàng)建 args=('info.log','a') #創(chuàng)建文件名字,以什么方式打開 [handler_errors] class=FileHandler level=DEBUG formatter=form02 args=('info1.log','a') [handler_debugs] class=FileHandler level=DEBUG formatter=form02 args=('info1.log','a')
3: 定義日志輸出格式,這里我們介紹最后一個(gè)組件formatters
[formatters] #固定格式 keys=form01,form02 #定義名稱,下面會引用格式同上 [formatter_form01] format=%(asctime)s %(filename)s %(levelname)s %(message)s #年-月-日 時(shí)-分-秒,毫秒,文件名,級別名,消息信息 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
4: 具體程序引用
#!/usr/bin/env python import logging import logging.config logging.config.fileConfig('log.conf') logs = logging.getLogger('error') logs.error('errorsssss')
補(bǔ)充知識:python按照日志等級將日志輸出至不同的日志文件
將日志按照等級分別保存在不同的文件中,并在控制臺同步輸出。
import os import sys import logging from logs.multiprocessloghandler import MultiprocessHandler def loggerDefine(platform, log_name): base_dir = "F:\PythonProject\\xiao_new_resources\logs" info_dir_path = base_dir + "\\info\\{}".format(platform) error_dir_path = base_dir + "\\error\\{}".format(platform) # 判斷響應(yīng)的文件是否存在 if not os.path.exists(info_dir_path): os.makedirs(info_dir_path) info_dir = os.path.join(info_dir_path, log_name) if not os.path.exists(error_dir_path): os.makedirs(error_dir_path) error_dir = os.path.join(error_dir_path, log_name) # 返回一個(gè)logger對象,如果沒有指定名字將返回root logger log = logging.getLogger('test') # 定義日志輸出格式 formattler = '%(asctime)s|%(processName)s|%(threadName)s|%(levelname)s|%(filename)s:%(lineno)d|%(funcName)s|%(message)s' fmt = logging.Formatter(formattler) # 設(shè)置日志控制臺輸出 stream_handler = logging.StreamHandler(sys.stdout) stream_handler.setLevel(logging.INFO) # 設(shè)置控制臺文件輸出 log_handler_info = MultiprocessHandler(info_dir) log_handler_err = MultiprocessHandler(error_dir) # 設(shè)置日志輸出格式: stream_handler.setFormatter(fmt) log_handler_info.setFormatter(fmt) log_handler_err.setFormatter(fmt) # 設(shè)置過濾條件 info_filter = logging.Filter() info_filter.filter = lambda record: record.levelno < logging.WARNING # 設(shè)置過濾等級 err_filter = logging.Filter() err_filter.filter = lambda record: record.levelno >= logging.WARNING # 對文件輸出日志添加過濾條件 log_handler_info.addFilter(info_filter) log_handler_err.addFilter(err_filter) # 對logger增加handler日志處理器 log.addHandler(log_handler_info) log.addHandler(log_handler_err) log.addHandler(stream_handler) log.setLevel("INFO") return log if __name__ == '__main__': logg = loggerDefine("youtube", "youtube.log") logg.info("info") logg.warning("warning") logg.error("error")
multiprocessloghandler源碼:
import datetime import logging import os import re try: import codecs except ImportError: codecs = None class MultiprocessHandler(logging.FileHandler): """支持多進(jìn)程的TimedRotatingFileHandler""" def __init__(self, filename, when='D', backupCount=7, encoding="utf-8", delay=False): """ filename 日志文件名,when 時(shí)間間隔的單位,backupCount 保留文件個(gè)數(shù) delay 是否開啟 OutSteam緩存 True 表示開啟緩存,OutStream輸出到緩存,待緩存區(qū)滿后,刷新緩存區(qū),并輸出緩存數(shù)據(jù)到文件。 False表示不緩存,OutStrea直接輸出到文件 """ self.prefix = filename self.backupCount = backupCount self.when = when.upper() # 正則匹配 年-月-日 # 正則寫到這里就對了 self.extMath = r"\d{4}-\d{2}-\d{2}" # S 每秒建立一個(gè)新文件 # M 每分鐘建立一個(gè)新文件 # H 每天建立一個(gè)新文件 # D 每天建立一個(gè)新文件 self.when_dict = { 'S': "%Y-%m-%d-%H-%M-%S", 'M': "%Y-%m-%d-%H-%M", 'H': "%Y-%m-%d-%H", 'D': "%Y-%m-%d" } # 日志文件日期后綴 self.suffix = self.when_dict.get(when) # 源碼中self.extMath寫在這里 # 這個(gè)正則匹配不應(yīng)該寫到這里,不然非D模式下 會造成 self.extMath屬性不存在的問題 # 不管是什么模式都是按照這個(gè)正則來搜索日志文件的。 # if self.when == 'D': # 正則匹配 年-月-日 # self.extMath = r"^\d{4}-\d{2}-\d{2}" if not self.suffix: raise ValueError(u"指定的日期間隔單位無效: %s" % self.when) # 拼接文件路徑 格式化字符串 self.filefmt = os.path.join(os.getcwd(), "%s.%s" % (self.prefix, self.suffix)) a = "%s.%s" % (self.prefix, self.suffix) # 使用當(dāng)前時(shí)間,格式化文件格式化字符串 self.filePath = datetime.datetime.now().strftime(self.filefmt) # 獲得文件夾路徑 _dir = os.path.dirname(self.filefmt) try: # 如果日志文件夾不存在,則創(chuàng)建文件夾 if not os.path.exists(_dir): os.makedirs(_dir) except Exception: print("創(chuàng)建文件夾失敗") print("文件夾路徑:" + self.filePath) pass if codecs is None: encoding = None # 調(diào)用FileHandler logging.FileHandler.__init__(self, self.filePath, 'a+', encoding, delay) def shouldChangeFileToWrite(self): """更改日志寫入目的寫入文件 return True 表示已更改,F(xiàn)alse 表示未更改""" # 以當(dāng)前時(shí)間獲得新日志文件路徑 _filePath = datetime.datetime.now().strftime(self.filefmt) # 新日志文件日期 不等于 舊日志文件日期,則表示 已經(jīng)到了日志切分的時(shí)候 # 更換日志寫入目的為新日志文件。 # 例如 按 天 (D)來切分日志 # 當(dāng)前新日志日期等于舊日志日期,則表示在同一天內(nèi),還不到日志切分的時(shí)候 # 當(dāng)前新日志日期不等于舊日志日期,則表示不在 # 同一天內(nèi),進(jìn)行日志切分,將日志內(nèi)容寫入新日志內(nèi)。 if _filePath != self.filePath: self.filePath = _filePath return True return False def doChangeFile(self): """輸出信息到日志文件,并刪除多于保留個(gè)數(shù)的所有日志文件""" # 日志文件的絕對路徑 self.baseFilename = os.path.abspath(self.filePath) # stream == OutStream # stream is not None 表示 OutStream中還有未輸出完的緩存數(shù)據(jù) if self.stream: # self.stream.flush() self.stream.close() self.stream = None # delay 為False 表示 不OutStream不緩存數(shù)據(jù) 直接輸出 # 所有,只需要關(guān)閉OutStream即可 if not self.delay: # self.stream.close() self.stream = self._open() # 刪除多于保留個(gè)數(shù)的所有日志文件 if self.backupCount > 0: for s in self.getFilesToDelete(): # print s os.remove(s) def getFilesToDelete(self): """獲得過期需要?jiǎng)h除的日志文件""" # 分離出日志文件夾絕對路徑 # split返回一個(gè)元組(absFilePath,fileName) # 例如:split('I:\ScripPython\char4\mybook\util\logs\mylog.2017-03-19) # 返回(I:\ScripPython\char4\mybook\util\logs, mylog.2017-03-19) # _ 表示占位符,沒什么實(shí)際意義, dirName, _ = os.path.split(self.baseFilename) fileNames = os.listdir(dirName) result = [] # self.prefix 為日志文件名 列如:mylog.2017-03-19 中的 mylog # 加上 點(diǎn)號 . 方便獲取點(diǎn)號后面的日期 prefix = self.prefix prefix = _.rsplit(".", 1)[0] + "." plen = len(prefix) for fileName in fileNames: if fileName[:plen] == prefix: # 日期后綴 mylog.2017-03-19 中的 2017-03-19 suffix = fileName[plen:] # 匹配符合規(guī)則的日志文件,添加到result列表中 if re.compile(self.extMath).match(suffix): result.append(os.path.join(dirName, fileName)) result.sort() # 返回 待刪除的日志文件 # 多于 保留文件個(gè)數(shù) backupCount的所有前面的日志文件。 if len(result) < self.backupCount: result = [] else: result = result[:len(result) - self.backupCount] return result def emit(self, record): """發(fā)送一個(gè)日志記錄 覆蓋FileHandler中的emit方法,logging會自動(dòng)調(diào)用此方法""" try: if self.shouldChangeFileToWrite(): self.doChangeFile() logging.FileHandler.emit(self, record) except (KeyboardInterrupt, SystemExit): raise except: self.handleError(record)
以上這篇Python logging日志模塊 配置文件方式就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
python實(shí)現(xiàn)微信自動(dòng)回復(fù)機(jī)器人功能
wxpy基于itchat,使用了 Web 微信的通訊協(xié)議,通過大量接口優(yōu)化提升了模塊的易用性,并進(jìn)行豐富的功能擴(kuò)展。這篇文章主要介紹了python實(shí)現(xiàn)微信自動(dòng)回復(fù)機(jī)器人功能,需要的朋友可以參考下2019-07-07詳解pyqt5 動(dòng)畫在QThread線程中無法運(yùn)行問題
這篇文章主要介紹了詳解pyqt5 動(dòng)畫在QThread線程中無法運(yùn)行問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05tensorflow指定GPU與動(dòng)態(tài)分配GPU memory設(shè)置
今天小編就為大家分享一篇tensorflow指定GPU與動(dòng)態(tài)分配GPU memory設(shè)置,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02Python用matplotlib庫畫圖中文和負(fù)號顯示為方框的問題解決
matplotlib中畫圖的時(shí)候會遇到負(fù)號顯示為方框的問題,下面這篇文章主要給大家介紹了關(guān)于Python用matplotlib庫畫圖中文和負(fù)號顯示為方框的問題解決,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07Python下使用Psyco模塊優(yōu)化運(yùn)行速度
這篇文章主要介紹了Python下使用Psyco模塊優(yōu)化運(yùn)行速度,Psyco模塊可以使你的Python程序運(yùn)行的像C語言一樣快,本文給出了多個(gè)代碼示例,并講解了Psyco的安裝和使用方法,需要的朋友可以參考下2015-04-04