日志记录统一格式和位置,多线程多文件多策略分类记录和打印
# -*- coding: utf-8 -*-
import atexit
import hashlib
import logging.config
import os
import sys
import queue
import time
from logging.handlers import QueueHandler, TimedRotatingFileHandler
class HiwayTimedRotatingFileHandler(TimedRotatingFileHandler):
"""修改日志文件命名格式"""
def __init__(self, *args, **kwargs):
super(HiwayTimedRotatingFileHandler, self).__init__(*args, **kwargs)
def doRollover(self):
"""
do a rollover; in this case, a date/time stamp is appended to the filename
when the rollover happens. However, you want the file to be named for the
start of the interval, not the current time. If there is a backup count,
then we have to get a list of matching filenames, sort them and remove
the one with the oldest suffix.
"""
if self.stream:
self.stream.close()
self.stream = None
# get the time that this sequence started at and make it a TimeTuple
currentTime = int(time.time())
dstNow = time.localtime(currentTime)[-1]
t = self.rolloverAt - self.interval
if self.utc:
timeTuple = time.gmtime(t)
else:
timeTuple = time.localtime(t)
dstThen = timeTuple[-1]
if dstNow != dstThen:
if dstNow:
addend = 3600
else:
addend = -3600
timeTuple = time.localtime(t + addend)
dfn = self.rotation_filename(self.baseFilename[:-4] +
time.strftime(self.suffix, timeTuple) + ".log")
if os.path.exists(dfn):
os.remove(dfn)
self.rotate(self.baseFilename, dfn)
if self.backupCount > 0:
for s in self.getFilesToDelete():
os.remove(s)
if not self.delay:
self.stream = self._open()
newRolloverAt = self.computeRollover(currentTime)
while newRolloverAt <= currentTime:
newRolloverAt = newRolloverAt + self.interval
# If DST changes and midnight or weekly rollover, adjust for this.
if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc:
dstAtRollover = time.localtime(newRolloverAt)[-1]
if dstNow != dstAtRollover:
if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour
addend = -3600
else: # DST bows out before next rollover, so we need to add an hour
addend = 3600
newRolloverAt += addend
self.rolloverAt = newRolloverAt
LOG_DIR = os.path.join("logs", datetime.datetime.now().strftime("%Y-%m-%d"))
if not os.path.exists(LOG_DIR):
os.makedirs(LOG_DIR)
# 全局日志把手
logger_handlers = {}
def get_logger(log_name='defalut', console_mode=True, when='D',level=logging.INFO):
"""
:param log_name: 日志名
:param console_mode: 是否打印标志
:param when: 分页模式;D--每天,H--每小时
:param level: 日志默认记录等级
:return: 日志把手
"""
log_md5=hashlib.md5(log_name.encode('utf-8')).hexdigest()
logger_obj = logger_handlers.get(log_md5)
if logger_obj:
return logger_obj
# 定义线程中日志队列
default_queue = queue.Queue(-1)
default_queue_handler = QueueHandler(default_queue)
# 定义日志文件把手
default_handler = HiwayTimedRotatingFileHandler(filename=os.path.join(LOG_DIR, f"{log_name}.log"), when=when,
backupCount=5, encoding='utf-8')
# 定义日志打印把手
default_stream_handler = logging.StreamHandler()
# 定义日志格式
simple_formater = '%(asctime)s - %(levelname)s - %(name)s - %(filename)s:%(lineno)d >> %(message)s'
standard_formater = '[%(asctime)s][%(threadName)s:%(thread)d][log_name:%(name)s][%(filename)s:%(lineno)d][%(levelname)s] >> %(message)s'
formatter = logging.Formatter(standard_formater)
default_handler.setFormatter(formatter)
default_stream_handler.setFormatter(formatter)
# 定义日志监听器
default_listener = logging.handlers.QueueListener(default_queue, default_handler, respect_handler_level=True)
# 定义日志记录器
default_logger = logging.getLogger(log_name)
default_logger.propagate = False
default_logger.addHandler(default_queue_handler)
if console_mode:
default_logger.addHandler(default_stream_handler)
default_logger.setLevel(level)
default_listener.start()
atexit.register(default_listener.stop)
logger_handlers.update({log_md5: default_logger})
return default_logger