【问题标题】:How many times was logging.error() called?logging.error() 调用了多少次?
【发布时间】:2010-10-23 04:27:21
【问题描述】:

也许它只是不存在,因为我找不到它。但是使用python的日志包,有没有办法查询一个记录器来找出一个特定的函数被调用了多少次?例如,报告了多少错误/警告?

【问题讨论】:

    标签: python logging


    【解决方案1】:

    日志模块似乎不支持这一点。从长远来看,您最好创建一个新模块,并通过对现有日志记录模块中的项目进行子类化来添加此功能以添加您需要的功能,但您也可以使用装饰器轻松实现此行为:

    class CallCounted:
        """Decorator to determine number of calls for a method"""
    
        def __init__(self,method):
            self.method=method
            self.counter=0
    
        def __call__(self,*args,**kwargs):
            self.counter+=1
            return self.method(*args,**kwargs)
    
    
    import logging
    logging.error = CallCounted(logging.error)
    logging.error('one')
    logging.error('two')
    print(logging.error.counter)
    

    输出:

    ERROR:root:one
    ERROR:root:two
    2
    

    【讨论】:

    • 这个看不到子模块发生的错误。
    【解决方案2】:

    您还可以向记录所有调用的记录器添加一个新的处理程序:

    class MsgCounterHandler(logging.Handler):
        level2count = None
    
        def __init__(self, *args, **kwargs):
            super(MsgCounterHandler, self).__init__(*args, **kwargs)
            self.level2count = {}
    
        def emit(self, record):
            l = record.levelname
            if (l not in self.level2count):
                self.level2count[l] = 0
            self.level2count[l] += 1
    

    之后您可以使用 dict 来输出调用次数。

    【讨论】:

    • 这对我来说很理想。装饰器的答案隐藏了调用记录器的真实函数名和行号。使用自定义处理程序,它可以完美运行。
    • Arrrrg,我花了很长时间才弄清楚这个“2 级”业务到底是什么。某种“2级”日志记录? 2 是级别常量之一(例如 logging.ERROR),而这段代码应该只计算它吗?不……这里的“2”是“To”的同音字。变量 level2count 旨在成为计数的字典,按级别索引。因此它将级别 映射到 计数。 FWIW,日志记录源代码具有类似的列表_levelToName,其中拼写了“To”。所以......这个答案有一个不错的解决方案,变量名的选择很差。
    • 另外,在示例代码中,level2count 被声明了两次:一次作为类变量(以后不使用),然后作为实例变量。
    【解决方案3】:

    有一个 warnings 模块——在一定程度上——做了一些。

    您可能希望将此计数功能添加到自定义的Handler。问题是有一百万个处理程序,您可能希望将其添加到多个类型中。

    您可能希望将其添加到Filter,因为它独立于正在使用的处理程序。

    【讨论】:

      【解决方案4】:

      基于Rolf's answerhow to write a dictionary to a file,这里是另一种将计数存储在json 文件中的解决方案。如果 json 文件存在且 continue_counts=True,它会恢复初始化计数。

      import json
      import logging
      import logging.handlers
      import os
      
      
      class MsgCounterHandler(logging.Handler):
          """
          A handler class which counts the logging records by level and periodically writes the counts to a json file.
          """
      
          level2count_dict = None
      
          def __init__(self, filename, continue_counts=True, *args, **kwargs):
              """
              Initialize the handler.
      
              PARAMETER
              ---------
              continue_counts: bool, optional
                  defines if the counts should be loaded and restored if the json file exists already.
              """
              super(MsgCounterHandler, self).__init__(*args, **kwargs)
      
              filename = os.fspath(filename)
              self.baseFilename = os.path.abspath(filename)
      
              self.continue_counts = continue_counts
      
              # if another instance of this class is created, get the actual counts
              if self.level2count_dict is None:
                  self.level2count_dict = self.load_counts_from_file()
      
          def emit(self, record):
              """
              Counts a record.
              In case, create add the level to the dict.
              If the time has come, update the json file.
              """
              level = record.levelname
              if level not in self.level2count_dict:
                  self.level2count_dict[level] = 0
              self.level2count_dict[level] += 1
      
              self.flush()
      
          def flush(self):
              """
              Flushes the dictionary.
              """
              self.acquire()
              try:
                  json.dump(self.level2count_dict, open(self.baseFilename, 'w'))
              finally:
                  self.release()
      
          def load_counts_from_file(self):
              """
              Load the dictionary from a json file or create an empty dictionary
              """
              if os.path.exists(self.baseFilename) and self.continue_counts:
                  try:
                      level2count_dict = json.load(open(self.baseFilename))
                  except Exception as a:
                      logging.warning(f'Failed to load counts with: {a}')
                      level2count_dict = {}
              else:
                  level2count_dict = {}
              return level2count_dict
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多