| 1 | """ |
|---|
| 2 | Logging utilities. |
|---|
| 3 | |
|---|
| 4 | Ported to Python 3. |
|---|
| 5 | """ |
|---|
| 6 | |
|---|
| 7 | from six import ensure_str |
|---|
| 8 | |
|---|
| 9 | from pyutil import nummedobj |
|---|
| 10 | |
|---|
| 11 | from foolscap.logging import log |
|---|
| 12 | from twisted.python import log as tw_log |
|---|
| 13 | |
|---|
| 14 | # We want to convert bytes keys to Unicode, otherwise JSON serialization |
|---|
| 15 | # inside foolscap will fail (for details see |
|---|
| 16 | # https://github.com/warner/foolscap/issues/88) |
|---|
| 17 | from .jsonbytes import bytes_to_unicode |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | NOISY = log.NOISY # 10 |
|---|
| 21 | OPERATIONAL = log.OPERATIONAL # 20 |
|---|
| 22 | UNUSUAL = log.UNUSUAL # 23 |
|---|
| 23 | INFREQUENT = log.INFREQUENT # 25 |
|---|
| 24 | CURIOUS = log.CURIOUS # 28 |
|---|
| 25 | WEIRD = log.WEIRD # 30 |
|---|
| 26 | SCARY = log.SCARY # 35 |
|---|
| 27 | BAD = log.BAD # 40 |
|---|
| 28 | |
|---|
| 29 | |
|---|
| 30 | def msg(*args, **kwargs): |
|---|
| 31 | return log.msg(*args, **bytes_to_unicode(True, kwargs)) |
|---|
| 32 | |
|---|
| 33 | # If log.err() happens during a unit test, the unit test should fail. We |
|---|
| 34 | # accomplish this by sending it to twisted.log too. When a WEIRD/SCARY/BAD |
|---|
| 35 | # thing happens that is nevertheless handled, use log.msg(failure=f, |
|---|
| 36 | # level=WEIRD) instead. |
|---|
| 37 | |
|---|
| 38 | def err(failure=None, _why=None, **kwargs): |
|---|
| 39 | tw_log.err(failure, _why, **kwargs) |
|---|
| 40 | if 'level' not in kwargs: |
|---|
| 41 | kwargs['level'] = log.UNUSUAL |
|---|
| 42 | return log.err(failure, _why, **bytes_to_unicode(True, kwargs)) |
|---|
| 43 | |
|---|
| 44 | class LogMixin: |
|---|
| 45 | """ I remember a msg id and a facility and pass them to log.msg() """ |
|---|
| 46 | def __init__(self, facility=None, grandparentmsgid=None): |
|---|
| 47 | self._facility = facility |
|---|
| 48 | self._grandparentmsgid = grandparentmsgid |
|---|
| 49 | self._parentmsgid = None |
|---|
| 50 | |
|---|
| 51 | def log(self, msg, facility=None, parent=None, *args, **kwargs): |
|---|
| 52 | if facility is None: |
|---|
| 53 | facility = self._facility |
|---|
| 54 | pmsgid = parent |
|---|
| 55 | if pmsgid is None: |
|---|
| 56 | pmsgid = self._parentmsgid |
|---|
| 57 | if pmsgid is None: |
|---|
| 58 | pmsgid = self._grandparentmsgid |
|---|
| 59 | kwargs = {ensure_str(k): v for (k, v) in kwargs.items()} |
|---|
| 60 | msgid = log.msg(msg, facility=facility, parent=pmsgid, *args, |
|---|
| 61 | **bytes_to_unicode(True, kwargs)) |
|---|
| 62 | if self._parentmsgid is None: |
|---|
| 63 | self._parentmsgid = msgid |
|---|
| 64 | return msgid |
|---|
| 65 | |
|---|
| 66 | class PrefixingLogMixin(nummedobj.NummedObj, LogMixin): |
|---|
| 67 | """ I prepend a prefix to each msg, which includes my class and instance number as well as |
|---|
| 68 | a prefix supplied by my subclass. """ |
|---|
| 69 | def __init__(self, facility=None, grandparentmsgid=None, prefix=''): |
|---|
| 70 | nummedobj.NummedObj.__init__(self) |
|---|
| 71 | LogMixin.__init__(self, facility, grandparentmsgid) |
|---|
| 72 | |
|---|
| 73 | if prefix: |
|---|
| 74 | if isinstance(prefix, bytes): |
|---|
| 75 | prefix = prefix.decode("utf-8", errors="replace") |
|---|
| 76 | self._prefix = "%s(%s): " % (self.__repr__(), prefix) |
|---|
| 77 | else: |
|---|
| 78 | self._prefix = "%s: " % (self.__repr__(),) |
|---|
| 79 | |
|---|
| 80 | def log(self, msg="", facility=None, parent=None, *args, **kwargs): |
|---|
| 81 | return LogMixin.log(self, self._prefix + msg, facility, parent, *args, **kwargs) |
|---|