import logging
import time
import threading
from logging.handlers import TimedRotatingFileHandler


class AppLogger:
    # 自定义控制台彩色格式器 + 兼容py3.7毫秒处理 + level居中8位
    class ColorFormatter(logging.Formatter):
        COLOR_MAP = {
            logging.DEBUG: "\033[36m",
            logging.INFO: "\033[32m",
            logging.WARNING: "\033[33m",
            logging.ERROR: "\033[31m",
            logging.CRITICAL: "\033[41;37m"
        }
        RESET = "\033[0m"

        def formatTime(self, record, datefmt=None):
            ct = self.converter(record.created)
            t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
            ms = f"{int(record.msecs):03d}"
            return f"{t},{ms}"

        def format(self, record):
            old_level = record.levelname
            record.levelname = record.levelname.center(8)
            raw_msg = super().format(record)
            record.levelname = old_level
            color = self.COLOR_MAP.get(record.levelno, "")
            return f"{color}{raw_msg}{self.RESET}"

    # 普通文件格式化器
    class PlainFormatter(logging.Formatter):
        def formatTime(self, record, datefmt=None):
            ct = self.converter(record.created)
            t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
            ms = f"{int(record.msecs):03d}"
            return f"{t},{ms}"

        def format(self, record):
            old_level = record.levelname
            record.levelname = record.levelname.center(8)
            raw_msg = super().format(record)
            record.levelname = old_level
            return raw_msg

    def __init__(self, log_name="app", save_file: bool = True):
        self.logger = logging.getLogger(log_name)
        if self.logger.handlers:
            return
        self.logger.setLevel(logging.DEBUG)
        self.logger.propagate = False

        fmt_str = "%(asctime)s[%(levelname)8s][%(filename)s:%(lineno)d] %(message)s"

        # 控制台彩色输出
        console_handler = logging.StreamHandler()
        console_handler.setFormatter(self.ColorFormatter(fmt_str))
        self.logger.addHandler(console_handler)

        # 文件按天轮转
        if save_file:
            file_handler = TimedRotatingFileHandler(
                filename=r"D:\code\app.log",  # 日志主文件路径,日志默认实时写入这个文件
                when="midnight",  # 日志切割时机:midnight=每天凌晨0点自动切分日志
                interval=1,  # 切割间隔倍数,配合when使用;interval=1代表每1天切一次
                backupCount=30,  # 最多保留30个历史归档日志,超过数量自动删除最旧日志,实现留存一个月
                encoding="utf-8",  # 日志文件编码为utf-8,避免中文乱码
                delay=True  # 延迟创建文件:程序启动没有日志写入时,不会自动生成空日志文件,有日志才创建
            )
            file_handler.suffix = "%Y-%m-%d"  # 切割后的历史日志后缀格式,切分后文件名示例:app.log.2026-06-17
            file_handler.setFormatter(self.PlainFormatter(fmt_str))
            self.logger.addHandler(file_handler)

    def get_logger(self):
        return self.logger


# ---------------------- 多线程压测逻辑 ----------------------
log = AppLogger(save_file=True).get_logger()

def thread_task(thread_id):
    """单个线程循环打日志"""
    for i in range(200):
        log.debug(f"线程{thread_id} debug 计数{i}")
        log.info(f"线程{thread_id} info 计数{i}")
        log.warning(f"线程{thread_id} warn 计数{i}")
        log.error(f"线程{thread_id} error 计数{i}")
        log.critical(f'asdasdasdsad')
        time.sleep(0.001)

if __name__ == "__main__":
    thread_count = 20
    thread_list = []

    log.info(f"===== 启动{thread_count}个线程开始日志压测 =====")

    for tid in range(thread_count):
        t = threading.Thread(target=thread_task, args=(tid,))
        thread_list.append(t)
        t.start()

    # 等待所有线程结束
    for t in thread_list:
        t.join()

    log.info("===== 所有线程执行完毕 =====")

更多推荐