python腳本攻略之log日志


1 logging模塊簡介

logging模塊是Python內置的標准模塊,主要用於輸出運行日志,可以設置輸出日志的等級、日志保存路徑、日志文件回滾等;相比print,具備如下優點:

  1. 可以通過設置不同的日志等級,在release版本中只輸出重要信息,而不必顯示大量的調試信息;
  2. print將所有信息都輸出到標准輸出中,嚴重影響開發者從標准輸出中查看其它數據;logging則可以由開發者決定將信息輸出到什么地方,以及怎么輸出
  3. 日志等級:

log4j定義了8個級別的log(除去OFF和ALL,可以說分為6個級別),優先級從高到低依次為:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL

ALL 最低等級的,用於打開所有日志記錄。

TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的日志級別,一般不會使用。

DEBUG 指出細粒度信息事件對調試應用程序是非常有幫助的,主要用於開發過程中打印一些運行信息。

INFO 消息在粗粒度級別上突出強調應用程序的運行過程。打印一些你感興趣的或者重要的信息,這個可以用於生產環境中輸出程序運行的一些重要信息,但是不能濫用,避免打印過多的日志。

WARN 表明會出現潛在錯誤的情形,有些信息不是錯誤信息,但是也要給程序員的一些提示。

ERROR 指出雖然發生錯誤事件,但仍然不影響系統的繼續運行。打印錯誤和異常信息,如果不想輸出太多的日志,可以使用這個級別。

FATAL 指出每個嚴重的錯誤事件將會導致應用程序的退出。這個級別比較高了。重大錯誤,這種級別你可以直接停止程序了。

OFF 最高等級的,用於關閉所有日志記錄。

如果將log level設置在某一個級別上,那么比此級別優先級高的log都能打印出來。例如,如果設置優先級為WARN,那么OFF、FATAL、ERROR、WARN 4個級別的log能正常輸出,而INFO、DEBUG、TRACE、 ALL級別的log則會被忽略。Log4j建議只使用四個級別,優先級從高到低分別是ERROR、WARN、INFO、DEBUG。

log4j默認的優先級為ERROR或者WARN(實際上是ERROR)

2 logging模塊使用

2.1 基本使用

1.配置logging基本的設置,然后在控制台輸出日志。

import logging
#初始化 logging.basicConfig(level
= logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s') #生成日志句柄
logger
= logging.getLogger("wqbin") logger.info("Start print log") logger.debug("Do something") logger.warning("Something maybe fail.") logger.info("Finish")

2016-10-09 19:11:19,434 - wqbin - INFO - Start print log
2016-10-09 19:11:19,434 - wqbin - WARNING - Something maybe fail.
2016-10-09 19:11:19,434 - wqbin - INFO - Finish

2.

2.1設置等級和格式有很多處。但是有優先等級。

2.2logger中添加StreamHandler,可以將日志輸出到屏幕上

2.3logger中添加FileHandler,可以將日志輸出到文件里

import logging
import time
import logging.handlers
#初始化設置
logging.basicConfig(level = logging.INFO,format='%(asctime)s|%(name)-12s: %(levelname)-8s %(message)s')
#創建
logger = logging.getLogger("wqbin")
logger.setLevel(logging.INFO)

#創建handler
handler1=logging.FileHandler("base-log.log")
handler1.setLevel(logging.INFO)
formatter=logging.Formatter('%(asctime)s|%(name)-12s+ %(levelname)-8s++%(message)s')
handler1.setFormatter(formatter)

handler2=logging.StreamHandler()
handler2.setLevel(logging.ERROR)

logger.addHandler(handler1)
logger.addHandler(handler2)

logger.info("info")
logger.warning("warning")
logger.error("error")
print('finish')

console:

2019-03-12 21:41:22,215|wqbin : INFO info
finish
2019-03-12 21:41:22,215|wqbin : WARNING warning
error
2019-03-12 21:41:22,215|wqbin : ERROR error

日志等級 初始化設置等級最高

格式 誰離得近誰最高

 

3.logging.basicConfig參數講解

logging.basicConfig(level = logging.DEBUG,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    filename  Specifies that a FileHandler be created, using the specified
              filename, rather than a StreamHandler.
    filemode  Specifies the mode to open the file, if filename is specified
              (if filemode is unspecified, it defaults to 'a').
    format    Use the specified format string for the handler.
    datefmt   Use the specified date/time format.
    style     If a format string is specified, use this to specify the
              type of format string (possible values '%', '{', '$', for
              %-formatting, :meth:`str.format` and :class:`string.Template`
              - defaults to '%').
    level     Set the root logger level to the specified level.
    stream    Use the specified stream to initialize the StreamHandler. Note
              that this argument is incompatible with 'filename' - if both
              are present, 'stream' is ignored.
    handlers  If specified, this should be an iterable of already created
              handlers, which will be added to the root handler. Any handler
              in the list which does not have a formatter assigned will be
              assigned the formatter created in this function.

4.fomat參數講解

%(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:打印日志信息

3 logging模塊高級用法

3.1日志回滾

什么是日志回滾:

將日志信息輸出到一個單一的文件中,隨着應用程序的持續使用,該日志文件會越來越龐大,進而影響系統的性能。因此,有必要對日志文件按某種條件進行切分,要切分日志文件。

分割日志的觸發條件:大小、日期,或者大小加上日期。

說是切分,實際上是,當一個日志文件達到觸發條件后,對日志文件進行重命名,之后再新建原來名稱的日志文件(此時就是空文件了),新產生的日志就寫入新的日志文件。

為啥叫回滾呢?當分割的日志文件達到指定數目的上限個數時,最老的日志文件就會被刪除。

logging庫提供了兩個可以用於日志滾動的class

1)RotatingFileHandler,它主要是根據日志文件的大小進行滾動,

2)TimeRotatingFileHandler,它主要是根據時間進行滾動。在實際應用中,我們通常根據時間進行滾動。

3.1.1按照天切分日志

import time
import logging
import logging.handlers
import os

# 如果日志文件夾不存在,則創建
log_dir = "log-day"  # 日志存放文件夾名稱
log_path = os.getcwd() + os.sep + log_dir
if not os.path.isdir(log_path):
    os.makedirs(log_path)

# logging初始化工作
logging.basicConfig()

# myapp的初始化工作
myapp = logging.getLogger('myapp')
myapp.setLevel(logging.INFO)

# 添加TimedRotatingFileHandler
# 定義一個1天換一次log文件的handler
# 保留3個舊log文件
timefilehandler = logging.handlers.TimedRotatingFileHandler(
    log_dir + os.sep + "sec.log",
    when='M',
    interval=1,
    backupCount=3
)
# 設置后綴名稱,跟strftime的格式一樣
timefilehandler.suffix = "%Y-%m-%d_%H-%M-%S.log"
# timefilehandler.suffix = "%Y-%m-%d.log"

formatter = logging.Formatter('%(asctime)s|%(name)-12s: %(levelname)-8s %(message)s')
timefilehandler.setFormatter(formatter)
myapp.addHandler(timefilehandler)

while True:
    time.sleep(6)
    myapp.info("test")

 

 

3.1.2按照時間日志回滾

import os
import time
import logging
import logging.handlers

log_dir = "log-day"  # 日志存放文件夾名稱
log_path = os.getcwd() + os.sep + log_dir
if not os.path.isdir(log_path):
    os.makedirs(log_path)

# logging初始化工作
logging.basicConfig()

# myapp的初始化工作
myapp = logging.getLogger('myapp')
myapp.setLevel(logging.INFO)

# 添加TimedRotatingFileHandler
# 定義一個1秒換一次log文件的handler
# 保留3個舊log文件
timefilehandler = logging.handlers.TimedRotatingFileHandler("log-day/myapp.log", when='S', interval=1, backupCount=3)
# 設置后綴名稱,跟strftime的格式一樣
timefilehandler.suffix = "%Y-%m-%d_%H-%M-%S.log"

formatter = logging.Formatter('%(asctime)s|%(name)-12s: %(levelname)-8s %(message)s')
timefilehandler.setFormatter(formatter)
myapp.addHandler(timefilehandler)

while True:
    time.sleep(0.1)
    myapp.info("test")

 

注意:filehanlder.suffix的格式必須這么寫,才能自動刪除舊文件,如果設定是天,就必須寫成“%Y-%m-%d.log”,寫成其他格式會導致刪除舊文件不生效。這個配置在源碼里能看出來,但是在官方文檔並沒有說明這一點!!!!!!!!!!

 

TimedRotatingFileHandler的構造函數定義如下:
TimedRotatingFileHandler(filename [,when [,interval [,backupCount]]])
filename 是輸出日志文件名的前綴,比如log/myapp.log
when 是一個字符串的定義如下:
“S”: Seconds
“M”: Minutes
“H”: Hours
“D”: Days
“W”: Week day (0=Monday)
“midnight”: Roll over at midnight
interval 是指等待多少個單位when的時間后,Logger會自動重建文件,當然,這個文件的創建
取決於filename+suffix,若這個文件跟之前的文件有重名,則會自動覆蓋掉以前的文件,所以
有些情況suffix要定義的不能因為when而重復。
backupCount 是保留日志個數。默認的0是不會自動刪除掉日志。若設3,則在文件的創建過程中
庫會判斷是否有超過這個3,若超過,則會從最先創建的開始刪除。

3.1.3 按照大小日志回滾

RotatingFileHandler基於文件大小切分
這個配置是可以生效的,符合預期

import os
import time
import logging
import logging.handlers


log_dir = "log-day"  # 日志存放文件夾名稱
log_path = os.getcwd() + os.sep + log_dir
if not os.path.isdir(log_path):
    os.makedirs(log_path)
# logging初始化工作
logging.basicConfig()

# myapp的初始化工作
myapp = logging.getLogger('myDemo')
myapp.setLevel(logging.INFO)

# 寫入文件,如果文件超過100個Bytes,僅保留5個文件。
handler = logging.handlers.RotatingFileHandler(
    'log-day/myDemo.log', maxBytes=500, backupCount=5)

formatter = logging.Formatter('%(asctime)s|%(name)-12s: %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
# 設置后綴名稱,跟strftime的格式一樣
myapp.addHandler(handler)

while True:
    time.sleep(0.1)
    myapp.info("file test")

 3.2traceback

import logging
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler("log-day/log.txt")
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)

console = logging.StreamHandler()
console.setLevel(logging.INFO)

logger.addHandler(handler)
logger.addHandler(console)

logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
try: open("log-day/sklearn.txt","rb") except (SystemExit,KeyboardInterrupt): raise
except Exception: logger.error("Faild to open sklearn.txt from logger.error",exc_info = True) 
logger.info("Finish")

也可以使用logger.exception(msg,_args),它等價於logger.error(msg,exc_info = True,_args),

logger.error("Faild to open sklearn.txt from logger.error",exc_info = True)==>>logger.exception("Failed to open sklearn.txt from logger.exception")

 


免責聲明!

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



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