解决设置 logger 后 cmd 还是输出报错信息的问题

解决设置 logger 后 cmd 还是输出报错信息的问题

创作背景

最近本菜鸡在使用 logging 时想要进行如下设置:

  1. 命令行不输出日志信息
  2. ERROR 信息输出到 error.log 文件中
  3. 其他都输出到 process.log 文件中

但是我设置完 logger 后命令行还是有报错信息输出,这是怎么回事呢?

本文就教你如何解决这个问题,也是记录一下以供以后的我学习。

如果觉得我这篇文章写的好的话,能不能给我 点个赞评论收藏 一条龙(☆▽☆)。如果要点个 关注 的话也不是不可以🤗。

请各位参加一下文末的 投票 哦,如果 有什么不足之处,还 请各位大佬在评论区提出,不胜感激。

问题代码

先来看看问题代码。

import logging

error_log_path = r'error.log'
major_log_path = r'process.log'

logging.basicConfig(
    format='%(asctime)s | %(filename)s[line:%(lineno)d] | %(levelname)s | Message: %(message)s',
    filemode='a'
)

major_logger = logging.getLogger()
major_logger.addHandler(logging.FileHandler(major_log_path))
exc_info_logger = logging.getLogger()
exc_info_logger.addHandler(logging.FileHandler(error_log_path))

def keep_log(message, level='info'):
    message = str(message).replace('\n', '').replace('|', ' ')
    if level.lower() == 'error':
        exc_info_logger.error('', exc_info=True)
    else:
        f = eval(f'major_logger.{level.lower()}')
        f(message)

其中:

  • major_logger 实现功能 3
  • exc_info_logger 实现功能 2
  • 两个 logger 共同实现功能 1

使用代码测试。

try:
    a = 1 / 0
except:
    keep_log('除数不能为零哦', 'error')

执行后确实会创建 error.log 文件,且写入信息,如下图所示。

在这里插入图片描述
可是出现了问题,如下图所示。
在这里插入图片描述
命令行也同样输出了错误信息。

这是怎么回事呢?

尝试解决

出现问题后,我向万能的百度求救,让我找到了一个看似可行的方案,链接

在这里插入图片描述
按照这位答主所说,需要将 propagate 属性设置为 False 才能达到我想要的效果。

尝试一下,代码如下:

major_logger = logging.getLogger()
major_logger.propagate = False
exc_info_logger = logging.getLogger()
exc_info_logger.propagate = False

但执行结果如下图所示:

在这里插入图片描述
命令行还是会输出错误结果。

如果 按照那位答主所说成功设置后能够隐藏命令行输出 并且 我的代码中 propagate 成功设置 的话,那问题应该是 Logger 中没有 propagate 这个属性导致功能没有实现。

查看一下 Logger 的源码:

在这里插入图片描述
有这个属性,如果成功设置的话应该会像答主所说的一样,那说明这个属性我没有成功设置。

问题出在哪里呢?

让我们看一下 getLogger 这个函数的源码:

在这里插入图片描述
其中有个 root ,看一下它的定义。

在这里插入图片描述可以看到,rootRootLogger 的实例化对象,再看一下 RootLogger 的源码。

在这里插入图片描述可以看到,RootLoggerLogger 的子类,追溯一下,可以找到 Logger 对象中进行 日志记录 的方法,如下图所示。

在这里插入图片描述
按照 getLogger 的逻辑,有 name新建一个 Logger 对象 ,否则返回 root ,即 RootLogger(WARNING)

可以看到, callHandlers 函数中,如果 propagate 属性为 True 的话,就会调用该 logger 的父级 logger ,进行同样的输出。

但是,我的代码中两个 getLogger 都返回的 RootLogger ,也就是都对 RootLogger 进行设置。

可是既然都设置 RootLogger 了,为什么还是会在命令行输出呢?

让我回溯一下:

我设置了 baseConfig ,只有 formatfilemode 两个属性,看一下 baseConfig 的源码:
在这里插入图片描述
当进行到画圈的位置时,因为没有制定日志文件路径,使用会实例化一个 StreamHandler 而不是 FileHandler

而且如下图所示,这个 StreamHandler 的输出是 sys.stderr
在这里插入图片描述
如下图所示,Logger 记录日志时会使用所有的 Handler 进行记录,其中就包括 StreamHandler ,所以会将日志输出至命令行。

为了验证我的猜想,在 getLogger 后输出 logger.handlers ,结果如下图所示。
在这里插入图片描述
和我的猜想一致。

你要问我为什么会多出来一个 process.logFileHandlererror.logFileHandler ,那我只能告诉你,我用的 jupyter ,直接重新运行的😜。

问题解决

既然已经知道了问题原因,那解决起来就挺简单了,只需要两步即可实现功能。

  1. getLogger 时传入参数 name ,这样返回的就是一个 RootLogger 的子 Logger
  2. 将此 loggerpropagate 属性设置为 False ,使其父 Logger 不会进行同等输出。

代码如下:

import logging

error_log_path = r'error.log'
major_log_path = r'process.log'

logging.basicConfig(
    format='%(asctime)s | %(filename)s[line:%(lineno)d] | %(levelname)s | Message: %(message)s',
    filemode='a'
)

major_logger = logging.getLogger('major')
major_logger.propagate = False
major_logger.addHandler(logging.FileHandler(major_log_path))
exc_info_logger = logging.getLogger('exc')
exc_info_logger.propagate = False
exc_info_logger.addHandler(logging.FileHandler(error_log_path))

def keep_log(message, level='info'):
    message = str(message).replace('\n', '').replace('|', ' ')
    if level.lower() == 'error':
        exc_info_logger.error('', exc_info=True)
    else:
        f = eval(f'major_logger.{level.lower()}')
        f(message)

再测试一下,结果如下图所示。
在这里插入图片描述
成功完成任务!!!




结尾

有想要一起学习 python 的小伙伴可以 私信我 进群哦。

以上就是我要分享的内容,因为 学识尚浅会有不足,还 请各位大佬指正
有什么问题也可在评论区留言。
在这里插入图片描述

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值