python日志logging的用法

本文介绍了如何在Python中实现跨文件的日志记录,通过在单独的logging_config.py中定义一个类方法,确保在多个文件中使用相同的日志配置。强调了使用`logging.getLogger(__name__)`时传入模块名称的重要性,以防因Logger名称冲突导致的日志混乱。

python日志看起比较简单,要用起来稍微有点复杂,基础用法网上也介绍得比较多,下面就最近遇见的问题,作一个简单的介绍。就是在两个以上的python文件中要记录日志,怎么才能实现在一个地方配置,多个地方使用的情景。

直接上配置代码:

logging_config.py

# -*- coding: UTF-8 -*-

import logging
from logging import FileHandler

class LoggerTest:
   
    @classmethod
    def get_logger(cls,name):
        #name表示模块的名字,调用函数时传入,以便知道来自哪里
        logger = logging.getLogger(name)
        
        logger.setLevel(logging.DEBUG)
        # 文件处理器,设置的级别为INFO
        file_handler = FileHandler(filename="logging_test.log")
        # 创建一个格式器
        formatter = logging.Formatter(fmt='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',datefmt='%Y-%m-%d %H:%M:%S')
        # 作用在handler上
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)
        return logger

思路就是在一个单独文件里面,写一个类方法,其它需要用到日志记录的,都调用这个代码。

如:

logging_test2.py

# -*- coding: UTF-8 -*-

from logging_config import LoggerTest

class LoggingTest2:
    logger = LoggerTest.get_logger(__name__)
    
    def __init__(self):       
        self.logger.info("this is test2")

logging_test.py

# -*- coding: UTF-8 -*-

from logging_test2 import LoggingTest2
from logging_config import LoggerTest

class LoggingTest:
    logger = LoggerTest.get_logger(__name__)
    
    def __init__(self):        
        self.logger.info("this is test")

if __name__=='__main__':
    LoggingTest()
    LoggingTest2()

logging_test2.py、logging_test.py两个文件中,都用到了日志记录的功能,用到的日志对象都来自logging_config.py中的LoggerTest.get_logger,从而实现了只在一处配置的用法。

运行logging_test.py以后,就可以看到日志文件了:

 可以看到,这两个py文件的日志都记录到logging_test.log文件中,结果还是比较理想。

现在我们来细究一个问题,那就是关于logging.getLogger(name)这个方法的应用,如果我们直接去掉参数name,程序照样能运行,但是会有些问题。

logger = logging.getLogger()
print(f"logger={logger}")

运行结果如下:

可以看出,如果不传名字name,那么logging会默认用RootLogger来替代,RootLogger的__repr__方法如下,输出类名、模块名和日志级别:

    def __repr__(self):
        level = getLevelName(self.getEffectiveLevel())
        return '<%s %s (%s)>' % (self.__class__.__name__, self.name, level)

再来看看getLogger源代码:

root = RootLogger(WARNING)
Logger.root = root
Logger.manager = Manager(Logger.root)
def getLogger(name=None):
    """
    Return a logger with the specified name, creating it if necessary.

    If no name is specified, return the root logger.
    """
    if name:
        return Logger.manager.getLogger(name)
    else:
        return root

也就是说,有参数会生成 一个相应的Logger,没有就用默认的RootLogger代替。

上面说到如果没有传名字name,又在多个文件中引用了LoggerTest.get_logger这个方法的话,输出的日志会有些问题,重新运行logging_test.py,结果如下:

 可以看到,每条日志输出了两次,所以需要在多个py文件在记录日志时,一定记得要传个名字(一般都用模块的名称)来获取logger。不然两个py文件的logger名字都叫root,那么在执行的时候会引起混乱。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值