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(object): |
---|
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) |
---|