1
2
3
4
5
6
7
8
9
10
11
12
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
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
247 import dbg
248
249
250
251
252
253 TRACE = 15
254 DBGTRACE = 5
255
256
257 addLevelName(TRACE, 'TRACE')
258 addLevelName(DBGTRACE, 'DBGTRACE')
259
260
261 _xBaseloggerClass = logging.getLoggerClass()
262
263
264
266 """
267 Return level name by level value.
268
269 If no such level then raise error KeyError.
270 """
271
272 return logging._levelNames[levelname]
273
274
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
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
348
349 if not all( \
350 [ cp.has_section(s) and cp.has_option(s, 'keys') \
351 for s in ('loggers', 'handlers', 'filters', 'formatters') ] ):
352
353 return
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
361
362
363
364
365
366 logging._acquireLock()
367 try:
368
369
370 sec='manager'
371 if cp.has_section(sec):
372 if cp.has_option(sec, 'disable'):
373 try:
374
375 disable( getLevelByName(cp.get(sec,'disable')) )
376 except:
377
378 pass
379
380
381 for logger in loggers:
382 sec = 'logger_' + logger
383
384 if cp.has_section(sec):
385 opts = _options(sec, cp)
386
387
388 if logger == 'root':
389 name = logger
390 else:
391 name = opts.has_key('qualname') and opts['qualname'] or logger
392
393
394 if name == 'root':
395 loginst = root
396 else:
397 loginst = logging.getLogger(name)
398 loggers[logger] = loginst
399
400
401 if opts.has_key('level'):
402 try:
403 loginst.setLevel( getLevelByName(opts['level']) )
404
405 except:
406
407 pass
408 if opts.has_key('propagate'):
409 try:
410 loginst.propagate = int(opts['propagate'])
411
412 except:
413
414 pass
415 if opts.has_key('disabled'):
416 try:
417 loginst.disabled = int(opts['disabled'])
418
419 except:
420
421 pass
422
423
424
425 _applyAttrs(opts, loginst)
426
427
428
429 if opts.has_key('filters'):
430
431
432 for f in loginst.filters:
433 loginst.remove(f)
434 fs=[ n.strip() for n in opts['filters'].split(',') if n.strip() ]
435
436 _applyFilters(fs, loginst, cp, filters)
437
438
439
440 if opts.has_key('handlers'):
441
442
443 for h in loginst.handlers:
444 loginst.removeHandler(h)
445 hs=[ n.strip() for n in opts['handlers'].split(',') if n.strip() ]
446
447 _applyHandlers(hs, loginst, cp, handlers, formatters, filters)
448
449
450
451 _applyActions(opts, loginst, cp, handlers, formatters, filters)
452
453
454
455
456
457
458 finally:
459
460 logging._releaseLock()
461
462
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
474 for a in [ opts[n.strip()] for n in opts['attributes'].split(',') \
475 if opts.has_key( n.strip() ) ]:
476
477 aa = [n.strip() for n in a.partition(',')]
478
479 if aa[0]:
480 try:
481
482 setattr(inst, aa[0], aa[2])
483 except:
484
485 pass
486
487
488
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
506 return r
507
508
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
543
544
545 for fn in flts:
546
547 if not filters.has_key(fn):
548
549
550 break
551 if cp.has_section('filter_' + fn):
552 opts = _options('filter_' + fn, cp)
553
554 f = None
555
556
557
558 for fi in inst.filters:
559 if hasattr(fi, 'name') and (fi.name == fn):
560
561 f=fi
562 break
563 if not f:
564 if filters[fn] != None:
565
566 f=filters[fn]
567 else:
568
569
570 klass = logging.Filter
571 if opts.has_key('class'):
572 c = opts['class'].strip()
573
574 if c:
575 try:
576
577 c = eval(c, vars(sys.modules[__name__]))
578 except:
579
580 c=None
581 if c:
582
583 klass = c
584 a = ()
585
586 if opts.has_key('args'):
587
588 a = opts['args']
589
590 try:
591
592 a = eval(a, vars(sys.modules[__name__]))
593 except:
594
595 a=()
596
597
598 f = klass(*a)
599
600 try:
601
602 inst.addFilter(f)
603 except:
604 pass
605
606
607 if filters[fn] == None:
608
609 filters[fn]=f
610
611
612
613 setattr(f, 'name', fn)
614
615
616 _applyAttrs(opts, f)
617
618
619
620
621
622
623
624
742
743
744
745
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
789
790
791 for hn in hdls:
792
793 if cp.has_section('handler_' + hn):
794 opts = _options('handler_' + hn, cp)
795
796 h = None
797 if not handlers.has_key(hn):
798
799
800 return
801
802
803 for hi in inst.handlers:
804 if hasattr(hi, 'name') and (hi.name == hn):
805
806 h=hi
807 break
808 if not h:
809
810
811 if handlers[hn] != None:
812
813 h=handlers[hn]
814 else:
815
816
817 klass = NullHandler
818 if opts.has_key('class'):
819 c = opts['class'].strip()
820
821 if c:
822 try:
823
824 c = eval(c, vars(sys.modules[__name__]))
825 except Exception, e:
826
827 c=None
828 if c:
829
830 klass = c
831 a = ()
832 if opts.has_key('args'):
833 a = opts['args']
834
835 try:
836
837 a = eval(a, vars(sys.modules[__name__]))
838 except:
839
840 a=()
841
842
843 h = klass(*a)
844
845
846 try:
847
848 inst.addHandler(h)
849 except:
850
851 pass
852
853
854 if handlers[hn] == None:
855
856 handlers[hn]=h
857
858
859 setattr(h, 'name', hn)
860
861
862
863 if opts.has_key('level'):
864 try:
865 h.setLevel( getLevelByName(opts['level']) )
866
867 except:
868
869 pass
870
871
872 if opts.has_key('formatter'):
873
874 _applyFormatter(opts['formatter'].strip(), h, cp, formatters)
875
876 if opts.has_key('filters'):
877
878 _applyFilters([f.strip() for f in opts['filters'].split(',') if f.strip()], h, cp, filters)
879
880
881 _applyAttrs(opts, h)
882
883
884 _applyActions(opts, h, cp, handlers, formatters, filters)
885
886
887
888
889
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
915 for a in [ opts[n.strip()] for n in opts['actions'].split(',') \
916 if opts.has_key( n.strip() ) ]:
917
918 aa = [n.strip() for n in a.split(',')]
919
920 if aa[0] == 'add':
921
922 if aa[1] == 'filter' and ( issubclass(inst.__class__, logging.Handler) \
923 or issubclass(inst.__class__, logging.Logger) ):
924
925 _applyFilters([aa[2]], inst, cp, filters)
926 elif aa[1] == 'handler' and issubclass(inst.__class__, logging.Logger):
927
928 _applyHandlers([aa[2]], inst, cp, handlers, formatters, filters)
929 elif aa[1] == 'formatter' and issubclass(inst.__class__, logging.Handler):
930
931 _applyFormatter(aa[2], inst, cp, formatters)
932
933 elif aa[0] == 'remove':
934
935 if aa[1] == 'filter' and ( issubclass(inst.__class__, logging.Handler) \
936 or issubclass(inst.__class__, logging.Logger) ):
937
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
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
951 inst.setFormatter(logging.Formatter())
952
953 elif aa[0] == 'clear':
954
955 if aa[1] == 'filter' and ( issubclass(inst.__class__, logging.Handler) \
956 or issubclass(inst.__class__, logging.Logger) ):
957
958 for i in inst.filters:
959 inst.removeFilter(i)
960 elif aa[1] == 'handler' and issubclass(inst.__class__, logging.Logger):
961
962 for i in inst.handlers:
963 inst.removeHandler(i)
964 elif aa[1] == 'formatter' and issubclass(inst.__class__, logging.Handler):
965
966 inst.setFormatter(logging.Formatter())
967
968
969
970
971
973 """
974 Handler that do no output.
975 """
979
980 - def emit(self, record):
981 """
982 Do nothing.
983 """
984
985 pass
986
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
1000 self._min=min
1001 self._max=max
1002
1004 """
1005 Return true if message is available (in specified range).
1006 """
1007
1008 return self._min <= record.levelno <= self._max
1009
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
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
1033 """
1034 Return true if message is available (in 'names').
1035 """
1036 r= self._case and record.name or record.name.lower()
1037
1038 for n in self._names:
1039
1040 if r.startswith(n):
1041 return 1
1042
1043 return 0
1044
1233
1234 @staticmethod
1274 return wrapper
1275
1276
1277 IndentFormatter()
1278
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
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
1310 _dbgtrace(self, msg, *args, **kwargs)
1311
1312
1313
1314 logging.setLoggerClass(XLogger)
1315
1316
1317
1318
1319
1320
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
1331 if self.manager.disable >= TRACE:
1332 return
1333
1334 if TRACE >= self.getEffectiveLevel():
1335 apply(self._log, (TRACE, msg, args), kwargs)
1336
1337
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
1348 if self.manager.disable >= DBGTRACE:
1349 return
1350
1351 if DBGTRACE >= self.getEffectiveLevel():
1352 apply(self._log, (DBGTRACE, msg, args), kwargs)
1353
1354
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
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
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
1383
1384
1385
1386
1387
1388
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, '')
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
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
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
1475
1476 if __name__=='__main__':
1477 _debug()
1478