通过缩进或前缀长度显示日志上下文级别

问题描述 投票:0回答:4

我的想法是制定一个上下文日志记录方案,如下例所示:

[   DEBUG] Parsing dialogs files
[   DEBUG] ... [DialogGroup_001]
[   DEBUG] ...... Indexing dialog xml file [c:\001_dlg.xml]
[   DEBUG] ......... dialog [LobbyA]
[   DEBUG] ............ speech nodes [3]
[   DEBUG] ............... [LobbyA_01]
[   DEBUG] ............... [LobbyA_02]
[   DEBUG] ............... [LobbyA_03]
[   DEBUG] ............ sms nodes [0]
[   DEBUG] ......... dialog [LobbyB]
[   DEBUG] ............ speech nodes [3]
[   DEBUG] ............... [LobbyB_01]
[   DEBUG] ............... [LobbyB_02]
[   DEBUG] ............... [LobbyB_03]
[   DEBUG] ............ sms nodes [0]
[   DEBUG] ... [DialogGroup_002]
[   DEBUG] ...... Indexing dialog xml file [c:\002_dlg.xml]
[   DEBUG] ......... dialog [HighGroundsA]
[   DEBUG] ............ speech nodes [3]
[   DEBUG] ............... [HighGroundsA_01]
[   DEBUG] ............... [HighGroundsA_02]
[   DEBUG] ............... [HighGroundsA_03]
[   DEBUG] ............ sms nodes [0]

此时,我正在使用Python的日志记录模块,在记录时带有自定义的、手写的前缀,例如:

(...)

log.debug('')
log.debug('Parsing dialogs files')
for dlg in defDlgList:
    log.debug('... [{0}]'.format(dlg))

(...)

它工作得很好,但有一些微妙的问题,例如:从内部函数记录时 - 它们可能从不同的范围调用,并且每次调用的前缀长度可能不同。

我正在寻找一种优雅且隐形的方式来自动为每个日志建立“...”前缀的长度。我宁愿避免将前缀长度作为参数传递给每个函数或使用显式调用设置长度,例如:

(...)

logWrapper.debug('')
logWrapper.debug('Parsing dialogs files')
for dlg in defDlgList:
    logWrapper.nextLogLevelBegin()
    logWrapper.debug('[{0}]'.format(dlg))
    logWrapper.nextLogLevelEnd()

(...)

有没有办法从Python的解析器获取当前的缩进级别或构造一个范围敏感的包装类来进行日志记录?

python logging formatting
4个回答
20
投票

也许您可以使用 inspect.getouterframes 来查找缩进级别:

import inspect
import logging

logger=logging.getLogger(__name__)

def debug(msg):
    frame,filename,line_number,function_name,lines,index=inspect.getouterframes(
        inspect.currentframe())[1]
    line=lines[0]
    indentation_level=line.find(line.lstrip())
    logger.debug('{i} [{m}]'.format(
        i='.'*indentation_level,
        m=msg            
        ))

def foo():    
    debug('Hi Mom')
    for i in range(1):
        debug("Now we're cookin")

if __name__=='__main__':
    logging.basicConfig(level=logging.DEBUG)
    foo()

产量

DEBUG:__main__:.... [Hi Mom]
DEBUG:__main__:........ [Now we're cookin]

11
投票

搜索文档,我确实没有找到获取当前缩进级别的方法。你能做的最好的事情就是获取当前的函数嵌套级别,如下所示:

len(traceback.extract_stack());

示例:

import traceback;

def test():
    print len(traceback.extract_stack()); 

print len(traceback.extract_stack()); # prints 1
test(); # prints 2

11
投票

将前面的答案与如何将自定义字段添加到Python日志格式字符串?相结合可以实现相同的结果,而无需提供自定义的 debug() 方法(因为每个级别的 info() 都需要执行相同的操作) ,错误()等)。

import logging
import traceback
class CustomAdapter(logging.LoggerAdapter):
    @staticmethod
    def indent():
        indentation_level = len(traceback.extract_stack())
        return indentation_level-4  # Remove logging infrastructure frames

    def process(self, msg, kwargs):
        return '{i}{m}'.format(i='\t'*self.indent(), m=msg), kwargs

logger = CustomAdapter(logging.getLogger(__name__), {})
logger.debug('A debug message')
logger.error('An error message')
logger.info('An info message')

0
投票

我为此创建了一个 pypi 包。
支持

  • 通过额外参数向每个日志添加手动缩进。 自动
  • 基于父子记录器层次结构的缩进。
  • 基于装饰器的缩进。

通过 pip 安装:

pip install indented_logger

用途:

from indented_logger import setup_logging
import logging

# Configure the logger
setup_logging(level=logging.INFO, include_func=True)

# Get the logger
logger = logging.getLogger(__name__)

# Basic logging
logger.info('Starting process A')
# Manual indentation
logger.info('Details of process A', extra={'lvl': 1})
logger.info('Deeper Details of process A', extra={'lvl': 2})
logger.info('Process complete')

输出:

2024-08-15 12:34:56 - INFO     - Starting process A                          {main}
2024-08-15 12:34:56 - INFO     -     Details of process A                    {main}
2024-08-15 12:34:56 - INFO     -         Deeper Details of process A         {main}
2024-08-15 12:34:56 - INFO     - Process complete                            {main}
© www.soinside.com 2019 - 2024. All rights reserved.