Hi Peter and Jean-Michel,
thanks for all your hints and pieces of code.

It took me a while to play around with what I got from you (and some study of Vinay's module documentation.

Now I have come up with a more complete solution I'm quite satisfied with. And I would be very glad to receive your comments on my code indicating what I could do better, given that I'm still at the very beginning with python.


Cheers + TIA

Hellmut


Here is my module and a corresponding test program:

l...@sylvester hw_logg $ cat loc_logg.py #!/bin/env python # -*- coding: utf-8 -*- """Hw's local logging module

To be done:
  Factorize 'trace' decorator to own module
    (to permit dependency on debug level) ???
"""

import sys # Basic system functions

import logging # Logging base
import logging.handlers

import inspect # monkey patch caller filename

# --- color change strings for terminal output ---
#
pc_yell = '\033[01;93m'
pc_purp = '\033[01;33m'
pc_gren = '\033[01;92m'
pc_blue = '\033[01;94m'
#
pc_bold = '\033[01;1m'
pc_norm = '\033[0m'
#
pc_reed = '\033[01;91m'
pc_cyan = '\033[01;96m'

level_color = {
  'fatal': pc_yell,
  'error': pc_yell,
  'warning': pc_purp,
  'info': pc_gren,
  'debug': pc_blue,
  'bold': pc_bold,
  'normal': pc_norm
  }

# --- define string building help function ---
#
def argskw_2_string(*args, **kwargs):
  """Generate String from *args and **kwargs

  Return string with
    *args list (comma separated) in first line
    **kwargs key=val list (comma separated) in second line
  """
  _str_lines = []

  if args:
    _args_strings = ''
    for a in args:
      _args_strings += str(a) + ', '
    _str_lines.append(_args_strings)

  if kwargs:
    _kwargs_strings = ''
    for k in kwargs:
      _kwargs_strings += str(k)+' = '+str(kwargs[k]) + ', '
    _str_lines.append(_kwargs_strings)
  return ''.join(_str_lines)


# --- Class for all logging functionality ---
#
class locLogg():
  _logger = None

  def __init__(self, newlogg=None):
    if not locLogg._logger:
      locLogg._logger = newlogg

  def init_logging(self,
    loclogg_output='line', # stream or/and file
    loclogg_fname='loggfile.txt',
    loclogg_dblevel='DEBUG'
    ):
    """Initiate logging with locLogg._logger

    Defines the logging handler to be used
    and initiates it.

    Possible values for loclogg_output:
      line ==> output to console
      file ==> log_file must be given
      both ==> log_file must be given
      null ==> no logging (NullHandler)
    """
    locLogg._logger.handlers=[]
    if loclogg_output in ('null'):
      class NullHandler(logging.Handler):
        def emit(self, record):
          pass
      locLogg._logger.addHandler(NullHandler())
    if loclogg_output in ('line', 'both'):
      locLogg._logger.addHandler(logging.StreamHandler())
    if loclogg_output in ('file', 'both'):
      locLogg._logger.addHandler(
          logging.handlers.RotatingFileHandler(loclogg_fname,
               maxBytes=200000, backupCount=5)
          )
    for _loc_logger in locLogg._logger.handlers:
      _loc_logger.setFormatter(logging.Formatter(
          '%(asctime)s ' + \
          '%(custom_filename)s <%(custom_lineno)d>:' + \
          '%(levelname)s %(message)s'))
    # Can this be done better ?
    _loc_levels = {'NOTSET': 0, 'DEBUG': 10,
        'INFO': 20, 'WARNING': 30, 'ERROR': 40, 'CRITICAL': 50}
    locLogg._logger.setLevel(_loc_levels[loclogg_dblevel])

  def info_log(self, msg, *args, **kwargs):
    previousFrame = inspect.currentframe().f_back
    locLogg._logger.info(str(level_color['info'])+msg+pc_norm + \
      ' ' + argskw_2_string(*args, **kwargs),
      extra={'custom_lineno': previousFrame.f_lineno,
        'custom_filename': previousFrame.f_code.co_filename })

  def debug_log(self, msg, *args, **kwargs):
    previousFrame = inspect.currentframe().f_back
    locLogg._logger.debug(str(level_color['debug'])+msg+pc_norm + \
      ' ' + argskw_2_string(*args, **kwargs),
      extra={'custom_lineno':previousFrame.f_lineno,
        'custom_filename': previousFrame.f_code.co_filename })

  def warn_log(self, msg, *args, **kwargs):
    previousFrame = inspect.currentframe().f_back
    locLogg._logger.debug(str(level_color['warning'])+msg+pc_norm + \
      ' ' + argskw_2_string(*args, **kwargs),
      extra={'custom_lineno':previousFrame.f_lineno,
        'custom_filename': previousFrame.f_code.co_filename })

  def error_log(self, msg, *args, **kwargs):
    previousFrame = inspect.currentframe().f_back
    locLogg._logger.error(str(level_color['error'])+msg+pc_norm + \
      ' ' + argskw_2_string(*args, **kwargs),
      extra={'custom_lineno':previousFrame.f_lineno,
        'custom_filename': previousFrame.f_code.co_filename })

  def fatal_log(self, msg, *args, **kwargs):
    previousFrame = inspect.currentframe().f_back
    locLogg._logger.fatal(str(level_color['fatal'])+msg+pc_norm + \
      ' ' + argskw_2_string(*args, **kwargs),
      extra={'custom_lineno':previousFrame.f_lineno,
        'custom_filename': previousFrame.f_code.co_filename })

# --- Permit definition of a tracing decorator ---
from decorator import decorator

@decorator
def trace(f, *args, **kw):
  print "@trace: calling %s with args %s, %s" % (f.func_name, args, kw)
  return f(*args, **kw)
# cf. doc of Michele Simoniato's decorator module


if __name__ == '__main__':

  _logger = logging.getLogger('jmp_logg__main__')
  foo = locLogg(_logger)
  foo.init_logging()

  foo.info_log('a foo info')
  foo.info_log('another bar info', 1,2,3, a=11, b=22, c=44)
  foo.debug_log('a debug bar info', 'a', '1aA', qwe=2, asd=99)
  foo.warn_log('a test info', 'ggg', '2U2', yxcv=2, asdf=99)

  try:
    b = 123
    c = 0
    a = b / c
  except:
    foo.fatal_log('Division by zero', b=123, c=0)

l...@sylvester hw_logg $ cat test_loclogg.py
#!/bin/env python
# -*- coding: utf-8 -*-

import logging
_logger = logging.getLogger()

import sys
pyDevelDir = '/home/leo/leo/brbeit/py-devel/Modules'
sys.path.append(pyDevelDir)

from hw_logg.loc_logg import locLogg
foo = locLogg(_logger)
foo.init_logging(
    loclogg_output='both',
    loclogg_dblevel='DEBUG')

import loc_module as jm

foo.info_log('First info with args in string: %d %d %d' % (1,2,3))
foo.warn_log('First warning')
foo.debug_log('First debug message TestTestTest', '----------', 4,5,6, 12*25, d=34, e='qwe')

foo.debug_log('Before calling jm.doIt()')
jm.doIt(True)

foo.info_log('Second info with kwargs separate:', a=11,b=22,c=33)

x = jm.MyClass(1, 2, 'abc')
x.mymethod()
x.mymethod(123, 234, a=1, b=2, c=3)

try:
  jm.doIt(0)
except Exception, e:
  foo.error_log(str(e), 1,5,8)
  foo.fatal_log('Fatal message')

l...@sylvester hw_logg $ cat loc_module.py
# -*- coding: utf-8 -*-

import logging
_logger = logging.getLogger('jmp_logger')

import sys
pyDevelDir = '/home/leo/leo/brbeit/py-devel/Modules'
sys.path.append(pyDevelDir)

from hw_logg.loc_logg import locLogg, trace
foo = locLogg(_logger)

foo.info_log("Start importing "+__name__)

def doIt(yn=None):
foo.debug_log("doin' stuff, yn =", str(yn)) # logLevel at calling point !
    print '=====> Output from doIt:', yn
    #do stuff...but suppose an error occurs?
    if yn:
      foo.info_log('yn: good value')
    else:
      raise TypeError, "bogus type error for testing"

class MyClass(object):
  @trace
  def __init__(self, *args, **kwargs):
    print 'MyClass.__init__'
  @trace
  def mymethod(self, *args, **kwargs):
    print 'MyClass.mymethod'

foo.info_log("End   importing "+__name__)

--
Dr. Hellmut Weber         m...@hellmutweber.de
Degenfeldstraße 2         tel   +49-89-3081172
D-80803 München-Schwabing mobil +49-172-8450321
please: No DOCs, no PPTs. why: tinyurl.com/cbgq

--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to