ydf0509 / nb_log

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

一个隐蔽的问题?:get_logger里默认的Handles的日志等级与log_level_int不一致 [用户原因] #67

Closed H-tao closed 3 months ago

H-tao commented 3 months ago

我将 loguru 替换为了 nb_log,确实好用。通过这个项目,我也学到了很多东西。现在我自己开发了一个web项目,出现了一点问题,小弟想请教作者大大。

问题:get_logger里默认的Handles的日志等级与log_level_int不一致

我初始化了一个 get_logger ,并设置了日志等级为 INFO,在这个logger里有两个handler,分别是ColorHandler和ConcurrentDayRotatingFileHandler

SERVER_LOG_NAME = "server"
server_logger = get_logger(
    SERVER_LOG_NAME,
    log_filename=f"{SERVER_LOG_NAME}.log",  # 日志文件名字
    log_level_int=logging.INFO,  # 日志输出级别
    is_add_stream_handler=True,  # 是否打印日志到控制台
    log_file_handler_type=2,  
    formatter_template=ServerFormatter.formatter(),
)

我发现打印日志的时候,会将我的 DEBUG 信息也给打印出来,一开始我以为是nb_log_config.py文件里的LOG_LEVEL_FILTER的污染,经过调试,我才发现是因为这两个 Handler 是日志等级为 DEBUG。 调试图

这个问题比较隐蔽,是需要在 get_logger 的时候人为设置 handle 吗?

解决方式

我现在通过这种方式解决了这个问题:

for handle in server_logger.handlers:
    handle.setLevel(logging.INFO)
ydf0509 commented 3 months ago

handler的级别一般是不需要设置的, 例如日志级别是info, 你handler级别设置debug, 你logger.debug(msg) 是不会记录的,

如果你的日志级别是info, 你handler级别设置warning,那么你logger.info(msg)是不会记录的,

logger级别是第一道关,handler级别是第二道关,你logger级别设置 error,那么handler级别设置debug info warning error 都是一回事的,都会导致值记录 logger.error以上的日志, 也就是handler级别只要低于logger级别,那么handler设置任何级别效果都是一样的.

ydf0509 commented 3 months ago

image 你可以测试我这个代码的.

ydf0509 commented 3 months ago

或者你给个完整的可复现的demo我,我排查下. 因为我没你完整的代码,不知道这个. 这个肯定是不需要用户亲自设置handler级别来屏蔽日志的,只需要设置logger级别就好了.

ydf0509 commented 3 months ago

只有特殊情况才需要设置handler级别,例如对同一个日志命名空间,你在控制台希望只打印错误的日志,但是在文件可以记录debug及以上的,那么就需要单独设置控制台handler的级别为ERROR,设置logger级别为DEBUG,设置文件handler级别为DEBUG

H-tao commented 3 months ago

我经过调试发现了问题所在,也许是小弟的使用方法不对:

import logging

from nb_log import get_logger

SERVER_LOG_NAME = "server"
settings_loglevel = 'ERROR'

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0

_levelToName = {
    CRITICAL: 'CRITICAL',
    ERROR: 'ERROR',
    WARNING: 'WARNING',
    INFO: 'INFO',
    DEBUG: 'DEBUG',
    NOTSET: 'NOTSET',
}

_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}

LOG_LEVEL = _nameToLevel.get(settings_loglevel, 'INFO')

server_logger = get_logger(
    SERVER_LOG_NAME,
    log_filename=f"{SERVER_LOG_NAME}.log",  # 日志文件名字
    log_level_int=LOG_LEVEL,  # 日志输出级别
    is_add_stream_handler=True,  # 是否打印日志到控制台
    log_file_handler_type=1,  # 使用多进程安全按日志文件大小切割文件日志
)

logger = server_logger

def configure_logging() -> None:  # pragma: no cover
    """Configures logging."""
    handlers = get_logger(SERVER_LOG_NAME).handlers         # TODO 这行代码改变了 日志等级
    # get_logger(SERVER_LOG_NAME)  # TODO 这行代码改变了 日志等级
    # handlers = server_logger.handlers     # 这样不会改变日志等级
    # handlers = []

    logging.basicConfig(handlers=handlers, level=logging.NOTSET)  

    for logger_name in logging.root.manager.loggerDict:
        if logger_name.startswith("uvicorn."):
            logging.getLogger(logger_name).handlers = []

    # change handler for default uvicorn logger
    logging.getLogger("uvicorn").handlers = handlers
    logging.getLogger("uvicorn.access").handlers = handlers

    logging.getLogger("urllib3").handlers = handlers
    # logging.getLogger("urllib3").setLevel(logging.INFO)

    # 主项目配置 handler 和 日志等级
    get_logger("src").handlers = handlers

if __name__ == '__main__':
    print(_levelToName[server_logger.level])
    server_logger.debug('A')
    server_logger.info('B')
    server_logger.error('C')
    server_logger.critical('D')
    configure_logging()     # TODO 这行代码改变了 日志等级
    print(_levelToName[server_logger.level])
    server_logger.debug('A')
    server_logger.info('B')
    server_logger.error('C')
    server_logger.critical('D')

2024-03-13 10:50:18 "E:\PyWorkProjects\nb_log_demos\log\server_log.py:76" --[print]- ERROR 2024-03-13 10:50:18 - server - "E:\PyWorkProjects\nb_log_demos\log\server_log.py:79" - - ERROR - C 2024-03-13 10:50:18 - server - "E:\PyWorkProjects\nb_log_demos\log\server_log.py:80" - - CRITICAL - D 2024-03-13 10:50:18 "E:\PyWorkProjects\nb_log_demos\log\server_log.py:82" --[print]- DEBUG 2024-03-13 10:50:18 - server - "E:\PyWorkProjects\nb_log_demos\log\server_log.py:83" - - DEBUG - A 2024-03-13 10:50:18 - server - "E:\PyWorkProjects\nb_log_demos\log\server_log.py:84" - - INFO - B 2024-03-13 10:50:18 - server - "E:\PyWorkProjects\nb_log_demos\log\server_log.py:85" - - ERROR - C 2024-03-13 10:50:18 - server - "E:\PyWorkProjects\nb_log_demos\log\server_log.py:86" - - CRITICAL - D

ydf0509 commented 3 months ago

get_logger(SERVER_LOG_NAME) # TODO 这行代码改变了 日志等级 ,你不传递级别就是debug级别啊,你自己先设置info级别,又设置了debug级别,为什么你要再次 get_logger(SERVER_LOG_NAME) 设置debug级别呢

ydf0509 commented 3 months ago

image 为了避免低级问题,你可以看看9.5.6,锁定日志级别后再也无法修改了.

H-tao commented 3 months ago

感谢作者大大,这回复也太及时了(此处配一个心动表情包)。

这确实是我问题,我下意识把 get_logger(name)直接当成单例模式使用了,没考虑到再次 get_logger(name) 后面会重新设置日志的级别。

另外,我想请教一下 FileHandlers 里有没有类似 loguru 的 retention 配置设定保留日志天数的设置。我之前使用的是按天分割和设置保留日志天数为一个月。现在切到 nb_log 的时候想找一下这个参数,没有找到对应的文档或者handlers。求教~

ydf0509 commented 3 months ago

感谢作者大大,这回复也太及时了(此处配一个心动表情包)。

这确实是我问题,我下意识把 get_logger(name)直接当成单例模式使用了,没考虑到再次 get_logger(name) 后面会重新设置日志的级别。

另外,我想请教一下 FileHandlers 里有没有类似 loguru 的 retention 配置设定保留日志天数的设置。我之前使用的是按天分割和设置保留日志天数为一个月。现在切到 nb_log 的时候想找一下这个参数,没有找到对应的文档或者handlers。求教~

get_logger是全面自动化封装创建logger,例如你想设置新的级别,新的日志模板等都是这里传参的,如果设置成你说的单利那样,用户想再次设置新的formmater和level那怎么搞,如果你不改变日志的级别和模板等,你用之前的logger对象就可以了,或者你要和之前传参一模一样啊,

ydf0509 commented 3 months ago

nb_log支持按天切割,也支持按大小切割, 也可以大小和时间双支持的切割,你可以看文档啊,filehandler type有7种.