| 1 |
from logging import * |
|---|
| 2 |
import sys |
|---|
| 3 |
|
|---|
| 4 |
NOTICE = (INFO+WARNING)/2 |
|---|
| 5 |
_default_level = NOTICE |
|---|
| 6 |
_default_format = "%(filename)s:%(name)s[%(lineno)d]: %(message)s" |
|---|
| 7 |
|
|---|
| 8 |
def set_default_level(level): |
|---|
| 9 |
""" |
|---|
| 10 |
Set the default log level for classes for which set_class_level() |
|---|
| 11 |
or instance.set_log_level() was never called. |
|---|
| 12 |
Default: NOTICE. |
|---|
| 13 |
Call early - only affects class loggers created after the call. |
|---|
| 14 |
""" |
|---|
| 15 |
global _default_level |
|---|
| 16 |
_default_level = level |
|---|
| 17 |
|
|---|
| 18 |
def _class_logger(cls): |
|---|
| 19 |
nm ="_" + cls.__name__ + "__logger" |
|---|
| 20 |
try: |
|---|
| 21 |
lg = getattr(cls, nm) |
|---|
| 22 |
except AttributeError: |
|---|
| 23 |
lg = getLogger(cls.__name__) |
|---|
| 24 |
lg.setLevel(_default_level) |
|---|
| 25 |
setattr(cls, nm, lg) |
|---|
| 26 |
return lg |
|---|
| 27 |
|
|---|
| 28 |
def set_class_level(cls, level): |
|---|
| 29 |
""" |
|---|
| 30 |
Set the log level for this class. |
|---|
| 31 |
level: one of the levels defined in the logging module. |
|---|
| 32 |
Side effects: Sets the log level for _any object_ of this class. |
|---|
| 33 |
""" |
|---|
| 34 |
lg = _class_logger(cls) |
|---|
| 35 |
lg.setLevel(level) |
|---|
| 36 |
|
|---|
| 37 |
class LoggingClass: |
|---|
| 38 |
|
|---|
| 39 |
""" |
|---|
| 40 |
A base class for classes using for easy use of the "logging" module. |
|---|
| 41 |
|
|---|
| 42 |
Instances of derived classes have a "logger" attribute |
|---|
| 43 |
that represents a class-specific logging.Logger object. |
|---|
| 44 |
|
|---|
| 45 |
The "name" of the class-specific logger will be the class name. |
|---|
| 46 |
Log levels etc. can be set on a class-specific basis. |
|---|
| 47 |
|
|---|
| 48 |
CAUTION: The "logger" attribute is resolved through __getattr__(). |
|---|
| 49 |
The "__logger" attribute should work independently of __getattr__(). |
|---|
| 50 |
|
|---|
| 51 |
Usage (doctest): |
|---|
| 52 |
|
|---|
| 53 |
>>> class LogTest(LoggingClass): |
|---|
| 54 |
... def info(self): |
|---|
| 55 |
... self.logger.info("This is an info.") |
|---|
| 56 |
... def error(self): |
|---|
| 57 |
... self.logger.error("This is an error!") |
|---|
| 58 |
... |
|---|
| 59 |
>>> init_logging(level=INFO, |
|---|
| 60 |
... format="%(name)s[%(lineno)d]: %(message)s", stream=sys.stdout) |
|---|
| 61 |
>>> logtest = LogTest() |
|---|
| 62 |
>>> logtest.info() |
|---|
| 63 |
>>> logtest.error() |
|---|
| 64 |
LogTest[5]: This is an error! |
|---|
| 65 |
>>> LogTest().set_log_level(INFO) |
|---|
| 66 |
>>> logtest.info() |
|---|
| 67 |
LogTest[3]: This is an info. |
|---|
| 68 |
|
|---|
| 69 |
""" |
|---|
| 70 |
|
|---|
| 71 |
|
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 |
|
|---|
| 76 |
|
|---|
| 77 |
def __getattr__(self, attr): |
|---|
| 78 |
""" |
|---|
| 79 |
Resolves the "logger" attribute. |
|---|
| 80 |
Call this when redefining __getattr__() in derived classes! |
|---|
| 81 |
""" |
|---|
| 82 |
if attr == "logger": |
|---|
| 83 |
return _class_logger(self.__class__) |
|---|
| 84 |
raise AttributeError, ("'LoggingClass' object has no attribute '%s'" |
|---|
| 85 |
% attr) |
|---|
| 86 |
|
|---|
| 87 |
def set_log_level(self, level): |
|---|
| 88 |
""" |
|---|
| 89 |
Set the log level for this class. |
|---|
| 90 |
level: one of the levels defined in the logging module. |
|---|
| 91 |
Sets the log level for _any object_ of this class. |
|---|
| 92 |
""" |
|---|
| 93 |
return set_class_level(self.__class__, level) |
|---|
| 94 |
|
|---|
| 95 |
|
|---|
| 96 |
def init_logging(level=NOTICE, format=_default_format, stream=sys.stderr): |
|---|
| 97 |
"""Initialize a basic logging setup.""" |
|---|
| 98 |
|
|---|
| 99 |
handler = StreamHandler(stream) |
|---|
| 100 |
handler.setFormatter(Formatter(format)) |
|---|
| 101 |
handler.setLevel(level) |
|---|
| 102 |
|
|---|
| 103 |
getLogger().addHandler(handler) |
|---|
| 104 |
|
|---|
| 105 |
def init_logfile(file, level=INFO, format=_default_format): |
|---|
| 106 |
|
|---|
| 107 |
handler = FileHandler(file) |
|---|
| 108 |
handler.setFormatter(Formatter(format)) |
|---|
| 109 |
handler.setLevel(level) |
|---|
| 110 |
|
|---|
| 111 |
getLogger().addHandler(handler) |
|---|
| 112 |
|
|---|
| 113 |
def _test(): |
|---|
| 114 |
import doctest, loggingclass |
|---|
| 115 |
doctest.testmod(loggingclass) |
|---|
| 116 |
|
|---|
| 117 |
if __name__ == "__main__": |
|---|
| 118 |
_test() |
|---|