Package XPyLIB :: Module xlogging
[hide private]
[frames] | no frames]

Source Code for Module XPyLIB.xlogging

   1  #!/usr/bin/env python
 
   2  # -*- coding: utf-8 -*-
 
   3  #--------------------------------------------------------------------
 
   4  # Filname: __init__.py
 
   5  # Author: Mazhugin Aleksey
 
   6  # Created: 2007/11/04
 
   7  # ID: $Id: XPyLIB.xlogging-pysrc.html 24 2008-12-01 17:51:12Z alex $
 
   8  # URL: $URL: file:///myfiles/svn_/XPyLIB/trunc/doc/html/XPyLIB.xlogging-pysrc.html $
 
   9  # Copyright: Copyright (c) 2007, Mazhugin Aleksey.
 
  10  # License: BSD
 
  11  #--------------------------------------------------------------------
 
  12  # Package initialisation
 
  13  
 
  14  """
 
  15  Some extensions for Python logging package.
 
  16  
 
  17  This module import standart Python logging namespace " from logging import * ",
 
  18  and you may use only xlogging for most usual targets.
 
  19  
 
  20  X{Logging config file format.}
 
  21  ==============================
 
  22      Logging file format like config format in python logging package, but
 
  23      have some differents.
 
  24      
 
  25      The file must contain I{main} sections called [loggers], [handlers],
 
  26      [filters] and  [formatters] which identify by name the entities of each
 
  27      type which are defined in the file. For each such entity, there is
 
  28      a separate I{entity} section which identified how that entity is configured.
 
  29      Thus, for a logger named log01 in the [loggers] section, the relevant
 
  30      configuration details are held in a section [logger_log01]. Similarly,
 
  31      a handler called hand01 in the [handlers] section will have its
 
  32      configuration held in a section called [handler_hand01], while a
 
  33      formatter called form01 in the [formatters] section will have its
 
  34      configuration specified in a section called [formatter_form01].
 
  35      The root logger configuration must be specified in a I{entity} section called
 
  36      [logger_root].
 
  37      The manager section configure loggers manager. Available only
 
  38      one option: "disable". (It as logging.disable() function). This
 
  39      section and option are optional.
 
  40      
 
  41      In I{main} sections you must use option B{keys} (it mandatory):
 
  42  
 
  43          - B{keys} - Add new object or will change configuration of existing
 
  44              object.
 
  45          
 
  46      Examples of these sections in the file are given below.::
 
  47          
 
  48          [manager]
 
  49          disable=WARNING
 
  50          
 
  51          [loggers]
 
  52          keys=root, log02, log03
 
  53          
 
  54          [handlers]
 
  55          keys=hand01, hand02, hand03, hand04
 
  56          
 
  57          [formatters]
 
  58          keys=form01,form02,form03,form04,form05,form06,form07,form08,form09
 
  59          
 
  60          [filters]
 
  61          keys=filt01, filt02, filt03
 
  62      
 
  63      The entity sections may contains B{actions} option. In this
 
  64      option may be listed action's names (it is a options's names with
 
  65      description of action). Each action entity have next format::
 
  66          
 
  67          act01=command, objecttype, arg01, arg02, ...
 
  68      
 
  69      where:
 
  70          - act01 - name of action given in actions option.
 
  71          - command - command that need to executed.
 
  72          - objecttype - object type for which command executed.
 
  73          - arg01, arg02, ... - additional arguments for command.
 
  74      
 
  75      For entity's sections B{logger_???} and B{handler_???} you may execute next
 
  76      commands: B{clear}, B{remove}, B{add}.
 
  77      For entity's sections B{formatter_???} and B{filter_???} actions will be
 
  78      I{ignored}.
 
  79      
 
  80      The I{arg**} in commands is name of objects.
 
  81      
 
  82      As I{objecttype} for sections you must use next types:
 
  83          - for B{[logger_???]} : handler, filter.
 
  84          - for B{[handler_???]} : filter, formatter.
 
  85      
 
  86      For entity section you also can specify object attribute and value to set::
 
  87          
 
  88          attributes=attr01, attr02
 
  89          attr01=attrname, attrvalue
 
  90          attr02=attrname, attrvalue
 
  91      
 
  92      Where B{attributes} is a option with attribute's options
 
  93      names I{attr01}, I{attr02}.
 
  94      Into options I{attr01}, I{attr02} you must specify attribute name
 
  95      B{attrname} and attribute value B{attrvalue}. The value willbe evaluated
 
  96      using eval() in logging namespace.
 
  97      
 
  98      The root logger I{must} specify a B{level}, list of handlers and filters.
 
  99      For [logger_???] sections have no mandatory options. By default
 
 100      level, handlers and other attributes are no changed.
 
 101      An example of a root logger section is given below.::
 
 102          
 
 103          [logger_root]
 
 104          level=NOTSET
 
 105          handlers=hand01
 
 106          filters=
 
 107          actions=act01, act02
 
 108          act01=clear, handler
 
 109          act02=remove, filter, filt99
 
 110          act03=add, handler, hand55
 
 111          disabled=0
 
 112          attributes=attr01
 
 113          attr01= name, A.B.C
 
 114      
 
 115      For loggers other than the root logger, some additional information is
 
 116      required.
 
 117      The level and handlers entries are interpreted as for the root logger,
 
 118      except that if a non-root logger's level is specified as NOTSET,
 
 119      the system consults loggers higher up the hierarchy to determine the
 
 120      effective level of the logger. The B{propagate} entry is set to B{1}
 
 121      (is default) to indicate
 
 122      that messages must propagate to handlers higher up the logger hierarchy
 
 123      from this logger, or B{0} to indicate that messages are not propagated to
 
 124      handlers up the hierarchy. The B{qualname} entry is the hierarchical channel
 
 125      name of the logger, that is to say the name used by the application to
 
 126      get the logger.
 
 127      The B{disabled} set this logger disabled (I{1}) or enabled (I{0}). By
 
 128      default disabled is I{0} for new or not changed for existing logger.
 
 129      The mandatory options is no. If B{qualname} is not specified then
 
 130      configuration name is used, for below example it is 'parser'.
 
 131      The B{filters} entry, specify filters names to use.If this entry specified
 
 132      then clear all filters then add new filters from I{filters} list.
 
 133      If I{handlers} entry specified then clear all filters then add new
 
 134      handlers from I{handlers} list.
 
 135      This is illustrated by the following example.::
 
 136          
 
 137          [logger_parser]
 
 138          level=DEBUG
 
 139          handlers=hand01
 
 140          propagate=1
 
 141          qualname=compiler.parser
 
 142          filters=
 
 143          actions=act01
 
 144          act01=clear,handler
 
 145          disabled=0
 
 146          attributes=attr01
 
 147          attr01= name, A.B.C
 
 148      
 
 149      Sections which specify handler configuration are exemplified by the following. 
 
 150      The B{class} entry indicates the handler's class (as determined by eval() in
 
 151      the logging package's namespace). The level is interpreted as for loggers,
 
 152      and NOTSET is taken to mean "log everything". 
 
 153  
 
 154      The B{formatter} entry indicates the key name of the formatter for
 
 155      this handler. If blank, a default formatter (C{logging._defaultFormatter})
 
 156      is used. If a name is specified, it must appear in the [formatters]
 
 157      section and have a corresponding section in the configuration file. 
 
 158  
 
 159      The B{args} entry, when eval() evaluated in the context of the logging
 
 160      package's namespace, is the list of arguments to the constructor
 
 161      for the handler class. Refer to the constructors for the relevant
 
 162      handlers, or to the examples below, to see how typical entries are
 
 163      constructed.
 
 164      
 
 165      The B{filters} entry, specify filters names to use.If this entry specified
 
 166      then clear all filters then add new filters from I{filters} list.
 
 167      
 
 168      The mandatory options is B{class} and B{args} and only for new handlers.::
 
 169          
 
 170          [handler_hand01]
 
 171          class=StreamHandler
 
 172          level=NOTSET
 
 173          formatter=form01
 
 174          args=(sys.stdout,)
 
 175          filters=
 
 176          actions=act01
 
 177          act01=add, filter, filt01
 
 178          attributes=attr01
 
 179          attr01= attrname, A.B.C
 
 180      
 
 181      Sections which specify filter configuration are typified by the following.
 
 182      The mandatory options is B{class} and B{args} and only for new filters.::
 
 183          
 
 184          [filter_filt01]
 
 185          class=Filter
 
 186          args=('App')
 
 187          attributes=attr01
 
 188          attr01= name, A.B.C
 
 189      
 
 190      Sections which specify formatter configuration are typified by the following.::
 
 191          
 
 192          [formatter_form01]
 
 193          format=F1 %(asctime)s %(levelname)s %(message)s
 
 194          datefmt=
 
 195          class=logging.Formatter
 
 196          args=()
 
 197          attributes=attr01
 
 198          attr01= name, A.B.C
 
 199      
 
 200      The mandatory options is B{format} and B{datefmt}.
 
 201      
 
 202      The B{format} entry is the overall format string, and the B{datefmt}
 
 203      entry is the strftime()-compatible date/time format string.
 
 204      If empty, the package substitutes ISO8601 format date/times,
 
 205      which is almost equivalent to specifying the date format string
 
 206      "The ISO8601 format also specifies milliseconds, which are appended to
 
 207      the result of using the above format string, with a comma separator.
 
 208      An example time in ISO8601 format is 2003-01-23 00:29:50,411. 
 
 209      
 
 210      The B{class} entry is optional. It indicates the name of the formatter's
 
 211      class (as a dotted module and class name.) This option is useful for
 
 212      instantiating a Formatter subclass. Subclasses of Formatter can present
 
 213      exception tracebacks in an expanded or condensed format. 
 
 214      
 
 215      
 
 216  
 
 217  
 
 218  @warning: You must accurate use remove or clear options or commands,
 
 219      becouse may be conflict with currently executed code in runtime if it
 
 220      use removed objects.
 
 221  
 
 222  @note: After importing xlogging L{XLogger} class set as default class for
 
 223  new loggers.
 
 224  
 
 225  @var TRACE: Logging level constant, used for prereliase tracing.
 
 226  @type TRACE: int
 
 227  
 
 228  @var DBGTRACE: Logging level constant, used for debug tracing.
 
 229  @type DBGTRACE: int
 
 230  
 
 231  @var _xBaseloggerClass: Base logger class (get from logging). Used as base for XLogger.
 
 232  @type _xBaseloggerClass: Logger
 
 233  """ 
 234  
 
 235  # Importing
 
 236  import logging 
 237  from logging import * 
 238  from functools import wraps 
 239  
 
 240  try: 
 241      import thread 
 242      import threading 
 243  except: 
 244      thread=None 
 245  
 
 246  # Not XPyLIB.dbg, only dbg for cross links avoid.
 
 247  import dbg ##@ 
 248  
 
 249  ##dbg.fwriteln('*** xlogging debug output ***') ##@
 
 250  
 
 251  # Constants.
 
 252  
 
 253  TRACE = 15 
 254  DBGTRACE = 5 
 255  
 
 256  # Add logging level constants.
 
 257  addLevelName(TRACE, 'TRACE') 
 258  addLevelName(DBGTRACE, 'DBGTRACE') 
 259  
 
 260  # Store base logger class.
 
 261  _xBaseloggerClass = logging.getLoggerClass() 
 262  
 
 263  # Start Implementation
 
 264  ##@dbg.fwlevel ##@
 
265 -def getLevelByName(levelname):
266 """ 267 Return level name by level value. 268 269 If no such level then raise error KeyError. 270 """ 271 ##dbg.fwriteln('getLevelByName: level %s=%d'% (levelname,logging._levelNames[levelname])) ##@ 272 return logging._levelNames[levelname]
273 274 ##@dbg.fwlevel ##@
275 -def applyConfigFile(fname, defaults=None):
276 """ 277 Read the logging configuration from a ConfigParser-format file. 278 279 This can be called several times from an application, allowing an end user 280 the ability to select from various pre-canned configurations (if the 281 developer provides a mechanism to present the choices and load the chosen 282 configuration). 283 In versions of ConfigParser which have the readfp method [typically 284 shipped in 2.x versions of Python], you can pass in a file-like object 285 rather than a filename, in which case the file-like object will be read 286 using readfp. 287 288 Algorithm: 289 ========== 290 291 1. Read [loggers], [handlers], [filters], [formatters] keys into DICT. 292 2. FOR _logger_ IN [loggers]: 293 1. IF _logger_ EXIST get it, ELSE create new 294 2. Read _fs_=[filters]. 295 3. IF _fs_ THEN: 296 1. _filters_.clear. 297 2. FOR _f_ IN _fs_: 298 1. Read filter from config. 299 2. Create new filter. 300 3. Add filter to _logger_. 301 4. FOR _f_ IN _fs_: 302 1. Read filter changes from config section. 303 2. Change filter _f_. 304 3. Read [attributes] and apply. 305 5. Read _hs_=[handlers]. 306 6. IF _hs_ THEN: 307 1. _handlers_.clear. 308 2. FOR _h_ IN _hs_: 309 1. Read handler from config. 310 2. Create new handler. 311 3. Add handler to _logger_. 312 7. FOR _h_ IN _hs_: 313 1. Read handler changes from config section. 314 2. Change handler _h_. 315 3. Read [formatter] and ADD or CHANGE. 316 4. Read [filters] and ADD or CHANGE. 317 5. Read [attributes] and apply. 318 8. Read [attributes] and apply. 319 320 Logger section example:: 321 322 [manager] 323 #disable=WARNING 324 325 [logger_parser] 326 level=DEBUG 327 handlers=hand01 328 propagate=1 329 qualname=compiler.parser 330 filters= 331 actions=act01 332 act01=clear,handler 333 disabled=0 334 attributes=attr01 335 attr01= name, A.B.C 336 """ 337 import ConfigParser 338 339 ##dbg.fwriteln('Load config parser.') ##@ 340 341 cp = ConfigParser.SafeConfigParser(defaults) 342 if hasattr(cp, 'readfp') and hasattr(fname, 'readline'): 343 cp.readfp(fname) 344 else: 345 cp.read(fname) 346 347 # Test for mandatory main sections. 348 ##dbg.fwriteln('Test for mandatory main sections.') ##@ 349 if not all( \ 350 [ cp.has_section(s) and cp.has_option(s, 'keys') \ 351 for s in ('loggers', 'handlers', 'filters', 'formatters') ] ): 352 ##dbg.fwriteln('\tFAIL Test for mandatory main sections.') ##@ 353 return # Return if not all have. 354 355 loggers=dict((n.strip(), None) for n in str(cp.get('loggers','keys')).split(',') if n.strip()) 356 handlers=dict((n.strip(), None) for n in str(cp.get('handlers','keys')).split(',') if n.strip()) 357 filters=dict((n.strip(), None) for n in str(cp.get('filters','keys')).split(',') if n.strip()) 358 formatters=dict((n.strip(), None) for n in str(cp.get('formatters','keys')).split(',') if n.strip()) 359 360 ##dbg.fwriteln('loggers=', loggers) ##@ 361 ##dbg.fwriteln('handlers=', handlers) ##@ 362 ##dbg.fwriteln('filters=', filters) ##@ 363 ##dbg.fwriteln('formatters=', formatters) ##@ 364 365 # Start critical section. 366 logging._acquireLock() 367 try: 368 369 ##dbg.fwriteln('manager configure') ##@ 370 sec='manager' 371 if cp.has_section(sec): 372 if cp.has_option(sec, 'disable'): 373 try: 374 ##dbg.fwriteln('set disable=',cp.get(sec,'disable')) ##@ 375 disable( getLevelByName(cp.get(sec,'disable')) ) 376 except: 377 ##dbg.fwriteln('\texception') ##@ 378 pass 379 380 ##dbg.fwriteln('\nSTART LOGGER LOOP\n') ##@ 381 for logger in loggers: 382 sec = 'logger_' + logger 383 ##dbg.fwriteln('Read section=', sec) ##@ 384 if cp.has_section(sec): 385 opts = _options(sec, cp) 386 ##dbg.fwriteln('opts=', opts) ##@ 387 # Get logger name, overwork about root. 388 if logger == 'root': 389 name = logger 390 else: 391 name = opts.has_key('qualname') and opts['qualname'] or logger 392 ##dbg.fwriteln('name=', name) ##@ 393 # Get logger, overwork about root logger. 394 if name == 'root': 395 loginst = root 396 else: 397 loginst = logging.getLogger(name) 398 loggers[logger] = loginst 399 # Configure logger. 400 ##dbg.fwriteln('Configure logger') ##@ 401 if opts.has_key('level'): 402 try: 403 loginst.setLevel( getLevelByName(opts['level']) ) 404 ##dbg.fwriteln('set level=', getLevelByName(opts['level'])) ##@ 405 except: 406 ##dbg.fwriteln('\texception') ##@ 407 pass 408 if opts.has_key('propagate'): 409 try: 410 loginst.propagate = int(opts['propagate']) 411 ##dbg.fwriteln('set propogate', int(opts['propagate'])) ##@ 412 except: 413 ##dbg.fwriteln('\texception') ##@ 414 pass 415 if opts.has_key('disabled'): 416 try: 417 loginst.disabled = int(opts['disabled']) 418 ##dbg.fwriteln('set disabled', int(opts['disabled'])) ##@ 419 except: 420 ##dbg.fwriteln('\texception') ##@ 421 pass 422 423 # Apply attributes. 424 ##dbg.fwriteln('Apply attributes') ##@ 425 _applyAttrs(opts, loginst) 426 427 # Apply filters. 428 ##dbg.fwriteln('Apply filters') ##@ 429 if opts.has_key('filters'): 430 # Clear filters. 431 ##dbg.fwriteln('\tClearfilters') ##@ 432 for f in loginst.filters: 433 loginst.remove(f) 434 fs=[ n.strip() for n in opts['filters'].split(',') if n.strip() ] 435 ##dbg.fwriteln('\tfilters=', fs) ##@ 436 _applyFilters(fs, loginst, cp, filters) 437 438 # Apply handlers. 439 ##dbg.fwriteln('Apply handlers') ##@ 440 if opts.has_key('handlers'): 441 # Clear filters. 442 ##dbg.fwriteln('\tClear handlers') ##@ 443 for h in loginst.handlers: 444 loginst.removeHandler(h) 445 hs=[ n.strip() for n in opts['handlers'].split(',') if n.strip() ] 446 ##dbg.fwriteln('handlers=', hs) ##@ 447 _applyHandlers(hs, loginst, cp, handlers, formatters, filters) 448 449 # Apply actions. 450 ##dbg.fwriteln('Apply actions') ##@ 451 _applyActions(opts, loginst, cp, handlers, formatters, filters) 452 453 ##end if cp.has_section(sec): 454 455 ##end for logger 456 ##dbg.fwriteln() ##@ 457 458 finally: 459 # End critical section. 460 logging._releaseLock()
461 462 ##@dbg.fwlevel ##@
463 -def _applyAttrs(opts, inst):
464 """ 465 Apply attributes from dictionary "opts" to object instance "inst". 466 467 @param opts: Dictionary with item "attributes" and items listed in 468 "attributes" which will be applied. 469 @type opts: dict 470 @param inst: Object instance. 471 """ 472 if opts.has_key('attributes'): 473 ##dbg.fwriteln('Find attributes') ##@ 474 for a in [ opts[n.strip()] for n in opts['attributes'].split(',') \ 475 if opts.has_key( n.strip() ) ]: 476 # Loop for attributes. 477 aa = [n.strip() for n in a.partition(',')] 478 ##dbg.fwriteln('apply attr "',aa[0], '" = ', aa[2]) ##@ 479 if aa[0]: 480 try: 481 ##dbg.fwriteln('\tset attr') ##@ 482 setattr(inst, aa[0], aa[2]) 483 except: 484 ##dbg.fwriteln('\t\texception') ##@ 485 pass
486 ##end for a 487 488 ##@dbg.fwlevel ##@
489 -def _options(sec, cp, raw=0):
490 """ 491 Return readed options and it's values in dictionary. 492 493 @param sec: Section name. 494 @type sec: str 495 @param cp: Config parser instance. 496 @type cp: ConfigParser 497 @param raw: Raw mode for get in ConfigParser. 498 @type raw: int = {0} 499 @return: Dictionary with options and values. 500 @rtype: dict 501 """ 502 r = {} 503 if cp.has_section(sec): 504 r = dict( (n, cp.get(sec,n,raw)) for n in cp.options(sec) ) 505 ##dbg.fwriteln('options=', r) ##@ 506 return r
507 508 ##@dbg.fwlevel ##@
509 -def _applyFilters(flts, inst, cp, filters):
510 """ 511 Aplly filters with names listed in "flts": to object "inst". 512 513 First try find named filter into "inst.filters" list (which have attribute "name"), 514 if not find then try find into "filters" dict, 515 else create new. Then apply changes 516 to filter. 517 Filter name must exist in filters list. 518 To add filter to inst used "addFilter" method. 519 To created or added filters set attribute "name" to filter name. 520 521 @param flts: List with filter's names. 522 @type flts: list 523 @param inst: Object instance to apply filters. 524 @type inst: Object instance 525 @param cp: Config parser instance. 526 @type cp: ConfigParser 527 @param filters: Permited filters name with existing or None instances. 528 @type filters: dict 529 530 Filter section example:: 531 532 [filter_filt01] 533 class=Filter 534 args=('App') 535 attributes=attr01 536 attr01= name, A.B.C 537 538 """ 539 if not flts or not hasattr(inst, 'filters') or not hasattr(inst, 'addFilter'): 540 return 541 import sys 542 ##_self_module=sys.modules[XLogger.__module__] 543 ##dbg.fwriteln('_self_module=', _self_module) ##@ 544 ##dbg.fwriteln('Filter loop') ##@ 545 for fn in flts: 546 ##dbg.fwriteln('fn=', fn) ##@ 547 if not filters.has_key(fn): 548 # Exit for if no such filter name into filters. 549 ##dbg.fwriteln('EXIT: no such name into filters') ##@ 550 break 551 if cp.has_section('filter_' + fn): 552 opts = _options('filter_' + fn, cp) 553 ##dbg.fwriteln('opts=', opts) ##@ 554 f = None # Filter 555 556 # Try find filter in instance. 557 ##dbg.fwriteln('Try find filter in instance') ##@ 558 for fi in inst.filters: 559 if hasattr(fi, 'name') and (fi.name == fn): 560 ##dbg.fwriteln('FIND filter in instance') ##@ 561 f=fi 562 break 563 if not f: 564 if filters[fn] != None: 565 ##dbg.fwriteln('find filter into filters') ##@ 566 f=filters[fn] 567 else: 568 # Create new filter. 569 ##dbg.fwriteln('Create new filter') ##@ 570 klass = logging.Filter 571 if opts.has_key('class'): 572 c = opts['class'].strip() 573 ##dbg.fwriteln('["class"]=', c) ##@ 574 if c: 575 try: 576 ##dbg.fwriteln('eval class') ##@ 577 c = eval(c, vars(sys.modules[__name__])) 578 except: 579 ##dbg.fwriteln('\texception') ##@ 580 c=None 581 if c: 582 ##dbg.fwriteln('Set new class', c) ##@ 583 klass = c 584 a = () 585 ##dbg.fwriteln('search args') ##@ 586 if opts.has_key('args'): 587 ##dbg.fwriteln('have args') ##@ 588 a = opts['args'] 589 ##dbg.fwriteln('args=', a) ##@ 590 try: 591 ##dbg.fwriteln('Try eval args') ##@ 592 a = eval(a, vars(sys.modules[__name__])) 593 except: 594 ##dbg.fwriteln('\texception') ##@ 595 a=() 596 597 ##dbg.fwriteln('CREATE filter') ##@ 598 f = klass(*a) 599 ##end if filters[fn] != None 600 try: 601 ##dbg.fwriteln('Add to instance') ##@ 602 inst.addFilter(f) 603 except: 604 pass 605 606 ##end if not f 607 if filters[fn] == None: 608 ##dbg.fwriteln('set to filters') ##@ 609 filters[fn]=f 610 611 # Set filter name. 612 ##dbg.fwriteln('Set name to filter=',fn) ##@ 613 setattr(f, 'name', fn) 614 615 ##dbg.fwriteln('Apply attrs') ##@ 616 _applyAttrs(opts, f)
617 618 ##end if cp.has_section('filter_' + fn) 619 ##dbg.fwriteln() ##@ 620 ##end for f 621 ##dbg.fwriteln('End filter loop') ##@ 622 # Ignore actions for filters 623 624 ##@dbg.fwlevel ##@
625 -def _applyFormatter(fmtr, inst, cp, formatters):
626 """ 627 Aplly formatter with name listed in "fmtr": to object "inst". 628 629 First try find named formatter into "inst.formatter" list (which have attribute "name"), 630 if not find then try find into "formatters" dict, 631 else create new. Then apply changes 632 to formatter. 633 Formatter name must exist in formatters list. 634 To add filter to inst used "setFormatter" method. 635 636 @warning: Options for formatter readed in raw mode (see ConfigParser). 637 638 @param fmtr: Formatter name. 639 @type fmtr: list 640 @param inst: Object instance to apply formatter. 641 @type inst: Object instance 642 @param cp: Config parser instance. 643 @type cp: ConfigParser 644 @param formatters: Permited formatters name with existing or None instances. 645 @type formatters: dict 646 647 Formatter section example:: 648 649 [formatter_form01] 650 format=F1 %(asctime)s %(levelname)s %(message)s 651 datefmt= 652 class=logging.Formatter 653 args=() 654 attributes=attr01 655 attr01= name, A.B.C 656 657 """ 658 if not fmtr or not hasattr(inst, 'formatter') or not hasattr(inst, 'setFormatter'): 659 return 660 import sys 661 ##_self_module=sys.modules[XLogger.__module__] 662 ##dbg.fwriteln('_self_module=', _self_module) ##@ 663 sec = 'formatter_' + fmtr 664 ##dbg.fwriteln('sec=', sec) ##@ 665 if cp.has_section(sec): 666 opts = _options(sec, cp, 1) # Raw 667 ##dbg.fwriteln('opts=', opts) ##@ 668 f = None # Formatter 669 if not formatters.has_key(fmtr): 670 # Exit if no such formatter name into formatterss. 671 ##dbg.fwriteln('EXIT such formatter is not in formatters.') ##@ 672 return 673 # Try find formatter in instance. 674 ##dbg.fwriteln('Try find in instance') ##@ 675 fi = inst.formatter 676 if hasattr(fi, 'name') and (fi.name == fmtr): 677 ##dbg.fwriteln('FIND in instance') ##@ 678 f=fi 679 if not f: 680 ##dbg.fwriteln('search in formatters') ##@ 681 if formatters[fmtr] != None: 682 ##dbg.fwriteln('FIND in formatters') ##@ 683 f=formatters[fmtr] 684 else: 685 # Create new formatter. 686 ##dbg.fwriteln('Create new') ##@ 687 klass = logging.Formatter 688 if opts.has_key('class'): 689 c = opts['class'].strip() 690 ##dbg.fwriteln('["class"]=',c) ##@ 691 if c: 692 try: 693 ##dbg.fwriteln('Eval class') ##@ 694 c = eval(c, vars(sys.modules[__name__])) 695 except: 696 ##dbg.fwriteln('\texception') ##@ 697 c=None 698 if c: 699 ##dbg.fwriteln('Set new class ', c) ##@ 700 klass = c 701 a = () 702 ##dbg.fwriteln('Search args') ##@ 703 if opts.has_key('args'): 704 a = opts['args'] 705 ##dbg.fwriteln('args=', a) ##@ 706 try: 707 ##dbg.fwriteln('eval args') ##@ 708 a = eval(a, vars(sys.modules[__name__])) 709 except: 710 ##dbg.fwriteln('\texception') ##@ 711 a=() 712 if opts.has_key('format'): 713 fs = opts['format'] 714 ##dbg.fwriteln('format=', fs) ##@ 715 else: 716 ##dbg.fwriteln('no format') ##@ 717 fs = None 718 if opts.has_key('datefmt'): 719 dfs = opts['datefmt'] 720 ##dbg.fwriteln('datefmt=', dfs) ##@ 721 else: 722 ##dbg.fwriteln('no datefmt') ##@ 723 dfs = None 724 ##dbg.fwriteln('Create new formatter.') ##@ 725 f = klass(fs, dfs, *a) 726 ##end if formatters[fmtr] != None 727 try: 728 ##dbg.fwriteln('Set instance formatter.') ##@ 729 inst.setFormatter(f) 730 except: 731 ##dbg.fwriteln('\texception') ##@ 732 pass 733 ##end if not f 734 if formatters[fmtr] == None: 735 ##dbg.fwriteln('Set formatters') ##@ 736 formatters[fmtr]=f 737 ##dbg.fwriteln('Set name to formatter=', fmtr) ##@ 738 setattr(f,'name',fmtr) 739 740 ##dbg.fwriteln('Apply attrs') ##@ 741 _applyAttrs(opts, f)
742 ##end if cp.has_section('filter_' + fn) 743 # Ignore actions for formatter 744 745 ##@dbg.fwlevel ##@
746 -def _applyHandlers(hdls, inst, cp, handlers, formatters, filters):
747 """ 748 Aplly handlerss with names listed in "hdls": to object "inst". 749 750 First try find named handler into "inst.handlers" list 751 (which have attribute "name"), if not then 752 try find in "handlers" dict, 753 else create new. Then apply changes 754 to handler. 755 Handler name must exist in handlers list. 756 To add handler to inst used "addHandler" method. 757 758 @param hdls: List with hamdler's names. 759 @type hdls: list 760 @param inst: Object instance to apply handlers. 761 @type inst: Object instance 762 @param cp: Config parser instance. 763 @type cp: ConfigParser 764 @param handlers: Permited handlers name with existing or None instances. 765 @type handlers: dict 766 @param formatters: Permited formatters. 767 @type formatters: dict 768 @param filters: Permited filters. 769 @type filters: dict 770 771 Handler section example:: 772 773 [handler_hand01] 774 class=StreamHandler 775 level=NOTSET 776 formatter=form01 777 args=(sys.stdout,) 778 filters= 779 actions=act01 780 act01=add, filter, filt01 781 attributes=attr01 782 attr01= attrname, A.B.C 783 784 """ 785 if not hdls or not hasattr(inst, 'handlers') or not hasattr(inst, 'addHandler'): 786 return 787 import sys 788 ##_self_module=sys.modules[XLogger.__module__] 789 ##dbg.fwriteln('_self_module=', _self_module) ##@ 790 ##dbg.fwriteln('HANDLERS LOOP') ##@ 791 for hn in hdls: 792 ##dbg.fwriteln('hn=', hn) ##@ 793 if cp.has_section('handler_' + hn): 794 opts = _options('handler_' + hn, cp) 795 ##dbg.fwriteln('opts=', opts) ##@ 796 h = None # Handler 797 if not handlers.has_key(hn): 798 # Exit if no such handler name into handlers. 799 ##dbg.fwriteln('EXIT such handler not find in handlers') ##@ 800 return 801 # Try find handler in instance. 802 ##dbg.fwriteln('Try find in instance') ##@ 803 for hi in inst.handlers: 804 if hasattr(hi, 'name') and (hi.name == hn): 805 ##dbg.fwriteln('FIND in instance') ##@ 806 h=hi 807 break 808 if not h: 809 # Try find handlers dict. 810 ##dbg.fwriteln('Search in handlers') ##@ 811 if handlers[hn] != None: 812 ##dbg.fwriteln('FIND in handlers') ##@ 813 h=handlers[hn] 814 else: 815 # Create new handler. 816 ##dbg.fwriteln('Create new') ##@ 817 klass = NullHandler 818 if opts.has_key('class'): 819 c = opts['class'].strip() 820 ##dbg.fwriteln('["class"]=', c) ##@ 821 if c: 822 try: 823 ##dbg.fwriteln('Eval class') ##@ 824 c = eval(c, vars(sys.modules[__name__])) 825 except Exception, e: 826 ##dbg.fwriteln('\texception=', e) ##@ 827 c=None 828 if c: 829 ##dbg.fwriteln('Set new class') ##@ 830 klass = c 831 a = () 832 if opts.has_key('args'): 833 a = opts['args'] 834 ##dbg.fwriteln('args=', a) ##@ 835 try: 836 ##dbg.fwriteln('Eval args') ##@ 837 a = eval(a, vars(sys.modules[__name__])) 838 except: 839 ##dbg.fwriteln('\texception') ##@ 840 a=() 841 842 ##dbg.fwriteln('Create and set new class', klass) ##@ 843 h = klass(*a) 844 ##end if handlers[hn] != None 845 ##dbg.fwriteln('Try add to instance') ##@ 846 try: 847 ##dbg.fwriteln('Add handler to instance') ##@ 848 inst.addHandler(h) 849 except: 850 ##dbg.fwriteln('\texception') ##@ 851 pass 852 853 ##end if not h 854 if handlers[hn] == None: 855 ##dbg.fwriteln('Add to handlers') ##@ 856 handlers[hn]=h 857 858 ##dbg.fwriteln('Set name to handler=',hn) ##@ 859 setattr(h, 'name', hn) 860 861 # Configure handler. 862 ##dbg.fwriteln('Configure handler') ##@ 863 if opts.has_key('level'): 864 try: 865 h.setLevel( getLevelByName(opts['level']) ) 866 ##dbg.fwriteln('set level=', getLevelByName(opts['level'])) ##@ 867 except: 868 ##dbg.fwriteln('\texception') ##@ 869 pass 870 871 # Apply formatter. 872 if opts.has_key('formatter'): 873 ##dbg.fwriteln('Apply formatter') ##@ 874 _applyFormatter(opts['formatter'].strip(), h, cp, formatters) 875 # Apply filters. 876 if opts.has_key('filters'): 877 ##dbg.fwriteln('ApplyFilters') ##@ 878 _applyFilters([f.strip() for f in opts['filters'].split(',') if f.strip()], h, cp, filters) 879 880 ##dbg.fwriteln('apply attrs') ##@ 881 _applyAttrs(opts, h) 882 883 ##dbg.fwriteln('Apply actions') ##@ 884 _applyActions(opts, h, cp, handlers, formatters, filters)
885 ##end if cp.has_section('handler_' + hn) 886 ##dbg.fwriteln() ##@ 887 ##end for h 888 889 ##@dbg.fwlevel ##@
890 -def _applyActions(opts, inst, cp, handlers, formatters, filters):
891 """ 892 Aplly actions with names listed in "opts['actions']": to object "inst". 893 894 First try find named filter into "filters" dict, if not find then 895 (which have attribute "name") into "inst.filters" list, 896 else create new. Then apply changes 897 to filter. 898 Filter name must exist in filters list. 899 To add filter to inst used "addFilter" method. 900 901 @param opts: Dictionary with actions describes. 902 @type opts: dict 903 @param inst: Object instance to apply actions. 904 @type inst: Object instance 905 906 Action example:: 907 908 actions=act01 909 act01=add, filter, filt01 910 911 """ 912 913 if opts.has_key('actions'): 914 ##dbg.fwriteln('Action LOOP') ##@ 915 for a in [ opts[n.strip()] for n in opts['actions'].split(',') \ 916 if opts.has_key( n.strip() ) ]: 917 # Loop for actions. 918 aa = [n.strip() for n in a.split(',')] 919 ##dbg.fwriteln('aa=', aa) ##@ 920 if aa[0] == 'add': 921 ##dbg.fwriteln('add') ##@ 922 if aa[1] == 'filter' and ( issubclass(inst.__class__, logging.Handler) \ 923 or issubclass(inst.__class__, logging.Logger) ): 924 ##dbg.fwriteln('\tfilters') ##@ 925 _applyFilters([aa[2]], inst, cp, filters) 926 elif aa[1] == 'handler' and issubclass(inst.__class__, logging.Logger): 927 ##dbg.fwriteln('\thandler') ##@ 928 _applyHandlers([aa[2]], inst, cp, handlers, formatters, filters) 929 elif aa[1] == 'formatter' and issubclass(inst.__class__, logging.Handler): 930 ##dbg.fwriteln('\tformatter') ##@ 931 _applyFormatter(aa[2], inst, cp, formatters) 932 ##end elif a[0] == 'add' 933 elif aa[0] == 'remove': 934 ##dbg.fwriteln('remove') ##@ 935 if aa[1] == 'filter' and ( issubclass(inst.__class__, logging.Handler) \ 936 or issubclass(inst.__class__, logging.Logger) ): 937 ##dbg.fwriteln('\tfilters') ##@ 938 for i in inst.filters: 939 if hasattr(i, 'name') and i.name == aa[2]: 940 inst.removeFilter(i) 941 break 942 elif aa[1] == 'handler' and issubclass(inst.__class__, logging.Logger): 943 ##dbg.fwriteln('\thandlers') ##@ 944 for i in inst.handlers: 945 if hasattr(i, 'name') and i.name == aa[2]: 946 inst.removeHandler(i) 947 break 948 elif aa[1] == 'formatter' and issubclass(inst.__class__, logging.Handler): 949 if hasattr(inst.formatter, 'name') and inst.formatter.name == aa[2]: 950 ##dbg.fwriteln('formatter') ##@ 951 inst.setFormatter(logging.Formatter()) 952 ##end elif a[0] == 'remove' 953 elif aa[0] == 'clear': 954 ##dbg.fwriteln('clear') ##@ 955 if aa[1] == 'filter' and ( issubclass(inst.__class__, logging.Handler) \ 956 or issubclass(inst.__class__, logging.Logger) ): 957 ##dbg.fwriteln('\tfilters') ##@ 958 for i in inst.filters: 959 inst.removeFilter(i) 960 elif aa[1] == 'handler' and issubclass(inst.__class__, logging.Logger): 961 ##dbg.fwriteln('\thandlers') ##@ 962 for i in inst.handlers: 963 inst.removeHandler(i) 964 elif aa[1] == 'formatter' and issubclass(inst.__class__, logging.Handler): 965 ##dbg.fwriteln('\tformatter') ##@ 966 inst.setFormatter(logging.Formatter())
967 ##end elif a[0] == 'clear' 968 ##dbg.fwriteln() ##@ 969 ##end for a 970 971
972 -class NullHandler(Handler):
973 """ 974 Handler that do no output. 975 """
976 - def __init__(self, level=NOTSET):
977 ##dbg.fwriteln('NullHandler.__init__') ##@ 978 Handler.__init__(self, level)
979
980 - def emit(self, record):
981 """ 982 Do nothing. 983 """ 984 ##dbg.fwriteln('NullHandler.emit') ##@ 985 pass
986
987 -class RangeFilter:
988 """ 989 Filter available output only if level in specified range. 990 Return true if available. 991 """
992 - def __init__(self, min=NOTSET, max=CRITICAL ):
993 """ 994 @param min: Minimal available level for output. 995 @type min: int = {NOTSET} 996 @param max: Maximal available level for output. 997 @type max: int = {CRITICAL} 998 """ 999 ##dbg.fwriteln('RangeFilter.__init__() ', min, ', ', max) ##@ 1000 self._min=min 1001 self._max=max
1002
1003 - def filter(self, record):
1004 """ 1005 Return true if message is available (in specified range). 1006 """ 1007 ##dbg.fwriteln('RangeFilter.filter %d <= %d <= %d == %d' % (self._min,record.levelno, self._max, self._min <= record.levelno <= self._max) ) ##@ 1008 return self._min <= record.levelno <= self._max
1009
1010 -class NamesFilter:
1011 """ 1012 Filter available output only if logger name equal any from 'names'. 1013 Return true if available. 1014 """
1015 - def __init__(self, names='', case=0 ):
1016 """ 1017 @param names: List (or string with one name) of names with which 1018 allow output. 1019 @type names: list or str = '' 1020 @param case: If true then compare names case sensitive. 1021 @type case: bool = 0 1022 """ 1023 ##dbg.fwriteln('NamesFilter.__init__() names=', repr(names)) ##@ 1024 if type(names) == str: 1025 names = [names] 1026 if not case: 1027 self._names=[n.lower() for n in names] 1028 else: 1029 self._names=names 1030 self._case=case
1031
1032 - def filter(self, record):
1033 """ 1034 Return true if message is available (in 'names'). 1035 """ 1036 r= self._case and record.name or record.name.lower() 1037 ##dbg.writeln('**** name=',r) ##@ 1038 for n in self._names: 1039 ##dbg.writeln('******** n=',n) ##@ 1040 if r.startswith(n): 1041 return 1 1042 ##dbg.writeln('**** return 0') ##@ 1043 return 0
1044
1045 -class IndentFormatter(Formatter, object):
1046 """ 1047 Formatter with indentation level support. 1048 1049 Instance of this class exists only in one exemplar. For other requests 1050 of new instance returned already existing. 1051 1052 Level indentation is specific for each threads separately (if thread 1053 library available, otherwase used only common indentation level for all threads). 1054 1055 @cvar _level: Indentation level. Dictionary of {thread.id, level} if thread 1056 enebled, else level. 1057 @type _level: dict{int,int} or int 1058 @cvar __instance: Singular instance. 1059 @type __instance: Instance IndentFormatter 1060 """ 1061 1062 __instance = None 1063 _level = thread and threading.local() or 0 1064
1065 - def __new__(cls, *args):
1066 """ 1067 Allow only one exemplar of instance. For other calls return existing. 1068 """ 1069 ##dbg.fwriteln('IndentFormatter.__new__') ##@ 1070 logging._acquireLock() 1071 try: 1072 if not IndentFormatter.__instance: 1073 ##dbg.fwriteln('IndentFormatter.__new__ create new') ##@ 1074 IndentFormatter.__instance = super(IndentFormatter, cls).__new__(cls, *args) 1075 IndentFormatter.__createLock() 1076 finally: 1077 logging._releaseLock() 1078 return IndentFormatter.__instance
1079
1080 - def __init__(self, fmt=None, datefmt=None):
1081 """ 1082 Initialize the formatter with specified format strings. 1083 1084 Initialize the formatter either with the specified format string, or a 1085 default as described above. Allow for specialized date formatting with 1086 the optional datefmt argument (if omitted, you get the ISO8601 format). 1087 """ 1088 ##dbg.fwriteln('IndentFormatter.__init__') ##@ 1089 Formatter.__init__(self, fmt, datefmt)
1090 1091 @staticmethod
1092 - def __init_level():
1093 """ 1094 Initialize level for current thread. 1095 """ 1096 ##dbg.fwriteln('IndentFormatter.initlevel') ##@ 1097 if thread: 1098 # Init thread dependent levels. 1099 if not hasattr(IndentFormatter._level, 'level'): 1100 ##dbg.fwriteln('IndentFormatter.initlevel initialized') ##@ 1101 IndentFormatter._level.level = 0
1102 1103 @staticmethod
1104 - def __get_level():
1105 """ 1106 Get level for current thread. 1107 """ 1108 ##dbg.fwriteln('IndentFormatter.getlevel') ##@ 1109 IndentFormatter.__init_level() 1110 if thread: 1111 l=IndentFormatter._level.level 1112 else: 1113 l=IndentFormatter._level 1114 return l
1115 1116 @staticmethod
1117 - def __set_level(value):
1118 """ 1119 Set level for current thread. 1120 """ 1121 ##dbg.fwriteln('IndentFormatter.setlevel') ##@ 1122 IndentFormatter.__init_level() 1123 if thread: 1124 IndentFormatter._level.level=value 1125 else: 1126 IndentFormatter._level=value
1127 1128 @staticmethod
1129 - def __createLock():
1130 """ 1131 Acquire a thread lock for serializing access to the level counter. 1132 """ 1133 ##dbg.fwriteln('IndentFormatter.createLock') ##@ 1134 if thread: 1135 IndentFormatter.__lock = threading.RLock() 1136 else: 1137 IndentFormatter.__lock = None
1138 1139 @staticmethod
1140 - def acquire():
1141 """ 1142 Acquire thread lock. 1143 """ 1144 ##dbg.fwriteln('IndentFormatter.acquire') ##@ 1145 if IndentFormatter.__lock: 1146 IndentFormatter.__lock.acquire()
1147 1148 @staticmethod
1149 - def release():
1150 """ 1151 Release thread lock. 1152 """ 1153 ##dbg.fwriteln('IndentFormatter.release') ##@ 1154 if IndentFormatter.__lock: 1155 IndentFormatter.__lock.release()
1156
1157 - def format(self, record):
1158 """ 1159 Format the specified record as text. 1160 """ 1161 ##dbg.fwriteln('IndentFormatter.format') ##@ 1162 c=__import__('XPyLIB') 1163 IndentFormatter.acquire() 1164 try: 1165 r=(c.log_levelbodychar * c.log_levelwidth * IndentFormatter.__get_level()) + c.log_levelendchar \ 1166 + Formatter.format(self, record) 1167 finally: 1168 IndentFormatter.release() 1169 return r
1170 1171 @staticmethod
1172 - def lvlup():
1173 """ 1174 Increase indentation level. 1175 """ 1176 ##dbg.fwriteln('IndentFormatter.lvlup') ##@ 1177 IndentFormatter.acquire() 1178 try: 1179 IndentFormatter.__set_level(IndentFormatter.__get_level()+1) 1180 finally: 1181 IndentFormatter.release()
1182 1183 @staticmethod
1184 - def lvldown():
1185 """ 1186 Decrease indentation level. 1187 """ 1188 ##dbg.fwriteln('IndentFormatter.lvldown') ##@ 1189 IndentFormatter.acquire() 1190 try: 1191 IndentFormatter.__set_level(IndentFormatter.__get_level()-1) 1192 if IndentFormatter.__get_level() < 0: 1193 IndentFormatter.__set_level(0) 1194 finally: 1195 IndentFormatter.release()
1196 1197 @staticmethod
1198 - def lvlreset():
1199 """ 1200 Reset indentation level to "0". 1201 """ 1202 ##dbg.fwriteln('IndentFormatter.lvlreset') ##@ 1203 IndentFormatter.acquire() 1204 try: 1205 IndentFormatter.__set_level(0) 1206 finally: 1207 IndentFormatter.release()
1208 1209 @staticmethod
1210 - def lvlwrap(fun):
1211 """ 1212 Auto level decorator for functions. 1213 1214 Call L{lvlup}() befor function call and L{lvldown}() after 1215 wrapped function return. 1216 @param fun: Wrapped function. 1217 @type func 1218 """ 1219 ##dbg.fwriteln('IndentFormatter.lvlwrap') ##@ 1220 @wraps(fun) 1221 def wrapper(*args, **kwds): 1222 IndentFormatter.acquire() 1223 try: 1224 l=IndentFormatter.__get_level() 1225 IndentFormatter.lvlup() 1226 r = fun(*args, **kwds) 1227 ##IndentFormatter.lvldown() 1228 IndentFormatter.__set_level(l) # Defense from error 1229 finally: 1230 IndentFormatter.release() 1231 return r
1232 return wrapper
1233 1234 @staticmethod
1235 - def lvlwraplog(fun, loginst):
1236 """ 1237 Auto level decorator for functions. 1238 1239 Write first 'Call "fun.__name__"' using loginst.L{dbgtrace}(). 1240 Also as L{lvlwrap}(). 1241 If exception occurs then raise it. 1242 If level error tested then write '*** DBG LEVEL ERROR = different' 1243 where 'different' is level different. 1244 Write last 'Return from "fun.__name__"' using loginst.L{dbgtrace}(). 1245 1246 @param fun: Wrapped function. 1247 @type func 1248 @param loginst: Logger instance to use for reporting. 1249 @type loginst 1250 """ 1251 ##dbg.fwriteln('IndentFormatter.lvlwraplog') ##@ 1252 @wraps(fun) 1253 def wrapper(*args, **kwds): 1254 ##dbg.fwriteln('IndentFormatter.lvlwraplog.wrapper') ##@ 1255 IndentFormatter.acquire() 1256 c=__import__('XPyLIB') 1257 try: 1258 l=IndentFormatter.__get_level() 1259 loginst.dbgtrace('%s%s()' % (c.log_descfuncall,fun.__name__)) 1260 IndentFormatter.lvlup() 1261 r = fun(*args, **kwds) 1262 IndentFormatter.lvldown() 1263 if IndentFormatter.__get_level()!=l: 1264 IndentFormatter.__set_level(l) # Defense from error 1265 loginst.dbgtrace('%s%d' % (c.log_levelerr, d)) 1266 except Exception,e: 1267 IndentFormatter.__set_level(l) 1268 ##dbg.fwriteln('IndentFormatter.lvlwraplog.wrapper except ',e) ##@ 1269 raise e 1270 finally: 1271 IndentFormatter.release() 1272 loginst.dbgtrace('%s%s()' % (c.log_descfunret,fun.__name__)) 1273 return r
1274 return wrapper 1275 1276 # Initialize instance of Indent formatter. 1277 IndentFormatter() 1278
1279 -class XLogger(_xBaseloggerClass):
1280 - def __init__(self, name, level=NOTSET):
1281 """ 1282 Base logging class fo xlogging. 1283 1284 After importing xlogging this class set as default class for new loggers. 1285 """ 1286 _xBaseloggerClass.__init__(self, name, level)
1287
1288 - def trace(self, msg, *args, **kwargs):
1289 """ 1290 Log 'msg % args' with severity 'TRACE'. 1291 1292 To pass exception information, use the keyword argument exc_info with 1293 a true value, e.g. 1294 1295 logger.trace("Houston, we have a %s", "thorny problem", exc_info=1) 1296 """ 1297 ##dbg.fwriteln('XLogger.trace') ##@ 1298 _trace(self, msg, *args, **kwargs)
1299
1300 - def dbgtrace(self, msg, *args, **kwargs):
1301 """ 1302 Log 'msg % args' with severity 'DBGTRACE'. 1303 1304 To pass exception information, use the keyword argument exc_info with 1305 a true value, e.g. 1306 1307 logger.dbgtrace("Houston, we have a %s", "thorny problem", exc_info=1) 1308 """ 1309 ##dbg.fwriteln('XLogger.dbgtrace') ##@ 1310 _dbgtrace(self, msg, *args, **kwargs)
1311 1312 1313 # Set XLogger as base logger class. 1314 logging.setLoggerClass(XLogger) 1315 1316 # Additional module assigments. 1317 ##dbg.fwriteln('_self_module=', sys.modules[__name__]) ##@ 1318 1319 # Additional fuctions for bound to logger class. 1320 ##@dbg.fwlevel ##@
1321 -def _trace(self, msg, *args, **kwargs):
1322 """ 1323 Log 'msg % args' with severity 'TRACE'. 1324 1325 To pass exception information, use the keyword argument exc_info with 1326 a true value, e.g. 1327 1328 logger.trace("Houston, we have a %s", "thorny problem", exc_info=1) 1329 """ 1330 ##dbg.fwriteln('_trace') ##@ 1331 if self.manager.disable >= TRACE: 1332 return 1333 ##dbg.fwriteln('_trace ... %d>=%d'%(TRACE,self.getEffectiveLevel())) ##@ 1334 if TRACE >= self.getEffectiveLevel(): 1335 apply(self._log, (TRACE, msg, args), kwargs)
1336 1337 ##@dbg.fwlevel ##@
1338 -def _dbgtrace(self, msg, *args, **kwargs):
1339 """ 1340 Log 'msg % args' with severity 'DBGTRACE'. 1341 1342 To pass exception information, use the keyword argument exc_info with 1343 a true value, e.g. 1344 1345 logger.dbgtrace("Houston, we have a %s", "thorny problem", exc_info=1) 1346 """ 1347 ##dbg.fwriteln('_dbgtrace') ##@ 1348 if self.manager.disable >= DBGTRACE: 1349 return 1350 ##dbg.fwriteln('_dbgtrace ... %d>=%d'%(DBGTRACE,self.getEffectiveLevel())) ##@ 1351 if DBGTRACE >= self.getEffectiveLevel(): 1352 apply(self._log, (DBGTRACE, msg, args), kwargs)
1353 1354 # Add if need trace and dbgtrace method to root logger. 1355 if not hasattr(root, 'tarce'): 1356 setattr(root, 'trace', XLogger.trace) 1357 1358 if not hasattr(root, 'dbgtarce'): 1359 setattr(root, 'dbgtrace', XLogger.dbgtrace) 1360 1361 ##@dbg.fwlevel ##@
1362 -def trace(msg, *args, **kwargs):
1363 """ 1364 Log a message with severity 'TRACE' on the root logger. 1365 """ 1366 if len(root.handlers) == 0: 1367 basicConfig() 1368 apply(_trace, (root, msg,)+args, kwargs)
1369 1370 ##@dbg.fwlevel ##@
1371 -def dbgtrace(msg, *args, **kwargs):
1372 """ 1373 Log a message with severity 'DBGTRACE' on the root logger. 1374 """ 1375 if len(root.handlers) == 0: 1376 basicConfig() 1377 apply(_dbgtrace, (root, msg,)+args, kwargs)
1378 1379 1380 1381 1382 # End Implemetation 1383 1384 1385 1386 1387 #-DEBUG-START------------------------------------------------------------------- 1388
1389 -def _debug():
1390 """ 1391 """ 1392 import XPyLIB 1393 import os 1394 1395 class _TestHandler(Handler): 1396 """ 1397 Test handler that add at start message 'TestHandler emit:' and output it to 1398 sys.stderr. 1399 """ 1400 def __init__(self, level=NOTSET): 1401 dbg.fwriteln('TestHandler.__init__') ##@ 1402 Handler.__init__(self, level)
1403 1404 def emit(self, record): 1405 """ 1406 1407 """ 1408 dbg.fwriteln('TestHandler.emit') ##@ 1409 import sys 1410 msg=self.format(record) 1411 sys.stderr.write('TestHandler emit: %s\n' % msg) 1412 pass 1413 1414 class _TestFilter(Filter): 1415 """ 1416 Test filter that available only if msg starts with 'yes' 1417 """ 1418 attr='NOT SET ATTR' 1419 def __init__(self, args='NO ARGS'): 1420 dbg.fwriteln('TestFilter.__init__() ', args) ##@ 1421 Filter.__init__(self, '') # No name 1422 1423 def filter(self, record): 1424 """ 1425 """ 1426 dbg.fwriteln('TestFilter.filter msg="'+record.getMessage()[:5]+'..."') ##@ 1427 dbg.fwriteln('TestFilter.filter attr=', self.attr) ##@ 1428 return 'yes' == record.getMessage()[:3] 1429 pass 1430 1431 _debug.TestHandler=_TestHandler 1432 _debug.TestFilter=_TestFilter 1433 #root.setLevel(TRACE) do this throw .cfg. 1434 p=os.path.join(XPyLIB.dir_root,'XPyLIB','test','xlogging1.cfg') 1435 dbg.writeln('p=',p) 1436 applyConfigFile(p) 1437 A=getLogger('A') 1438 trace('test trace msg') 1439 dbgtrace('test dbgtrace msg MUST NOT print') 1440 A.trace('test A.trace msg') 1441 A.warning('test A.warning msg') 1442 AB=getLogger('A.B') 1443 AB.error('test A.B.error msg') 1444 AB.dbgtrace('!!!!!!test A.B.dbgtrace msg must NOT print') 1445 ABC=getLogger('A.B.C') 1446 ABC.dbgtrace('yes!!!!!!test A.B.C.dbgtrace msg must NOT print') 1447 ABC.trace('!!!!!!test A.B.C.trace msg must NOT print') 1448 ABC.trace('yes test A.B.C.trace msg') 1449 1450 p=os.path.join(XPyLIB.dir_root,'XPyLIB','test','xlogging2.cfg') 1451 dbg.writeln('p=',p) 1452 applyConfigFile(p) 1453 warning('test root warning msg') 1454 A.warning('test A warning msg') 1455 critical('test root critical msg') 1456 A.critical('test A critical msg') 1457 1458 B=getLogger('B') 1459 B.propagate=0 1460 B.setLevel(TRACE) 1461 hB=StreamHandler(sys.stderr) 1462 B.addHandler(hB) 1463 BF=getLogger('B.F') 1464 BG=getLogger('B.g') 1465 BH=getLogger('B.H') 1466 fFG=NamesFilter(['B.F','B.G']) 1467 #fFG=Filter('B.F') 1468 hB.addFilter(fFG) 1469 BF.trace('BF.trace') 1470 BH.trace('BH.trace MUST NOT OUT') 1471 BG.trace('BG.trace') 1472 pass 1473 1474 #-DEBUG-END--------------------------------------------------------------------- 1475 1476 if __name__=='__main__': 1477 _debug() 1478