Sorry for open a new issue, the following content is deprecated. Just ignore this issue.
Hi, all:
I use zeromq and logbook in my code and I found a bug in Logbook(maybe)
Reproduce
Here is a sample code:
receiver
from logbook.queues import ZeroMQSubscriber
sub = ZeroMQSubscriber('tcp://*:20002', multi=True)
print sub.recv()
Now receiver is waiting for message.
sender
import zmq
c = zmq.Context()
s = c.socket(zmq.PUSH)
s.connect('tcp://127.0.0.1:20002')
s.send_json({'test': 'test string'})
Then the exception raised in receiver:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/python/lib/python2.7/site-packages/logbook/queues.py", line 478, in recv
return LogRecord.from_dict(json.loads(rv))
File "/opt/python/lib/python2.7/site-packages/logbook/base.py", line 499, in from_dict
rv.update_from_dict(d)
File "/opt/python/lib/python2.7/site-packages/logbook/base.py", line 515, in update_from_dict
self.extra = defaultdict(lambda: u'', self.extra)
AttributeError: 'LogRecord' object has no attribute 'extra'
Analysis
So I got into the source code of Logbook, and found the problem.
queues.py
class ZeroMQSubscriber(SubscriberBase):
...
def recv(self, timeout=None):
...
return LogRecord.from_dict(json.loads(rv))
base.py
class LogRecord(object):
...
def __init__(self, channel, level, msg, args=None, kwargs=None,
exc_info=None, extra=None, frame=None, dispatcher=None,
frame_correction=0):
...
self.extra = defaultdict(lambda: u'', extra or ()) # ----------> Notice here
...
...
@classmethod
def from_dict(cls, d):
rv = object.__new__(cls) # ----------> here
rv.update_from_dict(d)
return rv
def update_from_dict(self, d):
...
self.extra = defaultdict(lambda: u'', self.extra) # ----------> and here
return self
the __new__ method does not do any initialization, it just returns an instance of LogRecord. self.extra is initialized in __init__ method and this method is not called by __new__. So the new instance we just created has no attritube extra.
Solutions maybe available
add rv.__init__(...) after rv = object.__new__(cls)
move extra out of __init__
override __new__ in class LogRecord. I think this is the best solution
Sorry for open a new issue, the following content is deprecated. Just ignore this issue.