需求: 将日志记录异步发送到指定服务地址
实现思路:新建一个队列,将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---')