在python中创建分层记录器

2024-10-06 10:21:21 发布

您现在位置:Python中文网/ 问答频道 /正文

Python日志模块允许用户以分层方式创建记录器。虽然在高层次上理解它,但是当我的代码分布在多个类中,并且实际的函数流将创建一个复杂的网格时,我很难实现这样的层次结构。。在

我可以用下面的代码做一个简单的层次结构:

import logging 

logFormatter = logging.Formatter("%(asctime)s [%(levelname)-5.5s] %(childname)s  %(message)s") 

rootLogger = logging.getLogger() 
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
rootLogger.addHandler(consoleHandler)  
rootLogger.setLevel(logging.INFO) 
rootLogger.info("Hi..",extra={'childname':' '})
cL1= rootLogger.getChild("Child1") 
cL1.info("Hello..",extra={'childname': cL1.name})
cL2 = cL1.getChild('Child2') 
cL2.info("Hi .. hello..",extra={'childname':cL2.name})

上述代码块的输出将是

^{pr2}$

因此,我有了额外的参数,我可以在日志中转储整个层次结构。在

现在,当代码在多个类、多个文件中拆分时,如何实现这一点呢?在

moduleA.py

class A:
    def __init__(self,name):
        self.name=name
    def doSomethingForA_1(self,**kwargs):
        self.logger(msg="Yes i did A_1",level=logging.INFO)
    def doSomethingForA_2(self,**kwargs):
        self.logger(msg="Yes i did A_2",level=logging.INFO)
    def logger(msg,level):
        '''How do i get the parent logger to create the child logger here?'''
        logger=parentLogger.getLogger(self.name)
        logger.log(msg,level,extra={'childname':self.name})

moduleAggregationType1.py

class AggregatorType1:
    def __init__(self,name):
        self.name=name
        self.objs = []
    def doAggregationType1(self,**kwargs):
        self.logger(msg="Starting aggregation Operation-1",level=logging.INFO)
        for obj in self.objs:
            obj.doSomethingForA_1()
    def logger(msg,level):
        '''How do i get the parent logger to create the child logger here?'''
        logger=parentLogger.getLogger(self.name)
        logger.log(msg,level,extra={'childname':self.name})

moduleAggregationType2.py
class AggregatorType2:
    def __init__(self,name):
        self.name=name
        self.objs = []
    def doAggregationType2(self,**kwargs):
        self.logger(msg="Starting aggregation Operation-2",level=logging.INFO)
        for obj in self.objs:
            obj.doSomethingForA_2()
    def logger(msg,level):
        '''How do i get the parent logger to create the child logger here?'''
        logger=parentLogger.getLogger(self.name)
        logger.log(msg,level,extra={'childname':self.name})

对于这些模块,假设我通过导入它们来编写脚本。在

agg_1 = AggregatorType1(name='agg_1')

agg_1.objs = [A(name='aType1_1'),A(name='aType1_2'),A(name='aType1_3')]

agg_2 = AggregatorType1(name='agg_1')

agg_2.objs = [A(name='aType2_1'),A(name='aType2_2'),A(name='aType2_3')]

在这种情况下,我的日志应该是:

2017-08-23 22:52:47,999 [INFO ] agg_1 Starting aggregation Operation-1
2017-08-23 22:52:47,999 [INFO ] agg_1.aType1_1 Yes i did A_1
2017-08-23 22:52:47,999 [INFO ] agg_1.aType1_2 Yes i did A_1
2017-08-23 22:52:47,999 [INFO ] agg_1.aType1_3 Yes i did A_1
2017-08-23 22:52:47,999 [INFO ] agg_2 Starting aggregation Operation-2
2017-08-23 22:52:47,999 [INFO ] agg_2.aType2_1 Yes i did A_2
2017-08-23 22:52:47,999 [INFO ] agg_2.aType2_2 Yes i did A_2
2017-08-23 22:52:47,999 [INFO ] agg_2.aType2_3 Yes i did A_2

因此,在执行每个方法时,我应该确定我的日志应该传播到的父记录器是什么。。在

现在我们可以为所有可调用的方法创建一个decorator,我们可以确定其中的父logger,并创建一个子logger并在decorator的末尾删除它。但问题仍然存在。。在

如何在运行时在每个方法级别确定父记录器?在


Tags: thenameselfinfologgingdefmsglogger
1条回答
网友
1楼 · 发布于 2024-10-06 10:21:21

简单的回答你不能。没有所谓的“家长日志”。python日志系统承诺的是,您可以在解释器进程的任何地方通过名称引用同一个记录器。在

所以你的选择是(在我看来):

1)要么静态声明在构造变量时要记录的位置(这很难看而且容易出错)

2)使用内置的%(module)s%(funcName)s修饰符。为此,您必须停止使用您自己的logger方法,因为它将屏蔽您所在方法的实际名称

3)使用traceback模块在运行时获取堆栈跟踪

我修改了一点代码以反映所有这些更改(并在途中删除了可选参数)

class A():
    def __init__(self, name):
        logger = logging.getLogger(name)
        self.log = logger.log
    def doSomethingForA_1(self,**kwargs):
        self.log(msg="Yes i did A_1",level=logging.INFO)
    def doSomethingForA_2(self,**kwargs):
        stack = traceback.extract_stack(limit=2)
        self.log(msg='Caller=%s:%d>%s>'%(stack[0][0:3]), level=logging.INFO)

主要内容:

^{pr2}$

这将提供以下输出:

[INFO] root <main.<module>>  Hi..
[INFO] agg_1 <moduleAggregationType1.doAggregationType1>  Starting aggregation Operation-1
[INFO] agg_1.aType1_1 <moduleA.doSomethingForA_1>  Yes i did A_1
[INFO] agg_1.aType1_2 <moduleA.doSomethingForA_1>  Yes i did A_1
[INFO] agg_1.aType1_3 <moduleA.doSomethingForA_1>  Yes i did A_1
[INFO] agg_2 <moduleAggregationType2.logger>  Starting aggregation Operation-2
[INFO] agg_2.aType2_1 <moduleA.doSomethingForA_2>  Caller=<moduleAggregationType2.py:11.doAggregationType2>
[INFO] agg_2.aType2_2 <moduleA.doSomethingForA_2>  Caller=<moduleAggregationType2.py:11.doAggregationType2>

相关问题 更多 >