Django中间件与python日志模块 介绍
一、Django中間件
1.1 介紹
Django中的中間件是一個(gè)輕量級(jí)、底層的插件系統(tǒng),介于request與response處理之間的一道處理過(guò)程(用來(lái)處理特定業(yè)務(wù)的請(qǐng)求和響應(yīng))。中間件的設(shè)計(jì)為開(kāi)發(fā)者提供了一種無(wú)侵入式的開(kāi)發(fā)方式,增強(qiáng)了Django框架的健壯性。
我們可以使用中間件,在Django處理視圖的不同階段對(duì)輸入或輸出進(jìn)行干預(yù)。
請(qǐng)求—中間件—響應(yīng):
1.1.1 中間件配置
? 定義好中間件后,需要在settings.py 文件中添加注冊(cè)中間件
MIDDLEWARE = ['django.middleware.security.SecurityMiddleware', # 安全中間件'django.contrib.sessions.middleware.SessionMiddleware', # 會(huì)話中間件'corsheaders.middleware.CorsMiddleware', # 跨域請(qǐng)求中間件'django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware', # 防偽造跨域請(qǐng)求中間件'django.contrib.auth.middleware.AuthenticationMiddleware', # 授權(quán)中間件'django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware', ]【拓展】HTTP請(qǐng)求方法:
GET: 查詢
POST: 添加或修改數(shù)據(jù)
PUT : 修改數(shù)據(jù)
DELETE: 刪除數(shù)據(jù)
OPTIONS: 探測(cè)服務(wù)器是否支持跨域
Access-Control-Allow[-Origin|Headers|Methods|Credentials]
訪問(wèn)-控制-允許-[源|頭|方法|認(rèn)證]
1.1.2 中間件的鉤子函數(shù)(生命周期):
process_request: 請(qǐng)求到達(dá)時(shí),未到路由 process_view: 轉(zhuǎn)到view處理函數(shù)之前 process_exception: 在view處理函數(shù)中拋出異常時(shí) process_response: 在View響應(yīng)之后,向客戶返回(輸出)之前 process_template_response: 響應(yīng)之前,渲染模板之后1.1.3 自定義中間件類
from django.utils.deprecation import MiddlewareMixinclass AuthUserMiddleware(MiddlewareMixin):def process_request(self, request):passdef process_view(self, request, view, *args, **kwargs):passdef process_exception(self, request, exception):passdef process_response(self, request, response):return response1.1.4 通過(guò)中間件實(shí)現(xiàn)的功能
- 請(qǐng)求黑名單: 1秒內(nèi)允許2次請(qǐng)求(正常),非正常,則在process_request()方法直接返回 - 提取授權(quán)用戶的信息和權(quán)限驗(yàn)證: 提前配置請(qǐng)求路徑和用戶權(quán)限 - 異常的友好提示 - 緩存數(shù)據(jù)(減少數(shù)據(jù)庫(kù)的交互次數(shù)): process_response() 對(duì)response對(duì)象進(jìn)行序列化和緩存。 - 記錄日志(logging 模塊)1.2 線程方式實(shí)現(xiàn)緩存
import time from django.http import HttpResponse from django.utils.deprecation import MiddlewareMixin import threadingcached = {}# 過(guò)期緩存監(jiān)控的線程 class ExpireThread(threading.Thread):def clear(self, path, max_age):time.sleep(max_age)print('--checked--', path, cached.keys())if path in cached:cached.pop(path)def run(self):while True:time.sleep(1)print('--check--', cached.keys())for path, resp_max_age in cached.items():threading.Thread(target=self.clear,args=(path, resp_max_age[-1])).start()class MyMiddleware(MiddlewareMixin):def process_request(self, request):print('--process_request---', request.path)# 判斷當(dāng)前請(qǐng)求路徑是否在緩存中# 如果存在則,直接返回響應(yīng)if request.path in cached:return cached[request.path][0]def process_view(self, request, view, *args, **kwargs):# args 表示 view函數(shù)的位置參數(shù)# kwargs 表示 view函數(shù)的關(guān)鍵參數(shù)print('---process_view---', args)def process_exception(self, request, exception):print(request.path, dir(exception))print('----process_exception----', exception)return HttpResponse('<h3>Error Page 500: %s</h3>' % str(exception))def process_response(self, request, response):print('---process_response---')if request.path not in cached:# 存入緩存(內(nèi)存)print('---存入緩存---')cached[request.path] = (response, 3)print('---緩存---', cached)return responseExpireThread().start()注冊(cè)中間件, 在settings.py文件中,修改MIDDLEWARE,如下所示:
MIDDLEWARE = [...'apiapp.middleware.MyMiddleware','django.middleware.common.CommonMiddleware',... ]1.3 基于Redis實(shí)現(xiàn)緩存頁(yè)面
from utils.caches import save_response, get_response, has_response import pickle import base64class RedisCacheMiddleware(MiddlewareMixin):def process_request(self, request):print('--process_request---', request.path)# 判斷當(dāng)前請(qǐng)求路徑是否在緩存中# 如果存在則,直接返回響應(yīng)if has_response(request.path):resp_base_str = get_response(request.path)resp_bytes = base64.b32decode(resp_base_str.encode())response = pickle.loads(resp_bytes)return responsedef process_response(self, request, response):print('---process_response---')# 存入緩存(內(nèi)存)if not has_response(request.path):resp_bytes = pickle.dumps(response) # 將python的任意對(duì)象序列化字段碼# b'QABWGZDKMFXGO3ZONB2HI4BOOJSXG4DPNZZWKCSIOR2HAUTFONYG63TTMUFHCABJQFYQC7LRAIUFQCAAAAAF'resp_base64_str = base64.b32encode(resp_bytes).decode()save_response(request.path, resp_base64_str, 3)return response二、日志模塊
Python的日志模塊是: logging
import logging2.1 日志的四大部分
日志是用于記錄(Logger)程序中的一些重要信息的,記錄的信息按等級(jí)(Level)交給特定的處理器Handler按一定的格式(Formatter)進(jìn)行處理(打印、文件保存、上傳網(wǎng)絡(luò)和發(fā)送郵件等)。
2.1.1 日志記錄器 Logger
- 記錄日志信息的唯一對(duì)象, 根據(jù)不同的信息等級(jí)使用不同的記錄方法
- x.debug() 記錄調(diào)試信息,logging.DEBUG (10)
- x.info() 記錄普通信息, logging.INFO (20)
- x.warning() 記錄警告信息, loggin.WARNING (30)
- x.error() 記錄錯(cuò)誤信息, logging.ERROR (40)
- x.critical() 記錄嚴(yán)重錯(cuò)誤的信息, loggin.CRITICAL (50)
- 創(chuàng)建或獲取記錄器: logging.getLogger(name) 如果name為空,則默認(rèn)為root。
- 記錄器可以添加處理器和過(guò)濾器: x.addHandler(Handler())、 x.addFilter(Filter() )
2.1.2 日志處理器 Handler
作用: 將記錄器記錄的相關(guān)日志信息,進(jìn)行特定業(yè)務(wù)的處理,如寫(xiě)入文件的FileHandler、發(fā)送郵件的 SMTPHandler、上傳遠(yuǎn)程服務(wù)器的HTTPHandler等。
【注意】處理器可以設(shè)置日志格式化 Formatter: h.setFormatter(Formatter())
- StreamHandler 流處理器, 控制臺(tái)打印的
- FileHandler 文件處理器,將日志消息寫(xiě)入到文件中
- HTTPHandler 網(wǎng)絡(luò)處理器,將日志消息上傳到服務(wù)器
- SMTPHandler 郵件處理器,將日志消息發(fā)送到指定郵件中。
日志記錄器和處理器的關(guān)系:
一個(gè)記錄器可以添加多個(gè)處理器。
logger.addHandler(handler1) logger.addHandler(handler2) logger = logging.getLogger("network") logger.setLevel(logging.INFO) handler1 = StreamHandler() handler1.setLevel(logging.INFO)handler2 = FileHandler("network.log") handler1.setLevel(logging.WARNING)logger.addHandler(handler1) logger.addHandler(handler2)2.1.3 日志格式化 Formatter
作用: 將記錄日志信息進(jìn)行格式化(可以選擇重要的信息、或者自定義格式的信息)
經(jīng)典的日志格式:
[ %(asctime)s - %(levelname)s < line %(lineno)s at %(pathname)s > ] %(message)s如果給定的日志格式中變量不能完成業(yè)務(wù)需求時(shí),可以自定義:
[ %(asctime)s - %(username)s: %(ip)s < %(action)s > ] %(message)s以上username、ip和action都屬于自定義的格式變量,在記錄器記錄信息時(shí)指定extra 參數(shù), 它是一個(gè)字典類型,key即為擴(kuò)展的變量名,value即是它的值。
日志的格式:
| %(name)s Name of the logger (logging channel) 記錄器的名稱| %(levelno)s Numeric logging level for the message (DEBUG, INFO,| WARNING, ERROR, CRITICAL) 數(shù)字形式的日志記錄級(jí)別| %(levelname)s Text logging level for the message ("DEBUG", "INFO",| "WARNING", "ERROR", "CRITICAL") 日志記錄級(jí)別的文本名稱| %(pathname)s Full pathname of the source file where the logging| call was issued (if available) 執(zhí)行日志記錄調(diào)用的源文件的路徑名稱| %(filename)s Filename portion of pathname 執(zhí)行日志記錄調(diào)用的源文件的文件名稱| %(module)s Module (name portion of filename) 執(zhí)行日志記錄調(diào)用的模塊名稱| %(lineno)d Source line number where the logging call was issued| (if available) 執(zhí)行日志記錄調(diào)用的行號(hào)| %(funcName)s Function name 執(zhí)行日志記錄調(diào)用的函數(shù)名稱| %(created)f Time when the LogRecord was created (time.time()| return value) 執(zhí)行日志記錄的時(shí)間| %(asctime)s Textual time when the LogRecord was created 日期和時(shí)間| %(msecs)d Millisecond portion of the creation time 毫秒部分| %(relativeCreated)d Time in milliseconds when the LogRecord was created,| relative to the time the logging module was loaded| (typically at application startup time)| %(thread)d Thread ID (if available) 線程ID| %(threadName)s Thread name (if available) 線程名稱| %(process)d Process ID (if available) 進(jìn)程ID| %(message)s The result of record.getMessage(), computed just as| the record is emitted 記錄的消息2.1.4 日志過(guò)濾器 Filter
作用: 過(guò)濾一些敏感的記錄日志信息。
2.2 日志的應(yīng)用
2.2.1 標(biāo)準(zhǔn)使用
#!/usr/bin/python3 import logging from logging import StreamHandler, FileHandler, Formatter, Filterclass MsgFilter(Filter):def filter(self, record): # record記錄對(duì)象# print(dir(record)) # 查看記錄器里面的方法return record.msg.find('混沌') == -1logger = logging.getLogger('middleware') # 設(shè)置記錄器的信息等級(jí):DEBUG -> INFO -> WARNING -> ERROR -> CRITICAL logger.setLevel(logging.INFO) # 記錄器可以記錄INFO及以上等級(jí)信息# 添加日志過(guò)濾器 logger.addFilter(MsgFilter())# 創(chuàng)建日志處理器 handler1 = StreamHandler() # 流處理器,標(biāo)準(zhǔn)輸出 handler1.setLevel(logging.INFO) handler1.setFormatter(Formatter(fmt='[ %(asctime)s - %(levelname)s] %(message)s',datefmt='%Y-%m-%d %H:%M:%S' ))# 向記錄器添加處理器 logger.addHandler(handler1)handler2 = FileHandler('error.log', encoding='utf-8') handler2.setLevel(logging.ERROR) handler2.setFormatter(Formatter(fmt="[ %(asctime)s - %(levelname)s < line %(lineno)s at %(pathname)s > ] %(message)s",datefmt='%Y-%m-%d %H:%M:%S' )) logger.addHandler(handler2)if __name__ == '__main__':# x = logging.getLogger('middleware') # 獲取middleware的記錄器logging.getLogger('middleware').debug('中午吃拉面')logging.getLogger('middleware').info('中午吃木桶飯')logging.getLogger('middleware').warning('中午吃涼皮')logging.getLogger('middleware').error('中午吃粥和夾饃')logging.getLogger('middleware').critical('下午吃混沌')2.2.2 擴(kuò)展格式化的使用
mylogger = logging.getLogger('sys_action') mylogger.setLevel(logging.INFO)myhandler = StreamHandler() myhandler.setLevel(logging.INFO) myhandler.setFormatter(Formatter(fmt="[ %(asctime)s - %(username)s: %(ip)s < %(action)s > ] %(message)s",datefmt='%Y-%m-%d %H:%M:%S' ))mylogger.addHandler(myhandler)if __name__ == '__main__':extra_info = {'username': 'admin','ip': '10.36.172.110','action': 'del category'}logging.getLogger('sys_action').debug('中午吃拉面', extra=extra_info)logging.getLogger('sys_action').info('中午吃木桶飯', extra=extra_info)logging.getLogger('sys_action').warning('中午吃涼皮',extra=extra_info)logging.getLogger('sys_action').error('中午吃粥和夾饃', extra=extra_info)logging.getLogger('sys_action').critical('下午吃混沌', extra=extra_info)總結(jié)
以上是生活随笔為你收集整理的Django中间件与python日志模块 介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 从attention到Transform
- 下一篇: python实现Trie 树+朴素匹配字