需求: 將日誌記錄異步發送到指定服務地址
實現思路:新建一個隊列,將logging的http 發送任務放入隊列中。啓動一個線程監控隊列情況,並從隊列依次取任務發送。從而將日誌記錄和日誌發送分離開,日誌發送與業務功能代碼解耦,提高運行速率。
import pytz
import logging
from logging.handlers import RotatingFileHandler
from logging.handlers import QueueHandler
from logging.handlers import QueueListener
from logging import Handler
import os
from datetime import datetime
HOST = 'https://www.leontom.com' # 日誌接收的域名
PATH = '/log' # 日誌接收path
# --------------------------------------------log queue------------------------
class SlackQueueHandler(QueueHandler):
"""日誌隊列"""
def __init__(self, queue=None):
QueueHandler.__init__(self, queue)
def prepare(self, record):
"""
Override the method to allow the formatter to work.
"""
record.msg = self.format(record)
record.args = None
record.exc_info = None
return record
class SlackQueueListener(QueueListener, Handler):
"""日誌隊列監聽者,異步發送日誌"""
def __init__(self, queue=None):
QueueListener.__init__(self, queue)
Handler.__init__(self)
secure = True if HOST.startswith('https://') else False
self.HttpHandler = TestHTTPHandler(HOST, url=PATH, method="POST", secure=secure)
def handle(self, record):
"""
Override the QueueListener.handle method with the Handler.handle
method
"""
Handler.handle(self, record)
def emit(self, record):
# msg = self.format(record)
self.HttpHandler.emit(record)
# --------------------------------------------log queue------------------------
class TestHTTPHandler(logging.handlers.HTTPHandler):
"""HTTP Log日誌發送"""
def __init__(self, host, url, method="POST", secure=False, credentials=None, context=None, report_id=None):
super().__init__(host, url, method=method, secure=secure, credentials=credentials, context=context)
self.report_id = report_id
def mapLogRecord(self, record):
"""發送內容"""
tz = pytz.timezone('Asia/Shanghai')
asctime = datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
if hasattr(record,'name') and hasattr(record, 'message'):
data = {"asctime":asctime, "name": record.name, "message":record.message}
else:
data = {"asctime":asctime, "name": 'requests', "message": str(record)}
record_ = '%(asctime)s | %(name)s | %(message)s' % dict(data)
record_msg = {'record': record_}
print('----record msg----{}'.format(record_msg))
return record_msg
class TestLogger():
def __init__(self, filePath, fileName):
self.filePath = filePath # 存放文件的路徑
self.fileName = fileName # 存放文件的名字
# self.BACK_UP_COUNT = 5000 # 文件分割上限數
# self.MAX_LOG_BYTES = 1024 * 1024 * 10 # 單個文件最大記錄數10M
self.create_handler() # 初始化創建日誌handler
self.create_logger() # 初始化創建Logger
def create_handler(self):
"""建立handler"""
self.handler = RotatingFileHandler(filename=os.path.join(self.filePath, self.fileName),
# maxBytes=self.MAX_LOG_BYTES,
# backupCount=self.BACK_UP_COUNT,
delay=1
)
formatter = logging.Formatter('%(asctime)s | %(name)s | %(message)s') # 設定輸出格式
# formatter.converter = time.gmtime # 時間轉換
self.handler.setFormatter(formatter) # 格式加載到handler
secure = True if HOST.startswith('https://') else False
log_host = HOST.replace('https://', '').replace('http://', '')
self.http_handler = TestHTTPHandler(host=log_host, url=PATH, secure=secure) # 域名不帶http:// , secure=False 表示http, secure=True 表示https 請求
def create_logger(self):
"""建立Logger"""
self.mylogger = logging.getLogger('testlog')
def log(self, msg):
self.mylogger.info(msg)
self.http_handler.emit(record=msg)
if __name__ == '__main__':
logger = TestLogger(filePath='./', fileName='test1.logs')
logger.log('---test msg---')