ydf0509 / nb_log

pip install nb_log 各种日志handler和自动转化项目的任意print的效果。日志自动彩色炫酷,可点击控制台的日志自动精确跳转到pycharm的文件和行号。文件日志多进程切割安全。在10个最重要方面全方位超过loguru
375 stars 72 forks source link

常见问题中 “普通 debug info日志写入文件a,把错误级别日志写到文件b”,提供了一个新思路,还未在生产中验证。[框架新增了这种模式] #63

Closed WenkeZhou closed 5 months ago

WenkeZhou commented 6 months ago

个人需求:所有级别日志(包含错误日志)写入到 文件a, 错误日志 写到文件b。和 title 略有差别。

  1. 在 nb_log_config.py 文件后面加上不同日志级别对应文件路径
    
    import os
    CUSTOM_LOG_FILE_PATH = os.path.join(LOG_PATH, "common.log")
    ERR_LOG_FILE_PATH = os.path.join(LOG_PATH, "error.log")

class CustomFileHandler(object): @classmethod def custom_fh(cls, log_path=CUSTOM_LOG_FILE_PATH, form_dict_type=5, log_level=logging.INFO): from nb_log.handlers import ConcurrentRotatingFileHandler fh = ConcurrentRotatingFileHandler(log_path, encoding="utf-8") fh.setLevel(log_level) fh.setFormatter(FORMATTER_DICT[form_dict_type]) return fh

@classmethod
def error_fh(cls, log_path=ERR_LOG_FILE_PATH, form_dict_type=5, log_level=logging.ERROR):
    from nb_log.handlers import ConcurrentRotatingFileHandler

    # ErrConcurrentRotatingFileHandler 完全继承 ConcurrentRotatingFileHandler, 增加了一个独立的类。
    class ErrConcurrentRotatingFileHandler(ConcurrentRotatingFileHandler):

        def __init__(self,
                     filename: str,
                     mode: str = "a",
                     maxBytes: int = 0,
                     backupCount: int = 0,
                     encoding: Optional[str] = "utf-8",
                     debug: bool = False,
                     delay: None = None,
                     use_gzip: bool = False,
                     owner: Optional[Tuple[str, str]] = None,
                     chmod: Optional[int] = None,
                     umask: Optional[int] = None,
                     newline: Optional[str] = None,
                     terminator: str = "\n",
                     unicode_error_policy: str = "ignore",
                     lock_file_directory: Optional[str] = None):
            super().__init__(filename, mode, maxBytes, backupCount, encoding, debug, delay, use_gzip, owner, chmod,
                             umask, newline, terminator, unicode_error_policy, lock_file_directory)

    fh = ErrConcurrentRotatingFileHandler(log_path)
    fh.setLevel(log_level)
    fh.setFormatter(FORMATTER_DICT[form_dict_type])
    return fh

2. 使用方法

from nb_log import get_logger from nb_log_config import CustomFileHandler

logger = get_logger(name) logger.addHandler(CustomFileHandler.custom_fh()) logger.addHandler(CustomFileHandler.error_fh())

logger.info(f"info 级别日志")
logger.error(f"error 级别日志")


3. 输出
`common.log 文件日志记录`

2023-12-12 17:42:32 - main - "E:\nblog_test_err_info.py:12" - - INFO - info 级别日志 2023-12-12 17:42:32 - main - "E:\nblog_test_err_info.py:13" - - ERROR - error 级别日志


`error.log 文件日志记录`

2023-12-12 17:42:32 - main - "E:\nblog_test_err_info.py:13" - - ERROR - error 级别日志


4. 欢迎指正,勿喷。
WenkeZhou commented 6 months ago

绕开了源码中,作者设置的两处限制。 log_manager.py

def revision_call_handlers(self, record):
    c = self
    found = 0
    hdlr_type_set = set()

    while c:
        for hdlr in c.handlers:
            hdlr_type = type(hdlr)
            if hdlr_type == logging.StreamHandler:  # REMIND 因为很多handler都是继承自StreamHandler,包括filehandler,直接判断会逻辑出错。
                hdlr_type = ColorHandler
            found = found + 1
            if record.levelno >= hdlr.level:
                if hdlr_type not in hdlr_type_set:
                    hdlr.handle(record)
                hdlr_type_set.add(hdlr_type)
        if not c.propagate:
            c = None  # break out
        else:
            c = c.parent
    # noinspection PyRedundantParentheses
    if (found == 0):
        if logging.lastResort:
            if record.levelno >= logging.lastResort.level:
                logging.lastResort.handle(record)
        elif logging.raiseExceptions and not self.manager.emittedNoHandlerWarning:
            sys.stderr.write("No handlers could be found for logger"
                             " \"%s\"\n" % self.name)
            sys.stderr.flush()
            self.manager.emittedNoHandlerWarning = True

# noinspection PyProtectedMember
def revision_add_handler(self, hdlr):  # 从添加源头阻止同一个logger添加同类型的handler。
    """
    Add the specified handler to this logger.
    """
    logging._acquireLock()  # noqa

    try:
        """ 官方的
        if not (hdlr in self.handlers):
            self.handlers.append(hdlr)
        """
        hdlrx_type_set = set()
        for hdlrx in self.handlers:
            hdlrx_type = type(hdlrx)
            if hdlrx_type == logging.StreamHandler:  # REMIND 因为很多handler都是继承自StreamHandler,包括filehandler,直接判断会逻辑出错。
                hdlrx_type = ColorHandler
            hdlrx_type_set.add(hdlrx_type)

        hdlr_type = type(hdlr)
        if hdlr_type == logging.StreamHandler:
            hdlr_type = ColorHandler
        if hdlr_type not in hdlrx_type_set:
            self.handlers.append(hdlr)
    finally:
        logging._releaseLock()  # noqa
ydf0509 commented 6 months ago

新增了这个功能,看文档1.1.a2介绍,nb_log升级到 新版本

get_logger 传参了 error_log_filename 后,error级别以上的日志会单独写入到错误文件中。 或者 在nb_log_config.py 配置文件中 配置 AUTO_WRITE_ERROR_LEVEL_TO_SEPARATE_FILE = True # 自动把错误error级别以上日志写到单独的文件,根据log_filename名字自动生成错误文件日志名字。

@D`NO I(58DAYNX88IDCZHL