编写Logger通用类

主要功能:
print → DebugLogger → debug.log

log_info() → InfoLogger → info.log

log_time() → InfoLogger → info.log

log_err() → ErrorLogger → error.log

logger.py

import logging.config
import threading
import os
import sys
import time
from abc import ABC, abstractmethod
from datetime import datetime
from typing import Optional

# Setup logs directory
os.makedirs("logs", exist_ok=True)

# Configure logging
logging.config.fileConfig('logging.conf')


class DualLogger(ABC):
    def __init__(self, logger: logging.Logger, level: int, use_stderr: bool = False):
        self.terminal = sys.__stderr__ if use_stderr else sys.__stdout__
        self.logger = logger
        self.level = level

    def write(self, message: str) -> None:
        if not message.strip():
            return
        self._console(message.rstrip())
        self.log(message.rstrip())

    def flush(self) -> None:
        self.terminal.flush()

    @abstractmethod
    def log(self, message: str) -> None:
        pass

    def _console(self, message: str) -> None:
        thread_name = threading.current_thread().name
        timestamp = datetime.now().strftime('%H:%M:%S.%f')[:-3]
        self.terminal.write(f"{timestamp}::{thread_name}::{message}\n")


class DebugLogger(DualLogger):
    def log(self, message: str) -> None:
        self.logger.debug(message)


class InfoLogger(DualLogger):
    def log(self, message: str) -> None:
        self.logger.info(message)

class TimeLogger(DualLogger):
    def log(self, message: str) -> None:
        self.logger.info(message)

class ErrorLogger(DualLogger):
    def __init__(self):
        super().__init__(logging.getLogger("error"), logging.ERROR, use_stderr=True)

    def log(self, message: str) -> None:
        self.logger.error(message)


# Configure system loggers
sys.stdout = DebugLogger(logging.getLogger("debug"), logging.DEBUG)
sys.stderr = ErrorLogger()
info_logger = InfoLogger(logging.getLogger("info"), logging.INFO)


class ElapseTimer:
    def __init__(self):
        self._thread_local = threading.local()

    def get_elapsed(self) -> float:
        current_time = time.time()
        if not hasattr(self._thread_local, 'previous_time'):
            self._thread_local.previous_time = current_time
        elapsed = current_time - self._thread_local.previous_time
        self._thread_local.previous_time = current_time
        return elapsed


timer = ElapseTimer()


def time_key(s: Optional[str], logger: DualLogger) -> None:
    if not s:
        return
    try:
        elapsed = timer.get_elapsed()
        logger.write(f"{elapsed:1.3f}--{s}")
    except Exception as e:
        sys.__stderr__.write(f"Time key error: {str(e)}\n")


# Public API
def log_err(s: str) -> None:
    sys.stderr.write(s)


def log_info(s: str) -> None:
    info_logger.write(s)

def log_time(s: str) -> None:
    time_key(s, info_logger)


if __name__ == '__main__':
    # 普通日志
    print("中文 message")  # 输出到debug.log

    log_info("中文Operation started")  # 输出到info.log
    # 耗时跟踪
    log_time("中文Operation started") # 输出到info.log
    time.sleep(0.5)
    log_time("中文Operation completed")
    log_time("中文Operation started3")
    time.sleep(0.5)
    log_time("中文Operation completed4")
    # 错误处理
    try:
        1 / 0
    except Exception:
        log_err("中文Division error occurred") # 输出到error.log

logging.conf

[loggers]
keys=root,debug,info,error

[handlers]
keys=debug_handler,info_handler,error_handler

[formatters]
keys=detailed

[logger_root]
level=DEBUG
handlers=

[logger_debug]
level=DEBUG
handlers=debug_handler
qualname=debug

[logger_info]
level=INFO
handlers=info_handler
qualname=info

[logger_error]
level=ERROR
handlers=error_handler
qualname=error

[formatter_detailed]
format=%(asctime)s.%(msecs)03d %(threadName)s %(levelname)-8s %(message)s
datefmt=%Y-%m-%d %H:%M:%S

[handler_debug_handler]
level=DEBUG
formatter=detailed
class=handlers.RotatingFileHandler
args=('logs/debug.log', 'a', 1048576, 5)

[handler_info_handler]
level=INFO
formatter=detailed
class=handlers.RotatingFileHandler
args=('logs/info.log', 'a', 1048576, 5, 'utf-8')

[handler_error_handler]
level=ERROR
formatter=detailed
class=handlers.RotatingFileHandler
args=('logs/error.log', 'a', 1048576, 5, 'utf-8')
posted @ 2025-04-16 11:18  嘚惹  阅读(8)  评论(0)    收藏  举报