【问题标题】:logging remove / inspect / modify handlers configured by fileConfig()记录删除/检查/修改由 fileConfig() 配置的处理程序
【发布时间】:2010-09-02 20:05:04
【问题描述】:

如何使用 fileConfig() 函数删除/检查/修改为我的记录器配置的处理程序?

对于删除有 Logger.removeHandler(hdlr) 方法,但是如果它是从文件配置的,我如何首先获取处理程序?

【问题讨论】:

    标签: python logging


    【解决方案1】:

    logger.handlers 包含一个包含记录器所有处理程序的列表。

    【讨论】:

    • 这没有记录。使用起来安全吗?
    • @Manish:看代码,我会说它是安全的,只要你不做多线程。处理程序列表是受锁保护的共享资源,并且该列表仅包含对处理程序的引用。如果您使用多线程,请不要使用它。
    • 这仅包含标准处理程序,如果您自己编写呢?此外,将其称为列表具有误导性,我正在寻找实例列表,但没有。它只是一个类的集合。
    • 值得注意的是logger.handlers 不包括从父记录器派生的处理程序。除了RootLogger 之外,所有记录器都有其父记录器,它们有自己的handlers 列表。
    • 警告:logger.handlers 可能会被pytest 之类的包修改(至少如果logger 是根记录器,即logger = logging.getLogger())。因此,如果您想要可测试的代码(在测试中的行为与在生产中的行为相同),我宁愿避免访问本质上是全局状态的 logger.handlers。为什么 Python 开发人员决定通过全局状态实现日志记录而不是进行适当的依赖注入,这确实超出了我的理解。
    【解决方案2】:

    此代码将打印所有记录器以及每个记录器的处理程序

    for k,v in  logging.Logger.manager.loggerDict.items()  :
            print('+ [%s] {%s} ' % (str.ljust( k, 20)  , str(v.__class__)[8:-2]) ) 
            if not isinstance(v, logging.PlaceHolder):
                for h in v.handlers:
                    print('     +++',str(h.__class__)[8:-2] )
    

    这将打印出系统中的记录器和处理程序,包括它们的状态和级别。

    这将帮助您调试日志记录问题

    output:
    + [root                ] {logging.RootLogger} {DEBUG} 
    -------------------------
       -name=root
       -handlers=[<logging.FileHandler object at 0x7fc599585390>, <logging.StreamHandler object at 0x7fc599585550>]
       -filters=[]
       -propagate=True
       -level=10
       -disabled=False
       -parent=None
         +++logging.FileHandler {NOTSET}
       -stream=<_io.TextIOWrapper name='/dev/logs/myapp.log' mode='w' encoding='UTF-8'>
       -mode=w
       -filters=[]
       -encoding=None
       -baseFilename=/home/dev/logs/myapp.log
       -level=0
       -lock=<unlocked _thread.RLock object owner=0 count=0 at 0x7fc5a85a4240>
       -delay=False
       -_name=None
       -formatter=<logging.Formatter object at 0x7fc599585358>
         +++logging.StreamHandler {DEBUG}
       -lock=<unlocked _thread.RLock object owner=0 count=0 at 0x7fc5a85a4210>
       -filters=[]
       -stream=<ipykernel.iostream.OutStream object at 0x7fc5aa6abb00>
       -level=10
       -_name=None
       -formatter=<logging.Formatter object at 0x7fc5995853c8>
    + [PathFinder          ] {logging.Logger} {NOTSET} 
    -------------------------
       -name=PathFinder
       -handlers=[]
       -filters=[]
       -manager=<logging.Manager object at 0x7fc5b09757f0>
       -propagate=True
       -level=0
       -disabled=False
       -parent=<logging.RootLogger object at 0x7fc5b09757b8>
    

    【讨论】:

    • 这太棒了,完全是我在其他任何地方都找不到的东西。
    • 感谢@GregMueller,我正在开发一个 pip 安装的帮助模块,它将提供对日志堆栈的其他见解
    • @jens 是的。有一段时间没有提交了
    • 对于那些想在 github 上看到 Mickey 的调试器的人:github.com/mickeyperlstein/logging_debugger/blob/master/…
    【解决方案3】:

    另一种方法可能是使用 JSON 或 YAML 配置文件,该文件会加载到字典中,然后您可以在将其传递给 logger.config 之前对其进行查看/操作。

    import yaml
    import logging.config
    
    with open (LOG_CONFIG, 'rt') as f:
       config=yaml.safe_load(f)
       config['handlers']['error_file_handler']['filename']='foo'
    logging.config.dictConfig(config)
    

    【讨论】:

      【解决方案4】:

      @Mickey-Perlstein 的答案正是我想要的,但列表似乎来自比提供的代码更完整的版本。
      这段代码有点粗糙,但对我的使用和理解来说至关重要,包括根记录器

      import logging
      
      def listloggers():
          rootlogger = logging.getLogger()
          print(rootlogger)
          for h in rootlogger.handlers:
              print('     %s' % h)
      
          for nm, lgr in logging.Logger.manager.loggerDict.items():
              print('+ [%-20s] %s ' % (nm, lgr))
              if not isinstance(lgr, logging.PlaceHolder):
                  for h in lgr.handlers:
                      print('     %s' % h)
      

      输出:

      <RootLogger root (DEBUG)>
           <TimedRotatingFileHandler /path/to/myapp.log (DEBUG)>
           <StreamHandler <stdout> (DEBUG)>
      + [concurrent.futures  ] <Logger concurrent.futures (DEBUG)> 
      + [concurrent          ] <logging.PlaceHolder object at 0x7f72f624eba8> 
      + [asyncio             ] <Logger asyncio (DEBUG)> 
      + [myapp               ] <Logger myapp (DEBUG)> 
      + [flask.app           ] <Logger flask.app (DEBUG)> 
      + [flask               ] <Logger flask (DEBUG)> 
      + [werkzeug            ] <Logger werkzeug (ERROR)> 
      

      【讨论】:

      • 我喜欢你简洁的细节,很棒的“叉子”
      • 这也列出了我在 RootLogger 上的配置文件中定义的 FileHandler(米奇的代码没有。)
      【解决方案5】:

      重新删除处理程序 - 如果它对我想删除我创建的所有日志的所有处理程序有帮助(我正在学习 python 日志记录)并想出了这个:

      def log_close():
          # get all loggers
          loggers = [logging.getLogger(name) if 'your_app_name' in name else None for name in logging.root.manager.loggerDict]
          # for each valid logger remove all handlers
          for log in loggers:
              if log != None:
                  while bool(len(log.handlers)):
                      for handler in log.handlers:
                          log.removeHandler(handler)
      # set up log
      log = logging.getLogger('your_app_name')
      log.setLevel('DEBUG')
      log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
      date_format = '%Y-%m-%d %H:%M:%S'
      formatter = logging.Formatter(log_format, date_format)
      log_filename = 'your_app_name.log'
      log_write_mode = 'w+'
      file_handler = logging.FileHandler(log_filename, log_write_mode)
      file_handler.setFormatter(formatter)
      log.addHandler(file_handler)
      console_handler = logging.StreamHandler()
      console_handler.setFormatter(formatter)
      log.addHandler(console_handler)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-21
        • 1970-01-01
        • 1970-01-01
        • 2020-12-02
        相关资源
        最近更新 更多