中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python日志模塊logging如何使用

發布時間:2022-05-24 17:56:21 來源:億速云 閱讀:192 作者:iii 欄目:開發技術

這篇文章主要講解了“Python日志模塊logging如何使用”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Python日志模塊logging如何使用”吧!

關于開發日志

對于開發日志,很多程序員誤區可能就是停留在直接print打印到后臺日志中,好的地方方便快捷,但是壞的地方就是日志輸出的內容十分混亂,不方便排查。面對不同級別的事件,以及需要執行的任務時,采取的日志操作動作是不一樣的。

對此結合Python官方文檔總結以下執行任務對應的工具:

需要執行的任務

任務對應的工具

直接打印程序結果

print

記錄程序普通操作(比如請求記錄,狀態監控)

logging.info()

程序發生特殊事件引發的警告信息

logging.warning()

程序發生特殊事件引發錯誤

直接拋出異常(raise Exception)

報告錯誤而不引發異常

logging.error()、logging.exception()、logging.critical() 分別使用特定錯誤

日志功能事件級別對應應用場景(以嚴重性遞增)

級別

應用場景

DEBUG

細節信息,僅當診斷問題適用

INFO

確認程序預期運行,記錄程序正常運行狀態

WARNING

表明有已經或即將發生的意外

ERROR

由于嚴重的問題,程序某些功能不能使用

CRTICAL

嚴重的錯誤,程序已不能繼續執行

logging模塊默認級別是WARNING,意味著只會追蹤該級別以上的事件,除非更改日志配置;

關于logging基礎使用

日志記錄保存到文件

import logging
logging.basicConfig(filename="example.log", level=logging.INFO,
datefmt="%Y-%m-%d %H:%M:%S",
encoding='utf-8')
# 記錄日志信息
logging.debug("test DEBUG")
logging.info("test Info")
logging.warning("test Warning")
logging.warning('%s before you %s', 'Look', 'leap!')
logging.error("test Error")

代碼注解:

  • 3.9版本中才更新了encoding,encoding參數在更早的Python版本中沒有指定時,編碼會使用open()的默認值;

  • level是設置默認日志追蹤級別的閾值,默認級別是WARNING

  • filename是日志文件的存放路徑;

(上述腳本如果連續多次運行,連續運行的消息將追繳到指定的example.log日志文件,如果想每次都是重新開始,即example.log日志不保存之前的日志信息,則修改filemode參數為'w';)

關于logging進階使用

結合Python官方文檔,日志庫采用模塊化的方法,并提供幾類組件:記錄器、處理器、過濾器和格式器。

  • 記錄器:暴露了應用程序代碼直接使用的接口。

  • 處理器:將日志記錄(由記錄器創建)發送到適當的目標。

  • 過濾器:提供了更細粒度的功能,用于確定要輸出的日志記錄。

  • 格式器:指定最終輸出中日志記錄的樣式。

官方文檔中記錄器和處理在日志信息記錄流程:

Python日志模塊logging如何使用

解析:

  • 首先是判斷Logger對象執行的方法是否大于設置的最低嚴重性,大于則創建LogRecord對象,小于則終止;

  • 注冊的Filter對象進行過濾,如果為False不記錄日志;

  • 將LogRecord對象傳遞到當前注冊到Logger對象中的Handler對象;判斷Handler對象設置的級別大于Logger對象則證明有效,以及注冊到Handler對象中Filter過濾后是否返回True;

  • 最后判斷當前是否還有父Logger對象,如果是重復第三步,知道當前Logger設置為root Looger;

記錄器

關于記錄器,主要的任務總結有三個:

  • 暴露接口給應用程序記錄消息;

  • 根據嚴重性(默認嚴重級別)或者過濾器決定要處理的日志信息;

  • 將日志信息發送傳遞給對應日志處理器;

關于記錄器方法總結為兩類,配置和消息發送.

記錄器配置方法:

  • Logger.setLevel():設置記錄器處理的最低嚴重性日志信息(這就如果后續日志處理器設置的日志級別比記錄器低是無效的);

  • Logger.addHandler()和Logger.removeHandler():從記錄器對象中增加和刪除日志處理器對象;

  • Logger.addFilter()和Logger.removeFilter():從記錄器對象中增加和刪除過濾器;

記錄器常用創建信息方法:

  • Logger.debug() 、 Logger.info() 、 Logger.warning() 、 Logger.error() 和 Logger.critical() ;

  • Logger.exception()和以上的方法有點不同,只在異常處理程序中調用此方法,同時還記錄當前堆棧跟蹤信息;

處理器

關于處理器,簡單的可以理解為將特定嚴重級別的日志信息發送到特定的位置,常用的處理類型主要有兩個:

  • FileHandler

  • StreamHandler

由于內置處理對象常用的配置方法:

  • setLevel()方法,設置處理器中的最低嚴重性,即決定處理器該發送哪些級別的日志信息;

  • addFormatter,選擇該處理器使用的Formatter對象;

  • addFilter和removeFilter,在處理器上增加和刪除過濾器對象;

格式器

格式器配置日志消息的最終順序、結構和內容,格式器類的構造函數有三個可選參數:

  • 消息格式字符串

  • 日期格式字符串

  • 樣式指示符

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

備注:

  • fmt消息格式字符串一般不為空,為空默認就只打印message信息;

  • datefmt默認日期格式為:%Y-%m-%d %H:%M:%S;

  • style參數可選的范圍為:%、{、$這三個,主要用于fmt消息中字符串替換;

關于style:

fm = Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s",
"%Y-%m-%d %H:%M:%S", style='{')
fm = Formatter("{asctime} - {name} - {levelname} - {message}",
"%Y-%m-%d %H:%M:%S", style='{')
fm = Formatter("$asctime - $name - $levelname - $message",
"%Y-%m-%d %H:%M:%S", style='$')

(這三種style使用方式,效果都一樣)

配置記錄

開發人員可以通過三種方式配置日志記錄:

  • 使用提供的接口,顯示創建記錄器,處理器,格式器等直接配置;

  • 通過fileConfig()函數讀取已經創建好的配置文件;

  • 創建好配置函數字典傳遞到dictConfig()函數;

關于fileConfig()讀取的配置文件(官方示例):

[loggers]
keys=root,simpleExample
[handlers]
keys=consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s

(關于讀取的配置文件格式類似ini格式)

實戰

關于logging模塊,這里介紹一下我目前最常用的業務場景:調用方請求一個后端的rest api接口,我需要記錄調用方請求的時間,地址,請求參數,處理請求后的結果,以及我需要將報錯的信息保存到指定的文件里,方便排查。

為了后期使用方便,在不更改原有處理函數的基礎下增加日志記錄的功能,我會選擇將日志記錄操作封裝在一個裝飾器函數。

所以我只需將這部分功能分成兩部分:生成記錄器、請求處理的裝飾器函數

生成記錄器

# -*- coding: utf-8 -*-
from logging import handlers
from datetime import date
import logging
def init_logger():
"""
生成記錄器
:return:
"""
app_logger = logging.getLogger(APP_NAME)
app_logger.setLevel(logging.INFO)
fmt = logging.Formatter("%(asctime)s %(levelname)s: %(message)s", "%Y-%m-%d %H:%M:%S")
# 正常日志打印到控制臺
console = logging.StreamHandler()
console.setFormatter(fmt)
console.setLevel(logging.INFO)
# 異常日志記錄到log文件
today = date.today()
file_name = "logs/exceptions_" + str(today) + ".log"
fh = handlers.TimedRotatingFileHandler(filename=file_name, when='D', backupCount=30, encoding='utf-8')
fh.setLevel("ERROR")
fh.setFormatter(fmt)
app_logger.addHandler(console)
app_logger.addHandler(fh)
return app_logger

代碼解析:

  • APP_NAME是預設好的項目名稱,可根據實際業務進行調整;

  • 關于普通的StreamHandler前面已經提到了使用的方法,我這里之所選擇,是由于這個項目時Flask框架,后期部署通過uWSGI部署后端服務,我希望正常請求直接就打印在uwsgi的日志文件中,所以普通請求的處理器就選擇了StreamHandler

  • 關于異常日志處理器,這里用到特殊的TimeRotatingFileHandler,這個內置的處理器可以根據不同的時間跨度進行保存日志,就可以將異常日志信息按照一天的時間進行保存,注意設置最低嚴重性是ERROR

請求處理裝飾器

from functools import wraps
from flask import request
app_logger = init_logger()
def rest_log(return_type="dict"):
def decorator(func):
@wraps(func)
def inner(*args, **kwargs):
# 組裝打印的Message消息日志格式(請求URL,目標主機,請求方法,請求參數,響應內容)
log_params = {
"request": request.base_url,
"host": request.host,
"method": request.method
}
req_data = {}
if request.method == "POST":
req_data = dict(request.json)
elif request.method == "GET":
req_data = dict(request.args)
log_params.update({"params": req_data})
# 請求處理函數
try:
result = func(*args, **kwargs)
except Exception as e:
# 異常信息處理
err_msg = str(e)
result = {"ret_code": 500, "ret_info": err_msg}
app_logger.error(log_params, exc_info=True)
if return_type == "tuple":
result = (result, 500)
if return_type == "tuple":
log_params['result'] = result[0].data
else:
log_params['result'] = result
app_logger.info(log_params)
return result
return inner
return decorator

代碼解析:

  • 主要分為三部分:HTTP請求request解析、異常請求信息處理、請求結果處理;

  • app_logger.error(log_params, exc_info=True)中的exc_info可以將異常信息添加到日志信息中,即app_logger.exception()的效果;

  • 關于return_type參數是考慮到flask支持返回元組,即返回響應對象,響應狀態碼。考慮到日常使用場景會出現這種情況;

簡單使用示例:

# -*- coding: utf-8 -*-

from flask import request, Blueprint
from common.LogUtils import rest_log
test_api = Blueprint("TestApi", __name__)
@test_api.route("/log/test", methods=["GET"])
@rest_log()
def test_log():
name = request.args.get("name", "")
number = request.args.get('number', "")

if not name or not number:
raise Exception("number和name參數都不能為空")

response = {
"data": {
"name": f"Hello, {name}",
"number": number
},
"ret_code": 200,
"ret_info": "success"
}
return response

備注:

  • rest_log裝飾器不能放在test_api.route的前面,因為只有當路由注冊函數執行后,才能從request中獲取到對應的信息(base_url,host,method)

控制臺日志打印效果:

2022-05-22 12:01:01 INFO: {'request': 'http://127.0.0.1:23102/log/test', 'host': '127.0.0.1:23102', 'method': 'GET', 'params': {'name': 'zhangsn', 'number': '22'}, 'result': {'data': {'name': 'Hello, zhangsn', 'number': '22'}, 'ret_code': 200, 'ret_info': 'success'}}

異常日志打印:

2022-05-22 11:47:38 ERROR: {'request': 'http://127.0.0.1:23102/log/test', 'host': '127.0.0.1:23102', 'method': 'GET', 'params': {}}
Traceback (most recent call last):
File "C:\Users\admin\TestLogging\common\LogUtils.py", line 63, in inner
result = func(*args, **kwargs)
File "C:\Users\admin\TestLogging\controller\TestLogging.py", line 18, in test_log
raise Exception("number和name參數都不能為空")
Exception: number和name參數都不能為空

感謝各位的閱讀,以上就是“Python日志模塊logging如何使用”的內容了,經過本文的學習后,相信大家對Python日志模塊logging如何使用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

田阳县| 长治县| 玉林市| 大足县| 西吉县| 皮山县| 贡嘎县| 仲巴县| 崇阳县| 锡林郭勒盟| 新泰市| 磴口县| 英德市| 孝义市| 资中县| 延边| 崇义县| 栾城县| 资阳市| 乌拉特后旗| 崇礼县| 利辛县| 南雄市| 凤冈县| 久治县| 隆化县| 唐海县| 海宁市| 叙永县| 敦煌市| 郸城县| 广安市| 北川| 沙坪坝区| 东源县| 吴江市| 铜鼓县| 红桥区| 阿克陶县| 新兴县| 广饶县|