Package xmpp :: Module debug

[hide private]
[frames] | no frames]

# Source Code for Module xmpp.debug

      1  ##   debug.py
      2  ##
      3  ##   Copyright (C) 2003 Jacob Lundqvist
      4  ##
      5  ##   This program is free software; you can redistribute it and/or modify
      6  ##   it under the terms of the GNU Lesser General Public License as published
      7  ##   by the Free Software Foundation; either version 2, or (at your option)
      8  ##   any later version.
      9  ##
     10  ##   This program is distributed in the hope that it will be useful,
     11  ##   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  ##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  ##   GNU Lesser General Public License for more details.
     14
     15  _version_ = '1.4.0'
     16
     17  """\
     18
     19  Generic debug class
     20
     21  Other modules can always define extra debug flags for local usage, as long as
     22  they make sure they append them to debug_flags
     23
     24  Also its always a good thing to prefix local flags with something, to reduce risk
     25  of coliding flags. Nothing breaks if two flags would be identical, but it might
     26  activate unintended debugging.
     27
     28  flags can be numeric, but that makes analysing harder, on creation its
     29  not obvious what is activated, and when flag_show is given, output isnt
     30  really meaningfull.
     31
     32  This Debug class can either be initialized and used on app level, or used independantly
     33  by the individual classes.
     34
     35  For samples of usage, see samples subdir in distro source, and selftest
     36  in this code
     37
     38  """
     39
     40
     41
     42  import sys
     43  import traceback
     44  import time
     45  import os
     46
     47  import types
     48
     49  if os.environ.has_key('TERM'):
     50      colors_enabled=True
     51  else:
     52      colors_enabled=False
     53
     54  color_none         = chr(27) + "[0m"
     55  color_black        = chr(27) + "[30m"
     56  color_red          = chr(27) + "[31m"
     57  color_green        = chr(27) + "[32m"
     58  color_brown        = chr(27) + "[33m"
     59  color_blue         = chr(27) + "[34m"
     60  color_magenta      = chr(27) + "[35m"
     61  color_cyan         = chr(27) + "[36m"
     62  color_light_gray   = chr(27) + "[37m"
     63  color_dark_gray    = chr(27) + "[30;1m"
     64  color_bright_red   = chr(27) + "[31;1m"
     65  color_bright_green = chr(27) + "[32;1m"
     66  color_yellow       = chr(27) + "[33;1m"
     67  color_bright_blue  = chr(27) + "[34;1m"
     68  color_purple       = chr(27) + "[35;1m"
     69  color_bright_cyan  = chr(27) + "[36;1m"
     70  color_white        = chr(27) + "[37;1m"
     71
     72
     73  """
     74  Define your flags in yor modules like this:
     75
     76  from debug import *
     77
     78  DBG_INIT = 'init'                ; debug_flags.append( DBG_INIT )
     79  DBG_CONNECTION = 'connection'    ; debug_flags.append( DBG_CONNECTION )
     80
     81   The reason for having a double statement wis so we can validate params
     82   and catch all undefined debug flags
     83
     84   This gives us control over all used flags, and makes it easier to allow
     85   global debugging in your code, just do something like
     86
     87   foo = Debug( debug_flags )
     88
     89   group flags, that is a flag in it self containing multiple flags should be
     90   defined without the debug_flags.append() sequence, since the parts are already
     91   in the list, also they must of course be defined after the flags they depend on ;)
     92   example:
     93
     94  DBG_MULTI = [ DBG_INIT, DBG_CONNECTION ]
     95
     96
     97
     98    NoDebug
     99    -------
    100    To speed code up, typically for product releases or such
    101    use this class instead if you globaly want to disable debugging
    102  """
    103
    104
    105 -class NoDebug:
    106 -    def __init__( self, *args, **kwargs ):
    107          self.debug_flags = []
    108 -    def show( self,  *args, **kwargs):
    109          pass
    110 -    def Show( self,  *args, **kwargs):
    111          pass
    112 -    def is_active( self, flag ):
    113          pass
    114      colors={}
    115 -    def active_set( self, active_flags = None ):
    116          return 0
    117
    118
    119  LINE_FEED = '\n'
    120
    121
    122 -class Debug:
    123 -    def __init__( self,
    124                    #
    125                    # active_flags are those that will trigger output
    126                    #
    127                    active_flags = None,
    128                    #
    129                    # Log file should be file object or file namne
    130                    #
    131                    log_file = sys.stderr,
    132                    #
    133                    # prefix and sufix can either be set globaly or per call.
    134                    # personally I use this to color code debug statements
    135                    # with prefix = chr(27) + '[34m'
    136                    #      sufix = chr(27) + '[37;1m\n'
    137                    #
    138                    prefix = 'DEBUG: ',
    139                    sufix = '\n',
    140                    #
    141                    # If you want unix style timestamps,
    142                    #  0 disables timestamps
    143                    #  1 before prefix, good when prefix is a string
    144                    #  2 after prefix, good when prefix is a color
    145                    #
    146                    time_stamp = 0,
    147                    #
    148                    # flag_show should normaly be of, but can be turned on to get a
    149                    # good view of what flags are actually used for calls,
    150                    # if it is not None, it should be a string
    151                    # flags for current call will be displayed
    152                    # with flag_show as separator
    153                    # recomended values vould be '-' or ':', but any string goes
    154                    #
    155                    flag_show = None,
    156                    #
    157                    # If you dont want to validate flags on each call to
    158                    # show(), set this to 0
    159                    #
    160                    validate_flags = 1,
    161                    #
    162                    # If you dont want the welcome message, set to 0
    163                    # default is to show welcome if any flags are active
    164                    welcome = -1
    165                    ):
    166
    167          self.debug_flags = []
    168          if welcome == -1:
    169              if active_flags and len(active_flags):
    170                  welcome = 1
    171              else:
    172                  welcome = 0
    173
    174          self._remove_dupe_flags()
    175          if log_file:
    176              if type( log_file ) is type(''):
    177                  try:
    178                      self._fh = open(log_file,'w')
    179                  except:
    180                      print 'ERROR: can open %s for writing'
    181                      sys.exit(0)
    182              else: ## assume its a stream type object
    183                  self._fh = log_file
    184          else:
    185              self._fh = sys.stdout
    186
    187          if time_stamp not in (0,1,2):
    188              msg2 = '%s' % time_stamp
    189              raise 'Invalid time_stamp param', msg2
    190          self.prefix = prefix
    191          self.sufix = sufix
    192          self.time_stamp = time_stamp
    193          self.flag_show = None # must be initialised after possible welcome
    194          self.validate_flags = validate_flags
    195
    196          self.active_set( active_flags )
    197          if welcome:
    198              self.show('')
    199              caller = sys._getframe(1) # used to get name of caller
    200              try:
    201                  mod_name= ":%s" % caller.f_locals['__name__']
    202              except:
    203                  mod_name = ""
    204              self.show('Debug created for %s%s' % (caller.f_code.co_filename,
    205                                                     mod_name ))
    206              self.show(' flags defined: %s' % ','.join( self.active ))
    207
    208          if type(flag_show) in (type(''), type(None)):
    209              self.flag_show = flag_show
    210          else:
    211              msg2 = '%s' % type(flag_show )
    212              raise 'Invalid type for flag_show!', msg2
    213
    214
    215
    216
    217
    218 -    def show( self, msg, flag = None, prefix = None, sufix = None,
    219                lf = 0 ):
    220          """
    221          flag can be of folowing types:
    222              None - this msg will always be shown if any debugging is on
    223              flag - will be shown if flag is active
    224              (flag1,flag2,,,) - will be shown if any of the given flags
    225                                 are active
    226
    227          if prefix / sufix are not given, default ones from init will be used
    228
    229          lf = -1 means strip linefeed if pressent
    230          lf = 1 means add linefeed if not pressent
    231          """
    232
    233          if self.validate_flags:
    234              self._validate_flag( flag )
    235
    236          if not self.is_active(flag):
    237              return
    238          if prefix:
    239              pre = prefix
    240          else:
    241              pre = self.prefix
    242          if sufix:
    243              suf = sufix
    244          else:
    245              suf = self.sufix
    246
    247          if self.time_stamp == 2:
    248              output = '%s%s ' % ( pre,
    249                                   time.strftime('%b %d %H:%M:%S',
    250                                   time.localtime(time.time() )),
    251                                   )
    252          elif self.time_stamp == 1:
    253              output = '%s %s' % ( time.strftime('%b %d %H:%M:%S',
    254                                   time.localtime(time.time() )),
    255                                   pre,
    256                                   )
    257          else:
    258              output = pre
    259
    260          if self.flag_show:
    261              if flag:
    262                  output = '%s%s%s' % ( output, flag, self.flag_show )
    263              else:
    264                  # this call uses the global default,
    265                  # dont print "None", just show the separator
    266                  output = '%s %s' % ( output, self.flag_show )
    267
    268          output = '%s%s%s' % ( output, msg, suf )
    269          if lf:
    270              # strip/add lf if needed
    271              last_char = output[-1]
    272              if lf == 1 and last_char != LINE_FEED:
    273                  output = output + LINE_FEED
    274              elif lf == -1 and last_char == LINE_FEED:
    275                  output = output[:-1]
    276          try:
    277              self._fh.write( output )
    278          except:
    279              # unicode strikes again ;)
    280              s=u''
    281              for i in range(len(output)):
    282                  if ord(output[i]) < 128:
    283                      c = output[i]
    284                  else:
    285                      c = '?'
    286                  s=s+c
    287              self._fh.write( '%s%s%s' % ( pre, s, suf ))
    288          self._fh.flush()
    289
    290
    291 -    def is_active( self, flag ):
    292          'If given flag(s) should generate output.'
    293
    294          # try to abort early to quicken code
    295          if not self.active:
    296              return 0
    297          if not flag or flag in self.active:
    298              return 1
    299          else:
    300              # check for multi flag type:
    301              if type( flag ) in ( type(()), type([]) ):
    302                  for s in flag:
    303                      if s in self.active:
    304                          return 1
    305          return 0
    306
    307
    308 -    def active_set( self, active_flags = None ):
    309          "returns 1 if any flags where actually set, otherwise 0."
    310          r = 0
    311          ok_flags = []
    312          if not active_flags:
    313              #no debuging at all
    314              self.active = []
    315          elif type( active_flags ) in ( types.TupleType, types.ListType ):
    316              flags = self._as_one_list( active_flags )
    317              for t in flags:
    318                  if t not in self.debug_flags:
    319                      sys.stderr.write('Invalid debugflag given: %s\n' % t )
    320                  ok_flags.append( t )
    321
    322              self.active = ok_flags
    323              r = 1
    324          else:
    325              # assume comma string
    326              try:
    327                  flags = active_flags.split(',')
    328              except:
    329                  self.show( '***' )
    330                  self.show( '*** Invalid debug param given: %s' % active_flags )
    331                  self.show( '*** please correct your param!' )
    332                  self.show( '*** due to this, full debuging is enabled' )
    333                  self.active = self.debug_flags
    334
    335              for f in flags:
    336                  s = f.strip()
    337                  ok_flags.append( s )
    338              self.active = ok_flags
    339
    340          self._remove_dupe_flags()
    341          return r
    342
    343 -    def active_get( self ):
    344          "returns currently active flags."
    345          return self.active
    346
    347
    348 -    def _as_one_list( self, items ):
    349          """ init param might contain nested lists, typically from group flags.
    350
    351          This code organises lst and remves dupes
    352          """
    353          if type( items ) <> type( [] ) and type( items ) <> type( () ):
    354              return [ items ]
    355          r = []
    356          for l in items:
    357              if type( l ) == type([]):
    358                  lst2 = self._as_one_list( l )
    359                  for l2 in lst2:
    360                      self._append_unique_str(r, l2 )
    361              elif l == None:
    362                  continue
    363              else:
    364                  self._append_unique_str(r, l )
    365          return r
    366
    367
    368 -    def _append_unique_str( self, lst, item ):
    369          """filter out any dupes."""
    370          if type(item) <> type(''):
    371              msg2 = '%s' % item
    372              raise 'Invalid item type (should be string)',msg2
    373          if item not in lst:
    374              lst.append( item )
    375          return lst
    376
    377
    378 -    def _validate_flag( self, flags ):
    379          'verify that flag is defined.'
    380          if flags:
    381              for f in self._as_one_list( flags ):
    382                  if not f in self.debug_flags:
    383                      msg2 = '%s' % f
    384                      raise 'Invalid debugflag given', msg2
    385
    386 -    def _remove_dupe_flags( self ):
    387          """
    388          if multiple instances of Debug is used in same app,
    389          some flags might be created multiple time, filter out dupes
    390          """
    391          unique_flags = []
    392          for f in self.debug_flags:
    393              if f not in unique_flags:
    394                  unique_flags.append(f)
    395          self.debug_flags = unique_flags
    396
    397      colors={}
    398 -    def Show(self, flag, msg, prefix=''):
    399          msg=msg.replace('\r','\\r').replace('\n','\\n').replace('><','>\n  <')
    400          if not colors_enabled: pass
    401          elif self.colors.has_key(prefix): msg=self.colors[prefix]+msg+color_none
    402          else: msg=color_none+msg
    403          if not colors_enabled: prefixcolor=''
    404          elif self.colors.has_key(flag): prefixcolor=self.colors[flag]
    405          else: prefixcolor=color_none
    406
    407          if prefix=='error':
    408              _exception = sys.exc_info()
    409              if _exception[0]:
    410                  msg=msg+'\n'+''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip()
    411
    412          prefix= self.prefix+prefixcolor+(flag+' '*12)[:12]+' '+(prefix+' '*6)[:6]
    413          self.show(msg, flag, prefix)
    414
    415 -    def is_active( self, flag ):
    416          if not self.active: return 0
    417          if not flag or flag in self.active and DBG_ALWAYS not in self.active or flag not in self.active and DBG_ALWAYS in self.active : return 1
    418          return 0
    419
    420  DBG_ALWAYS='always'
    421
    422  ##Uncomment this to effectively disable all debugging and all debugging overhead.
    423  #Debug=NoDebug
    424