Python logging日志模塊 配置文件方式
在一些微服務(wù)或web服務(wù)中我們難免需要日志功能,用來(lái)記錄一些用戶的登錄記錄,操作記錄,以及一些程序的崩潰定位,執(zhí)行訪問(wèn)定位等等;
Python內(nèi)置 非常強(qiáng)大的日志模塊 ==> logging 今天給大家分享一下以配置文件形式進(jìn)行配置log日志 ;
Centos6.7
Python3.6
logging0.5.1.2
logging模塊有三個(gè)比較重要的功能組件:
1、loggers 配置文件可定義一些輸出日志的appname
2、handler 過(guò)濾器,比如設(shè)置日志的分隔大小,輸出位置,日志文件創(chuàng)建等
3、formatters 指定日志輸出的格式
1: 創(chuàng)建一個(gè)文件,以.conf結(jié)尾 或以.ini結(jié)尾(PS: 其他的結(jié)尾沒(méi)試過(guò),你可以試試)
vim log.conf
2: 定義日志輸出的APP名,指定過(guò)濾器這里用loggers功能
[loggers] #固定寫(xiě)法 keys=root,error,info #創(chuàng)建三個(gè)app名,root是父類(lèi),必需存在的 [logger_root] #創(chuàng)建完的app名我們要定義一些規(guī)則,嚴(yán)格要求格式為"logger_appname" level=DEBUG #設(shè)置日志級(jí)別 qualname=root #這里在"root"appname下可以不填,所有沒(méi)獲取get的情況下默認(rèn)app名都是root handlers=debugs #設(shè)置指定過(guò)濾器,多個(gè)以逗號(hào)分隔,這個(gè)名字待會(huì)兒 我們會(huì)以固定格式"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: 定義日志過(guò)濾器這里用handler功能
[handlers] #固定格式
keys=infos,errors,debugs #定義過(guò)濾器名稱(chēng),下面定義以handler_keysname格式定義,上面引用名稱(chēng)必須和keys一致
[handler_infos]
class=FileHandler #指定過(guò)濾器組件,詳情請(qǐng)看官網(wǎng),這個(gè)是以文件方式創(chuàng)建
level=INFO #設(shè)置級(jí)別
formatter=form01 #定義日志打印格式,下面會(huì)創(chuàng)建formatters,格式也是嚴(yán)格要求formatter_keysname 創(chuàng)建
args=('info.log','a') #創(chuàng)建文件名字,以什么方式打開(kāi)
[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 #定義名稱(chēng),下面會(huì)引用格式同上 [formatter_form01] format=%(asctime)s %(filename)s %(levelname)s %(message)s #年-月-日 時(shí)-分-秒,毫秒,文件名,級(jí)別名,消息信息 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ǔ)充知識(shí):python按照日志等級(jí)將日志輸出至不同的日志文件
將日志按照等級(jí)分別保存在不同的文件中,并在控制臺(tái)同步輸出。
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對(duì)象,如果沒(méi)有指定名字將返回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è)置日志控制臺(tái)輸出
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setLevel(logging.INFO)
# 設(shè)置控制臺(tái)文件輸出
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è)置過(guò)濾條件
info_filter = logging.Filter()
info_filter.filter = lambda record: record.levelno < logging.WARNING # 設(shè)置過(guò)濾等級(jí)
err_filter = logging.Filter()
err_filter.filter = lambda record: record.levelno >= logging.WARNING
# 對(duì)文件輸出日志添加過(guò)濾條件
log_handler_info.addFilter(info_filter)
log_handler_err.addFilter(err_filter)
# 對(duì)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 是否開(kāi)啟 OutSteam緩存
True 表示開(kāi)啟緩存,OutStream輸出到緩存,待緩存區(qū)滿后,刷新緩存區(qū),并輸出緩存數(shù)據(jù)到文件。
False表示不緩存,OutStrea直接輸出到文件
"""
self.prefix = filename
self.backupCount = backupCount
self.when = when.upper()
# 正則匹配 年-月-日
# 正則寫(xiě)到這里就對(duì)了
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寫(xiě)在這里
# 這個(gè)正則匹配不應(yīng)該寫(xiě)到這里,不然非D模式下 會(huì)造成 self.extMath屬性不存在的問(wèn)題
# 不管是什么模式都是按照這個(gè)正則來(lái)搜索日志文件的。
# if self.when == 'D':
# 正則匹配 年-月-日
# self.extMath = r"^\d{4}-\d{2}-\d{2}"
if not self.suffix:
raise ValueError(u"指定的日期間隔單位無(wú)效: %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):
"""更改日志寫(xiě)入目的寫(xiě)入文件
return True 表示已更改,F(xiàn)alse 表示未更改"""
# 以當(dāng)前時(shí)間獲得新日志文件路徑
_filePath = datetime.datetime.now().strftime(self.filefmt)
# 新日志文件日期 不等于 舊日志文件日期,則表示 已經(jīng)到了日志切分的時(shí)候
# 更換日志寫(xiě)入目的為新日志文件。
# 例如 按 天 (D)來(lái)切分日志
# 當(dāng)前新日志日期等于舊日志日期,則表示在同一天內(nèi),還不到日志切分的時(shí)候
# 當(dāng)前新日志日期不等于舊日志日期,則表示不在
# 同一天內(nèi),進(jìn)行日志切分,將日志內(nèi)容寫(xiě)入新日志內(nèi)。
if _filePath != self.filePath:
self.filePath = _filePath
return True
return False
def doChangeFile(self):
"""輸出信息到日志文件,并刪除多于保留個(gè)數(shù)的所有日志文件"""
# 日志文件的絕對(duì)路徑
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):
"""獲得過(guò)期需要?jiǎng)h除的日志文件"""
# 分離出日志文件夾絕對(duì)路徑
# 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)
# _ 表示占位符,沒(méi)什么實(shí)際意義,
dirName, _ = os.path.split(self.baseFilename)
fileNames = os.listdir(dirName)
result = []
# self.prefix 為日志文件名 列如:mylog.2017-03-19 中的 mylog
# 加上 點(diǎn)號(hào) . 方便獲取點(diǎn)號(hào)后面的日期
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會(huì)自動(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日志模塊 配置文件方式就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Python中內(nèi)置的日志模塊logging用法詳解
- python標(biāo)準(zhǔn)日志模塊logging的使用方法
- Python中使用logging模塊打印log日志詳解
- Python中使用logging模塊代替print(logging簡(jiǎn)明指南)
- Python logging模塊handlers用法詳解
- 解決Python logging模塊無(wú)法正常輸出日志的問(wèn)題
- Python使用logging模塊實(shí)現(xiàn)打印log到指定文件的方法
- 詳解?python?logging日志模塊
- Python中的logging模塊實(shí)現(xiàn)日志打印
- Python中l(wèi)ogging模塊用法示例總結(jié)
相關(guān)文章
對(duì)numpy下的軸交換transpose和swapaxes的示例解讀
今天小編就為大家分享一篇對(duì)numpy下的軸交換transpose和swapaxes的示例解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-06-06
Python把png轉(zhuǎn)成jpg的項(xiàng)目實(shí)踐
本文主要介紹了Python把png轉(zhuǎn)成jpg的項(xiàng)目實(shí)踐,可以使用PIL庫(kù)來(lái)將PNG圖片轉(zhuǎn)換為JPG格式,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02
Python通過(guò)四大 AutoEDA 工具包快速產(chǎn)出完美數(shù)據(jù)報(bào)告
在三年前,我們做數(shù)據(jù)競(jìng)賽或者數(shù)據(jù)建模類(lèi)的項(xiàng)目時(shí),前期我們會(huì)耗費(fèi)較多的時(shí)間去分析數(shù)據(jù),但現(xiàn)在非常多擅長(zhǎng)數(shù)據(jù)分析的大師們已經(jīng)將我們平時(shí)??吹臄?shù)據(jù)方式進(jìn)行了集成,開(kāi)發(fā)了很多AutoEDA的工具包??梢詭椭覀児?jié)省大量時(shí)間2021-11-11
Elasticsearches的集群搭建及數(shù)據(jù)分片過(guò)程詳解
這篇文章主要為大家介紹了Elasticsearches的集群搭建及數(shù)據(jù)分片過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04
Python摸魚(yú)神器之利用樹(shù)莓派opencv人臉識(shí)別自動(dòng)控制電腦顯示桌面
這篇文章主要介紹了Python摸魚(yú)神器樹(shù)莓派opencv人臉識(shí)別自動(dòng)控制電腦顯示桌面,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
Python簡(jiǎn)單基礎(chǔ)小程序的實(shí)例代碼
這篇文章主要介紹了Python簡(jiǎn)單基礎(chǔ)小程序的實(shí)例代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-04-04
python繞過(guò)圖片滑動(dòng)驗(yàn)證碼實(shí)現(xiàn)爬取PTA所有題目功能 附源碼
這篇文章主要介紹了python繞過(guò)圖片滑動(dòng)驗(yàn)證碼實(shí)現(xiàn)爬取PTA所有題目 附源碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01

