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})上述代码块的输出将为
In [8]: rootLogger.info("Hi..",extra={'childname':' '})
2017-08-23 22:52:47,703 [INFO ] Hi..
In [10]: cL1.info("Hello..",extra={'childname': cL1.name})
2017-08-23 22:52:47,999 [INFO ] Child1 Hello..
In [12]: cL2.info("Hi .. hello..",extra={'childname':cL2.name})
2017-08-23 22:52:48,296 [INFO ] Child1.Child2 Hi .. hello..因此,有了这个额外的参数,我就能够在日志中转储整个层次结构。
现在,当代码跨多个类、跨多个文件拆分时,如何实现这一点?
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因此,在执行每个方法时,我应该确定我的日志应该传播到的父记录器是什么。
现在我们可以为所有可调用的方法创建一个装饰器,我们可以在其中确定父记录器,并创建子记录器并在装饰器的末尾删除它。但问题仍然存在..
如何在每个方法级别确定运行时的父记录器?
发布于 2017-08-24 05:24:32
简单的答案是你不能。没有“家长记录器”这回事。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)在main中:
logFormatter = logging.Formatter("[%(levelname)s] %(name)s <%(module)s.%(funcName)s> %(message)s")
agg_1 = AggregatorType1(name='agg_1')
agg_2 = AggregatorType2(name='agg_2')
agg_1.objs = [A(name='agg_1.aType1_1'),A(name='agg_1.aType1_2'),A(name='agg_1.aType1_3')]
agg_2.objs = [A(name='agg_2.aType2_1'),A(name='agg_2.aType2_2')]
agg_1.doAggregationType1()
agg_2.doAggregationType2()这将提供以下输出:
[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>https://stackoverflow.com/questions/45846387
复制相似问题