Some people like to sprinkle stack trace information in their code, and it is always helpful to get a visual clue to the call stack depth. inspect.stack() contains the entire call stack.
To make this information available conditionally, on a per-subsystem basis, the logging module is helpful. Here is one way to combine the two ideas.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import logging, inspect
class IndentFormatter(logging.Formatter):
def __init__( self, fmt=None, datefmt=None ):
logging.Formatter.__init__(self, fmt, datefmt)
self.baseline = len(inspect.stack())
def format( self, rec ):
stack = inspect.stack()
rec.indent = ' '*(len(stack)-self.baseline)
rec.function = stack[8][3]
out = logging.Formatter.format(self, rec)
del rec.indent; del rec.function
return out
# USAGE:
formatter = IndentFormatter("[%(levelname)s]%(indent)s%(function)s:%(message)s")
logger = logging.getLogger('logger')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
TRON = logging.DEBUG + 1
logging.addLevelName(TRON, "TRON")
logger.setLevel(TRON)
logger.log(TRON, 'I am a logger')
def f3():
logger.log(TRON, 'I am f3')
def f2():
logger.log(TRON, 'I am f2')
f3()
def f1():
logger.log(TRON, 'I am f1')
f2()
def go():
logger.log(TRON, 'I am go.')
f1()
f2()
f3()
f1()
go()
|
We try to get a rough idea of the indentation level in the constructor.
In format(), we grab whatever info we want from the stack and add that to the LogRecord. The format string may refer to any attributes of the record. Here, a ? is printed for global functions.
Output: <pre> [TRON] ?:I am a logger [TRON] f1:I am f1 [TRON] f2:I am f2 [TRON] f3:I am f3 [TRON] go:I am go. [TRON] f1:I am f1 [TRON] f2:I am f2 [TRON] f3:I am f3 [TRON] f2:I am f2 [TRON] f3:I am f3 [TRON] f3:I am f3 </pre>
[See also: 'Automatic indentation of output based on frame stack']