Show log context level by indentation or prefix length
My idea is to make a context logging scheme as showed on the example below:
[ 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]
At this point, I'm using Python's logging module with custom, hand-written prefixes when logging, for example:
(...)
log.debug('')
log.debug('Parsing dialogs files')
for dlg in defDlgList:
log.debug('... [{0}]'.format(dlg))
(...)
It's working quite ok, but there are some subtle problems, for example: when logging from inside functions - they may be called from various scopes and prefix length may vary for each call.
I'm looking for an elegant and invisible way to establish a length of a '...' prefix automatically for each log. I'd rather avoid passing prefix length as a parameter to each function or setting the length using explicit calls, for example:
(...)
logWrapper.debug('')
logWrapper.debug('Parsing dialogs files')
for dlg in defDlgList:
logWrapper.nextLogLevelBegin()
logWrapper.debug('[{0}]'.format(dlg))
logWrapper.nextLogLevelEnd()
(...)
Is there a way to get the current indentation level from Python's parser or construct a scope sensitive wrapper class for logging?
Perhaps you can use inspect.getouterframes to find the indentation level:
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()
yields
DEBUG:__main__:.... [Hi Mom]
DEBUG:__main__:........ [Now we're cookin]
Searching through the docs, I don't really see a way to get current indentation level. The best you can do, is get the current function nesting level, like this:
len(traceback.extract_stack());
Example:
import traceback;
def test():
print len(traceback.extract_stack());
print len(traceback.extract_stack()); # prints 1
test(); # prints 2
Combining the previous answers with How do I add custom field to Python log format string? can achieve the same result without needing to provide a custom debug() method (since the same would need to be done for each level info(), error(), etc).
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')
精彩评论