Module Gnumed.pycommon.gmLog2
GNUmed logging framework setup.
All error logging, user notification and otherwise unhandled exception handling should go through classes or functions of this module.
Theory of operation:
This module tailors the standard logging framework to the needs of GNUmed.
By importing gmLog2 into your code you'll get the root logger send to a unicode file with messages in a format useful for debugging. The filename is either taken from the command line (–log-file=…) or derived from the name of the main application.
The log file will be found in one of the following standard locations:
1) given on the command line as "–log-file=LOGFILE"
2) ~/.
where
If you want to specify just a directory for the log file you must end the –log-file definition with a slash.
By importing "logging" and getting a logger your modules never need to worry about the real message destination or whether at any given time there's a valid logger available.
Your MAIN module simply imports gmLog2 and all other modules will merrily and automagically start logging away.
Ad hoc call stack logging recipe:
call_stack = inspect.stack()
call_stack.reverse()
for idx in range(1, len(call_stack)):
caller = call_stack[idx]
_log.debug('%s[%s] @ [%s] in [%s]', ' '* idx, caller[3], caller[2], caller[1])
del call_stack
Functions
def add_word2hide(word: str)
-
Expand source code
def add_word2hide(word:str): """Add a string to the list of strings to be scrubbed from logging output. Useful for hiding credentials etc. """ if word is None: return if word.strip() == '': return if word not in __words2hide: __words2hide.append(str(word))
Add a string to the list of strings to be scrubbed from logging output.
Useful for hiding credentials etc.
def flush()
-
Expand source code
def flush(): """Log a <synced> line and flush handlers.""" logger = logging.getLogger('gm.logging') logger.critical('-------- synced log file -------------------------------') root_logger = logging.getLogger() for handler in root_logger.handlers: handler.flush()
Log a
line and flush handlers. def log_instance_state(instance)
-
Expand source code
def log_instance_state(instance): """Log the state of a class instance.""" logger = logging.getLogger('gm.logging') logger.debug('state of %s', instance) for attr in [ a for a in dir(instance) if not a.startswith('__') ]: try: val = getattr(instance, attr) except AttributeError: val = '<cannot access>' logger.debug(' %s: %s', attr, val)
Log the state of a class instance.
def log_multiline(level: int = 10,
message: str = None,
line_prefix: str = None,
text: str | list[str] = None)-
Expand source code
def log_multiline(level:int=logging.DEBUG, message:str=None, line_prefix:str=None, text:str|list[str]=None): """Log multi-line text in a standard format. Args: level: a log level message: an arbitrary message to add in line_prefix: a string to prefix lines with text: the multi-line text to log """ if not text: return if line_prefix: line_template = '%s: %%s' % line_prefix else: line_template = ' > %s' lines2log = [] if message: lines2log.append(message) if isinstance(text, list): lines2log.extend([ line_template % line for line in text ]) else: lines2log.extend([ line_template % line for line in text.split('\n') ]) logger = logging.getLogger('gm.logging') logger.log(level, '\n'.join(lines2log))
Log multi-line text in a standard format.
Args
level
- a log level
message
- an arbitrary message to add in
line_prefix
- a string to prefix lines with
text
- the multi-line text to log
def log_stack_trace(message: str = None, t=None, v=None, tb=None)
-
Expand source code
def log_stack_trace(message:str=None, t=None, v=None, tb=None): """Log exception details and stack trace. (t,v,tb) are what sys.exc_info() returns. If any of (t,v,tb) is None it is attempted to be retrieved from sys.exc_info(). Args: message: arbitrary message to add in t: an exception type v: an exception value tb: a traceback object """ logger = logging.getLogger('gm.logging') if t is None: t = sys.exc_info()[0] if v is None: v = sys.exc_info()[1] if tb is None: tb = sys.exc_info()[2] if tb is None: logger.debug('sys.exc_info() did not return a traceback object, trying sys.last_traceback') try: tb = sys.last_traceback except AttributeError: logger.debug('no stack to trace (no exception information available)') return # log exception details logger.debug('exception: %s', v) logger.debug('type: %s', t) logger.debug('list of attributes:') for attr in [ a for a in dir(v) if not a.startswith('__') ]: try: val = getattr(v, attr) except AttributeError: val = '<cannot access>' logger.debug(' %s: %s', attr, val) # make sure we don't leave behind a binding # to the traceback as warned against in # sys.exc_info() documentation try: # recurse back to root caller while 1: if not tb.tb_next: break tb = tb.tb_next # put the frames on a stack stack_of_frames = [] frame = tb.tb_frame while frame: stack_of_frames.append(frame) frame = frame.f_back finally: del tb stack_of_frames.reverse() if message is not None: logger.debug(message) logger.debug('stack trace follows:') logger.debug('(locals by frame, outmost frame first)') for frame in stack_of_frames: logger.debug ( '--- frame [%s]: #%s, %s -------------------', frame.f_code.co_name, frame.f_lineno, frame.f_code.co_filename ) for varname, value in frame.f_locals.items(): if varname == '__doc__': continue logger.debug('%20s = %s', varname, value)
Log exception details and stack trace.
(t,v,tb) are what sys.exc_info() returns.
If any of (t,v,tb) is None it is attempted to be retrieved from sys.exc_info().
Args
message
- arbitrary message to add in
t
- an exception type
v
- an exception value
tb
- a traceback object
def log_step(level: int = 10, message: str = None, restart: bool = False)
-
Expand source code
def log_step(level:int=logging.DEBUG, message:str=None, restart:bool=False): if restart: global __current_log_step __current_log_step = 1 logger = logging.getLogger('gm.logging') if message: logger.log(level, '%s - %s', __current_log_step, message) else: logger.log(level, '%s', __current_log_step) __current_log_step += 1
def print_logfile_name()
-
Expand source code
def print_logfile_name(): global _logfile_name_printed if _logfile_name_printed: return print('Log file:', _logfile_name) _logfile_name_printed = True