欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用Python自定義創(chuàng)建的Log日志模塊

 更新時間:2023年07月07日 09:17:04   作者:信橙則靈  
這篇文章主要介紹了使用Python自定義創(chuàng)建的Log日志模塊,日志文件是用于記錄系統(tǒng)操作事件的文件集合,可分為事件日志和消息日志。具有處理歷史數(shù)據、診斷問題的追蹤以及理解系統(tǒng)的活動等重要作用,需要的朋友可以參考下

日志的作用

作為一名開發(fā)人員,日志是我們排查問題的好幫手,在程序中設計一份好的日志,能夠讓我們快速定位到問題的原因。比如我們的產品在用戶手中出了問題,我們只需要查看該用戶日志,然后就能發(fā)現(xiàn)問題原因。毫無疑問。這會極大的節(jié)省我們排查問題的時間,提升了我們工作的效率。

日志分類

根據Python中l(wèi)ogging提供的日志函數(shù),它們分別是: debug()、 info()、 warning()、 error() 和 critical(),logging根據錯誤對程序運行的影響情況,可以大致分為四類(影響遞增):

  • debug:所有詳細信息,用于調試。
  • info:一些關鍵跳轉,證明軟件正常運行的日志。
  • warning:表明發(fā)生了一些意外,軟件無法處理,但是依然能正常運行。
  • error:由于一些嚴重問題,軟件不能正常執(zhí)行一些功能,但是依然能運行。
  • critical/fatal:非常嚴重的錯誤,軟件已經不能繼續(xù)運行了。

每個級別對應的數(shù)字值為
CRITICAL:50,ERROR:40,WARNING:30,INFO:20,DEBUG:10,NOTSET:0。
Python 中日志的默認等級是 WARNING,DEBUG 和 INFO 級別的日志將不會得到顯示,在 logging 中更改設置。

日志輸出

日志輸出的方式主要有兩種,一種使用 logging 在控制臺打印日志,另一種是將日志打印到文件中,方便日后的觀察

輸出到控制臺

使用 logging 在控制臺打印日志

import logging
logging.debug('運行正常')
logging.warning('博主顏值要爆表了')
logging.info('博主張的真帥,可惜你看不到')
logging.error('程序運行遇到錯誤')
logging.critical('嚴重錯誤,無法運行')

在這里插入圖片描述

根據控制臺的打印情況,可以看出,日志設置在 WARNING 級別(那些數(shù)字低于這個級別的將不會展示)

那怎么去改變日志的級別呢?

很簡單,一句代碼就可以實現(xiàn)

import logging
logging.basicConfig(level=logging.DEBUG)   # 此處的級別要大寫
logging.debug('運行正常')
logging.warning('博主顏值要爆表了')
logging.info('博主張的真帥,可惜你看不到')
logging.error('程序運行遇到錯誤')
logging.critical('嚴重錯誤,無法運行')

當設置為最小的級別時,那所有的日志信息就都展示出來了

將日志信息打印到文件中

將信息打印到文件中同樣需要調用 basicConfig ,現(xiàn)在我們修改上面的代碼,查看一下運行情況。

import logging
logging.basicConfig(level=logging.DEBUG, filename='Zhang.log', filemode='a')   # 此處的級別要大寫
logging.debug('運行正常')
logging.warning('博主顏值要爆表了')
logging.info('博主張的真帥,可惜你看不到')
logging.error('程序運行遇到錯誤')
logging.critical('嚴重錯誤,無法運行')

在這里插入圖片描述

在 basicConfig 中添加配置信息 : filename(文件名稱)、filemode(寫入文件方式),OK ,查看一下文件中的內容:

在這里插入圖片描述

在運行文件的同級目錄生成了 Zhang.log 日志文件 現(xiàn)在這個方法雖然將日志打印到文件中了,但是在控制臺中卻沒有了輸出信息,那怎么才能既在控制臺中顯示,又能寫入到日志中呢

強大的 logging

logging所提供的模塊級別的日志記錄函數(shù)是對logging日志系統(tǒng)相關類的封裝

logging 模塊提供了兩種記錄日志的方式:

  • 使用logging提供的模塊級別的函數(shù)

  • 使用Logging日志系統(tǒng)的四大組件

這里提到的級別函數(shù)就是上面所用的 DEBGE、ERROR 等級別,而四大組件則是指 loggers、handlers、filters 和 formatters 這幾個組件,下圖簡單明了的闡述了它們各自的作用:

在這里插入圖片描述

日志器(logger)是入口,真正工作的是處理器(handler),處理器(handler)還可以通過過濾器(filter)和格式器(formatter)對要輸出的日志內容做過濾和格式化等處理操作。

四大組件

下面介紹下與logging四大組件相關的類:Logger, Handler, Filter, Formatter。

在這里插入圖片描述

Logger類

Logger 對象有3個工作要做:

1)向應用程序代碼暴露幾個方法,使應用程序可以在運行時記錄日志消息;
2)基于日志嚴重等級(默認的過濾設施)或filter對象來決定要對哪些日志進行后續(xù)處理;
3)將日志消息傳送給所有感興趣的日志handlers。

Logger對象最常用的方法分為兩類:配置方法 和 消息發(fā)送方法 最常用的配置方法如下:

在這里插入圖片描述

關于Logger.setLevel()方法的說明:

內建等級中,級別最低的是DEBUG,級別最高的是CRITICAL。例如setLevel(logging.INFO),此時函數(shù)參數(shù)為INFO,那么該logger將只會處理INFO、WARNING、ERROR和CRITICAL級別的日志,而DEBUG級別的消息將會被忽略/丟棄。

logger對象配置完成后,可以使用下面的方法來創(chuàng)建日志記錄:

在這里插入圖片描述

那么,怎樣得到一個Logger對象呢?一種方式是通過Logger類的實例化方法創(chuàng)建一個Logger類的實例,但是我們通常都是用第二種方式–logging.getLogger()方法。

logging.getLogger()方法有一個可選參數(shù)name,該參數(shù)表示將要返回的日志器的名稱標識,如果不提供該參數(shù),則其值為’root’。若以相同的name參數(shù)值多次調用getLogger()方法,將會返回指向同一個logger對象的引用。

關于logger的層級結構與有效等級的說明:
     logger的名稱是一個以'.'分割的層級結構,每個'.'后面的logger都是'.'前面的logger的children,例如,有一個名稱為 foo 的logger,其它名稱分別為 foo.bar, foo.bar.baz 和 foo.bam都是 foo 的后代。
    logger有一個"有效等級(effective level)"的概念。如果一個logger上沒有被明確設置一個level,那么該logger就是使用它parent的level;如果它的parent也沒有明確設置level則繼續(xù)向上查找parent的parent的有效level,依次類推,直到找到個一個明確設置了level的祖先為止。需要說明的是,root logger總是會有一個明確的level設置(默認為 WARNING)。當決定是否去處理一個已發(fā)生的事件時,logger的有效等級將會被用來決定是否將該事件傳遞給該logger的handlers進行處理。
    child loggers在完成對日志消息的處理后,默認會將日志消息傳遞給與它們的祖先loggers相關的handlers。因此,我們不必為一個應用程序中所使用的所有l(wèi)oggers定義和配置handlers,只需要為一個頂層的logger配置handlers,然后按照需要創(chuàng)建child loggers就可足夠了。我們也可以通過將一個logger的propagate屬性設置為False來關閉這種傳遞機制。

Handler

Handler對象的作用是(基于日志消息的level)將消息分發(fā)到handler指定的位置(文件、網絡、郵件等)。Logger對象可以通過addHandler()方法為自己添加0個或者更多個handler對象。比如,一個應用程序可能想要實現(xiàn)以下幾個日志需求:

1)把所有日志都發(fā)送到一個日志文件中;
2)把所有嚴重級別大于等于error的日志發(fā)送到stdout(標準輸出);
3)把所有嚴重級別為critical的日志發(fā)送到一個email郵件地址。
這種場景就需要3個不同的handlers,每個handler復雜發(fā)送一個特定嚴重級別的日志到一個特定的位置。

一個handler中只有非常少數(shù)的方法是需要應用開發(fā)人員去關心的。對于使用內建handler對象的應用開發(fā)人員來說,似乎唯一相關的handler方法就是下面這幾個配置方法:

在這里插入圖片描述

需要說明的是,應用程序代碼不應該直接實例化和使用Handler實例。因為Handler是一個基類,它只定義了素有handlers都應該有的接口,同時提供了一些子類可以直接使用或覆蓋的默認行為。下面是一些常用的Handler:

在這里插入圖片描述

Formater

Formater對象用于配置日志信息的最終順序、結構和內容。與logging.Handler基類不同的是,應用代碼可以直接實例化Formatter類。另外,如果你的應用程序需要一些特殊的處理行為,也可以實現(xiàn)一個Formatter的子類來完成。

Formatter類的構造方法定義如下:

logging.Formatter.__init__(fmt=None, datefmt=None, style='%')

該構造方法接收3個可選參數(shù):

  • fmt:指定消息格式化字符串,如果不指定該參數(shù)則默認使用message的原始值
  • datefmt:指定日期格式字符串,如果不指定該參數(shù)則默認使用"%Y-%m-%d %H:%M:%S"
  • style:Python 3.2新增的參數(shù),可取值為 ‘%’, ‘{‘和 ‘$’,如果不指定該參數(shù)則默認使用’%’

Filter

Filter可以被Handler和Logger用來做比level更細粒度的、更復雜的過濾功能。Filter是一個過濾器基類,它只允許某個logger層級下的日志事件通過過濾。該類定義如下:

class logging.Filter(name='')
    filter(record)

比如,一個filter實例化時傳遞的name參數(shù)值為’A.B’,那么該filter實例將只允許名稱為類似如下規(guī)則的loggers產生的日志記錄通過過濾:‘A.B’,‘A.B,C’,‘A.B.C.D’,‘A.B.D’,而名稱為’A.BB’, 'B.A.B’的loggers產生的日志則會被過濾掉。如果name的值為空字符串,則允許所有的日志事件通過過濾。

filter方法用于具體控制傳遞的record記錄是否能通過過濾,如果該方法返回值為0表示不能通過過濾,返回值為非0表示可以通過過濾。

說明: 
    如果有需要,也可以在filter(record)方法內部改變該record,比如添加、刪除或修改一些屬性。
    我們還可以通過filter做一些統(tǒng)計工作,比如可以計算下被一個特殊的logger或handler所處理的record數(shù)量等。

實戰(zhàn)演練

上面文縐縐的說了(復制/粘貼)那么多,現(xiàn)在應該動手實踐了。

現(xiàn)在我需要既將日志輸出到控制臺、又能將日志保存到文件,我應該怎么辦?

利用剛才所學的知識,我們可以構思一下:

在這里插入圖片描述

看起來好像也不難,挺簡單的樣子,但是實際如此嗎?

在實際的工作或應用中,我們或許還需要指定文件存放路徑、用隨機數(shù)作為日志文件名、顯示具體的信息輸出代碼行數(shù)、日志信息輸出日期和日志寫入方式等內容。再構思一下:

在這里插入圖片描述

具體代碼如下:

import os
import logging
import uuid
from logging import Handler, FileHandler, StreamHandler
class PathFileHandler(FileHandler):
    def __init__(self, path, filename, mode='a', encoding=None, delay=False):
        filename = os.fspath(filename)
        if not os.path.exists(path):
            os.mkdir(path)
        self.baseFilename = os.path.join(path, filename)
        self.mode = mode
        self.encoding = encoding
        self.delay = delay
        if delay:
            Handler.__init__(self)
            self.stream = None
        else:
            StreamHandler.__init__(self, self._open())
class Loggers(object):
    # 日志級別關系映射
    level_relations = {
        'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARNING,
        'error': logging.ERROR, 'critical': logging.CRITICAL
    }
    def __init__(self, filename='{uid}.log'.format(uid=uuid.uuid4()), level='info', log_dir='log',
                 fmt='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
        self.logger = logging.getLogger(filename)
        abspath = os.path.dirname(os.path.abspath(__file__))
        self.directory = os.path.join(abspath, log_dir)
        format_str = logging.Formatter(fmt)  # 設置日志格式
        self.logger.setLevel(self.level_relations.get(level))  # 設置日志級別
        stream_handler = logging.StreamHandler()  # 往屏幕上輸出
        stream_handler.setFormatter(format_str)
        file_handler = PathFileHandler(path=self.directory, filename=filename, mode='a')
        file_handler.setFormatter(format_str)
        self.logger.addHandler(stream_handler)
        self.logger.addHandler(file_handler)
if __name__ == "__main__":
    txt = "關注公眾號【進擊的 Coder】,回復『日志代碼』可以領取文章中完整的代碼以及流程圖"
    log = Loggers(level='debug')
    log.logger.info(4)
    log.logger.info(5)
    log.logger.info(txt)

本人在使用代碼后,將日志模塊放入到程序中打包完成,但運行后,在exe的同級目錄并沒有產生 log 文件夾,而自己在測的時候是可以的,另外,代碼中的 os.fspath 方法是在 Python 3.6 之后才有的 最后,根據本人程序的需要,我對原作者的代碼進行了修改

import os
import logging
import time
from logging import Handler, FileHandler, StreamHandler
class PathFileHandler(FileHandler):
    def __init__(self, path, filename, mode='a', encoding=None, delay=False):
        if not os.path.exists(path):
            os.mkdir(path)
        self.baseFilename = os.path.join(path, filename)
        self.mode = mode
        self.encoding = encoding
        self.delay = delay
        if delay:
            Handler.__init__(self)
            self.stream = None
        else:
            StreamHandler.__init__(self, self._open())
class Loggers(object):
    # 日志級別關系映射
    level_relations = {
        'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARNING,
        'error': logging.ERROR, 'critical': logging.CRITICAL
    }
    def __init__(self, filename='{date}.log'.format(date = time.strftime("%Y-%m-%d_%H%M%S", time.localtime())), level='info', log_dir='log',
                 fmt='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
        self.logger = logging.getLogger(filename)
        self.directory = os.path.join(os.getcwd(), log_dir)
        format_str = logging.Formatter(fmt)  # 設置日志格式
        self.logger.setLevel(self.level_relations.get(level))  # 設置日志級別
        stream_handler = logging.StreamHandler()  # 往屏幕上輸出
        stream_handler.setFormatter(format_str)
        file_handler = PathFileHandler(path=self.directory, filename=filename, mode='a')
        file_handler.setFormatter(format_str)
        self.logger.addHandler(stream_handler)
        self.logger.addHandler(file_handler)
if __name__ == "__main__":
    txt = "將信息打印到日志文件中......"
    log = Loggers(level='debug')
    log.logger.info(4)
    log.logger.info(5)
    log.logger.info(txt)

文件保存后運行,運行結果如下圖所示:

在這里插入圖片描述

目錄內生成指定的文件和文件夾,文件打開后可以看到里面的內容:

在這里插入圖片描述

這樣,以后在需要日志的時候,直接導入該日志模塊。而且,可以根據自己的需要對模塊進行修改。最關鍵的是,原作者對該模塊設計時的思路。 如果該文章有什么問題,或者侵權,請告知,我會進行修改。

到此這篇關于使用Python自定義創(chuàng)建的Log日志模塊的文章就介紹到這了,更多相關Python自定義Log內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論