【Python】Logging 模塊 _ 打印及保存日志


1、Logging 

  用來做簡單的日志。等級分為 debug()、 info()、 warning()、 error() 和 critical()

等級 使用場景
DEBUG 調試 ,打印詳細信息
INFO 一般信息,打印關鍵信息,證明程序按預定軌跡執行。
WARNING 警告信息,未預料到的 及可能出現問題和錯誤的提示信息,但是軟件還是會照常運行    例如:磁盤空間不足。
ERROR 程序出現錯誤,可能會波及一些功能的使用
CRITICAL 嚴重錯誤,軟件不能正常執行

 

 

 

 

 

 

 

 

  logging組件:

     Logger 記錄器:     記錄運行日志,並按配置日志等級過濾日志信息。

      常用的方法分為兩類:配置和發送消息。

        Logger.setLevel()
            指定logger將會處理的日志等級信息。
        Logger.addHandler()和Logger.removeHandler()
            從記錄器對象中添加和刪除處理程序對象。
        Logger.addFilter()和Logger.removeFilter()
            從記錄器對象添加和刪除過濾器對象。
常用的方法

     Handler 處理器:     將日志存放到控制台或寫入文件。

            logging.StreamHandler    
                控制台輸出
            logging.FileHandler        
                文件輸出
            logging.handlers.RotatingFileHandler
                按照大小自動分割日志文件,一旦達到指定的大小重新生成文件 
            logging.handlers.TimedRotatingFileHandler
                按照時間自動分割日志文件 
                
            配置方法:

            setLevel()方法
                指明了將會分發日志的最低級別。為什么會有兩個setLevel()方法?記錄器的級別決定了消息是否要傳遞給處理器。
                每個處理器的級別決定了消息是否要分發。
            setFormatter()
                為該處理器選擇一個格式化器。
            addFilter()和removeFilter()
                分別配置和取消配置處理程序上的過濾器對象。
常用處理及配置方法

     Filter 過濾器:       過濾輸出的日志信息。

                addFilter(filter),removeFilter(filter)和filter(record)方法

                常用的屬性
                    name 就是初始化logger對象時傳入的名字

                    level 是級別

                    pathname 是哪個文件輸出的這行日志

                    lineno 是行號

                    msg 是日志本身
常用屬性

     Formatter 格式化器:   格式化日志輸出格式。    

            默認的時間格式為%Y-%m-%d %H:%M:%S

            常用信息
                %(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。可能沒有

                %(message)s        用戶輸出的消息
默認的時間格式為%Y-%m-%d %H:%M:%S

  

一、引用包

import logging
from logging import handles

  

二、配置日志輸出格式 

 

logging.basicConfig函數各參數(紅色為常用信息)

filename: 指定日志文件名,將文件寫入 
filemode: 和file函數意義相同,指定日志文件的打開模式,'w' 覆蓋寫入 'a' 追加寫入 ,默認寫入模式為a format: 指定輸出的格式和內容,format可以輸出很多有用信息,如上例所示:
    %(levelno)s:    打印日志級別的數值
    %(levelname)s:  打印日志級別
    %(pathname)s:   打印當前執行程序名(包含詳細路徑),其實就是sys.argv[0]
    %(filename)s:   打印當前執行程序名
    %(funcName)s:   打印日志的當前函數
    %(lineno)d:     打印日志的當前行號
    %(asctime)s:    打印日志的時間
    %(thread)d:     打印線程ID
    %(threadName)s: 打印線程名稱
    %(process)d:    打印進程ID
    %(message)s: 打印日志信息
datefmt: 指定時間格式,同time.strftime()
   英文:    %A 周, %B 月
   英文縮寫:  %a 周, %b 月, %c 日期+時間縮寫 (輸出格式:Wed Jan 12 10:00:06 2022)
   時間:    %d 日, %w 周, %m 月, %Y 年, %H:%M:%S 時分秒, %T 時間 (10:09:32), %D 日期 (12/01/22), %F 日期(2022-01-12)
level: 設置日志級別,默認為logging.WARNING 
stream: 指定將日志的輸出流,可以指定輸出到sys.stderr,sys.stdout或者文件,默認輸出到sys.stderr,當stream和filename同時指定時,stream被忽略

 

設置日志格式

# 設置打印格式
logging.basicConfig(format='%(asctime)s - %(name)s[line:%(lineno)d] - %(levelname)s: %(message)s', # 日志格式
                    datefmt='%F %T ', # 日期格式
                    level=logging.INFO) # 日志等級info

運行結果:  

 

 

 

三、打印日志(單一打印日志)

1、僅打印到控制台

# coding:utf-8
import logging

# 打印到控制台

logging.debug("打印到控制台")
logging.info("打印到控制台")
logging.warning("打印到控制台")
logging.error("打印到控制台")
logging.critical("打印到控制台")

 

  logging 默認設置的等級為warning

  運行結果:  

 

2、僅將日志寫入文件

# 設置打印格式
logging.basicConfig(format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s', # 日志格式
                    datefmt='%F %T ', # 日期格式
                    level=logging.INFO,# 日志等級
                    filename="info.log",    # 日志寫入文件info.log
                    filemode="a")      #a 追加寫入, w 覆蓋寫入

   運行結果:  

 

  info.log內容:  

 

 

 

 

四、輸出控制台並寫入日志文件

 

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import os, datetime, logging
from logging import handlers

# >>> 定義Logger類
class Logger(object):
    # 定義類屬性
    level_relations = {'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARNING, 'error': logging.ERROR, 'crit': logging.CRITICAL}#日志級別關系映射

    # 使用函數exists()對文件存在與否進行判斷,存在為True,不存在為False.
    if os.path.exists('logs') == True:  # 文件存在
        filepath = os.getcwd() + '\logs\log_' + datetime.datetime.now().strftime('%Y%m%d') + '.log'
    else:
        os.makedirs(".\logs")  # 創建文件夾
        filepath = os.getcwd() + '\logs\log_' + datetime.datetime.now().strftime('%Y%m%d') + '.log'

    # 定義構造函數  when=D 天數,新生成的文件名上會帶上時間 backCount 保留文件生成個數
    def __init__(self, filename=filepath, level='info', when='D', backCount=3, fmt='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
     #when:描述滾動周期的基本單位;“S”: Seconds ,“M”: Minutes ,“H”: Hours ,“D”: Days ,“W”: Week day (0=Monday) ,“midnight”: Roll over at midnight
        self.logger = logging.getLogger(filename)   # 指定日志文件名
        format_str = logging.Formatter(fmt) # 設置日志格式
        self.logger.setLevel(self.level_relations.get(level))   # 設置日志級別
        sh = logging.StreamHandler()    # 往屏幕上輸出
        sh.setFormatter(format_str)     # 設置屏幕上顯示的格式
        th = handlers.TimedRotatingFileHandler(filename=filename, when=when, backupCount=backCount, encoding='utf-8')  # 寫入文件
        th.setFormatter(format_str) # 設置文件里寫入的格式
        self.logger.addHandler(sh)  # 把對象加到logger里 屏幕輸出
        self.logger.addHandler(th)  # 把對象加到logger里 文件寫入

    def getLog(self):
        return self.logger

#創建log對象,隱式調用了我們手動創建的 __init__() 構造方法,並設置日志等級
# logs = Logger().logger  # 方法一
# logs = Logger().getLog()  # 方法二
# 方法三:重置日志等級
logs = Logger(level="debug").getLog()


# 該部分只有文件作為腳本時才會被執行,而 import 到其他腳本中是不會被執行的
if __name__ == '__main__':
    logs.debug('debug 信息')
    logs.info('info 信息')
    logs.warning('警告 信息')
    logs.error('報錯 信息')
    logs.critical('嚴重 信息')

 

 

運行結果

  控制台:    

 

 

   .log文件:   

 

自動分割日志文件

import logging
from logging import handlers

class Logger(object):
    level_relations = {'debug': logging.DEBUG,  'info': logging.INFO, 'warning': logging.WARNING,  'error': logging.ERROR, 'crit': logging.CRITICAL}#日志級別關系映射

    def __init__(self, filename, level='info', when='D', backCount=3, fmt='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
        self.logger = logging.getLogger(filename) # 創建一個logger
        format_str = logging.Formatter(fmt)#設置日志格式
        self.logger.setLevel(self.level_relations.get(level))#設置日志級別
        sh = logging.StreamHandler()#往屏幕上輸出
        sh.setFormatter(format_str) #設置屏幕上顯示的格式
        th = handlers.TimedRotatingFileHandler(filename=filename, when=when, backupCount=backCount, encoding='utf-8') #往文件里寫入#指定間隔時間自動生成文件的處理器
        th.setFormatter(format_str)#設置文件里寫入的格式
        self.logger.addHandler(sh) #把對象加到logger里
        self.logger.addHandler(th)#

if __name__ == '__main__':
    log = Logger('./logs/debug.log', level='debug')
    log.logger.debug('debug')
    log.logger.info('info')
    log.logger.warning('警告')
    log.logger.error('報錯')
    log.logger.critical('嚴重')
    Logger('./logs/error.log', level='error').logger.error('error')
info error  

運行結果:

 

 

 

 

 

 

 

2、loguru

# 安裝
pip install loguru
# 引用
from loguru import logger as logg
# 打印日志
logg.info("debug")

 

# 寫入文件
# logg.add("logs_20220414.log")
# 將日志保存在當前路徑上一級目錄的logs目錄下,命名為 log_name 
log_name = "log_{}.log".format(datetime.datetime.now().strftime('%Y%m%d'))
logs.add(sink=os.path.abspath("..") + "\\logs\\{}".format(log_name), level=log_level.upper()) 

# 設置生成日志文件,utf-8編碼,每天0點切割,zip壓縮,保留3天,異步寫入 
# logs.add(sink='test.log', level="INFO", rotation="00:00", retention="3 days", compression="zip", encoding="utf-8", enqueue=True)

 

 

 

 

from loguru import logger as logg
logg.add("logs.log")

def case():
    logg.debug("debug")
    logg.warning("warning")


case()
源碼

 

執行結果:

 

 

 

# 僅輸出到文件 不打印到控制台

# 刪除以前添加的處理程序並停止向其接收器發送日志。
logs.remove(handler_id=None)     # 移除控制台輸出

 

 

# 集成loguru到控制台(即html報告)
class PropogateHandler(logging.Handler):
    def emit(self, record):
        logging.getLogger(record.name).handle(record)
logs.add(PropogateHandler(), format="{time:YYYY-MM-DD at HH:mm:ss} | {message}")

 

執行結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM