getsentry / raven-python

Raven is the legacy Python client for Sentry (getsentry.com) — replaced by sentry-python
https://sentry.io
BSD 3-Clause "New" or "Revised" License
1.68k stars 657 forks source link

Sentry fall if there is a frozenset as key of dict in context #982

Open uchood opened 7 years ago

uchood commented 7 years ago

Sentry fall if there is a frozenset as key of dict in context I found this when near place of send error was dict with frozenset as key

proof 1

from  raven.utils.json import *
value = {frozenset([1,2,3]):4}
json.dumps(value, cls=BetterJSONEncoder)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/usr/lib/python2.7/json/__init__.py", line 251, in dumps
    sort_keys=sort_keys, **kw).encode(obj)
  File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
TypeError: keys must be a string

user case

/pycharm-2016.3.2/helpers/pydev/pydevconsole.py 39277 38925
PyDev console: starting.
import sys; print('Python %s on %s' % (sys.version, sys.platform))
import django; print('Django %s' % django.get_version())
sys.path.extend(['/home/uc/Projects/c2public', '/home/uc/Downloads/pycharm-2016.3.2/helpers/pycharm', '/home/uc/Downloads/pycharm-2016.3.2/helpers/pydev'])
if 'setup' in dir(django): django.setup()
import django_manage_shell; django_manage_shell.run("/home/uc/Projects/c2public")
Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
[GCC 5.4.0 20160609] on linux2
Django 1.9.9
log = logging.getLogger('django')
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'logging' is not defined
import logging
log = logging.getLogger('django')
log.error("test error 1")
ERROR test error 1
a = {frozenset([1,2,3]):4}
log.error("test error 2")
ERROR test error 2
log.error("test error 3", extra={'locals': locals()})
ERROR test error 3
Top level Sentry exception caught - failed creating log record
test error 3
Traceback (most recent call last):
  File "/home/uc/envs/c2public/local/lib/python2.7/site-packages/raven/handlers/logging.py", line 89, in emit
    return self._emit(record)
  File "/home/uc/envs/c2public/local/lib/python2.7/site-packages/raven/contrib/django/handlers.py", line 33, in _emit
    return super(SentryHandler, self)._emit(record, request=request)
  File "/home/uc/envs/c2public/local/lib/python2.7/site-packages/raven/handlers/logging.py", line 180, in _emit
    extra=extra, date=date, **kwargs)
  File "/home/uc/envs/c2public/local/lib/python2.7/site-packages/raven/contrib/django/client.py", line 284, in capture
    result = super(DjangoClient, self).capture(event_type, **kwargs)
  File "/home/uc/envs/c2public/local/lib/python2.7/site-packages/raven/base.py", line 610, in capture
    self.send(**data)
  File "/home/uc/envs/c2public/local/lib/python2.7/site-packages/raven/base.py", line 703, in send
    message = self.encode(data)
  File "/home/uc/envs/c2public/local/lib/python2.7/site-packages/raven/base.py", line 745, in encode
    return zlib.compress(json.dumps(data).encode('utf8'))
  File "/home/uc/envs/c2public/local/lib/python2.7/site-packages/raven/utils/json.py", line 51, in dumps
    return json.dumps(value, cls=BetterJSONEncoder, **kwargs)
  File "/usr/lib/python2.7/json/__init__.py", line 251, in dumps
    sort_keys=sort_keys, **kw).encode(obj)
  File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
TypeError: keys must be a string
mattrobenolt commented 7 years ago

Hmm, definitely seems bad. Lemme see if I can fix this today.

mattrobenolt commented 7 years ago

Oh. Wait. This is definitely going to be tricky. I'm not sure how we can reasonably translate this to JSON. Since in JSON, you can use a list as a key for an Object.

@mitsuhiko thoughts? The only thing I can think of is just using the repr() and force it to a string.

mattrobenolt commented 7 years ago

This seems to be what the internet suggests doing as well. Or storing as key/value pairs instead of a dictionary. Leaning towards just coercing the keys to strings with repr().

mitsuhiko commented 7 years ago

I thought we already repr() keys.