Repository: getsentry/sentry

Issue:
logging: __sentry__ isn't always callable
acdha@0af552b18d72594b183b18834ba7245a1ff5ade1 contains a trivial "fix" to avoid crashing when handling a value which has `__sentry__` set to `None` but I haven't had time to learn what `__sentry__` is supposed to do. `logging` is configured exactly as in the documentation, the code in question made a simple `logging.exception` call inside an `except` clause.

Here's a traceback - it's oddly formatted because the bug in question happened inside a django-tastypie resource handler:

```
Traceback (most recent call last):

  File "/Users/cadams/.virtualenvs/MyProject/lib/python2.6/site-packages/tastypie/resources.py", line 178, in wrapper
    return getattr(self,
     view)(request,
     *args,
     **kwargs)

  File "/Users/cadams/Projects/MyProject/MyProject/apps/api/resources.py", line 133, in dispatch_notes
    return self.dispatch('notes',
     request,
     **kwargs)

  File "/Users/cadams/.virtualenvs/MyProject/lib/python2.6/site-packages/tastypie/resources.py", line 350, in dispatch
    response = method(request,
     **kwargs)

  File "/Users/cadams/Projects/MyProject/MyProject/apps/api/resources.py", line 167, in post_notes
    bundle.data)

  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/logging/__init__.py", line 1419, in exception
    error(*((msg,
    )+args),
     **
    {
        'exc_info': 1
    }
    )

  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/logging/__init__.py", line 1412, in error
    root.error(*((msg,
    )+args),
     **kwargs)

  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/logging/__init__.py", line 1047, in error
    self._log(ERROR,
     msg,
     args,
     **kwargs)

  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/logging/__init__.py", line 1129, in _log
    self.handle(record)

  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/logging/__init__.py", line 1139, in handle
    self.callHandlers(record)

  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/logging/__init__.py", line 1176, in callHandlers
    hdlr.handle(record)

  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/logging/__init__.py", line 662, in handle
    self.emit(record)

  File "/Users/cadams/Projects/django-sentry/sentry/client/handlers.py", line 14, in emit
    get_client().create_from_record(record)

  File "/Users/cadams/Projects/django-sentry/sentry/client/base.py", line 157, in create_from_record
    return self.create_from_exception(record.exc_info,
     **kwargs)

  File "/Users/cadams/Projects/django-sentry/sentry/client/base.py", line 189, in create_from_exception
    frames = varmap(shorten,
     reporter.get_traceback_frames())

  File "/Users/cadams/Projects/django-sentry/sentry/helpers.py", line 58, in varmap
    return 
    [
        varmap(func,
         f) for f in var
    ]


  File "/Users/cadams/Projects/django-sentry/sentry/helpers.py", line 56, in varmap
    return dict((k,
     varmap(func,
     v)) for k,
     v in var.iteritems())

  File "/Users/cadams/Projects/django-sentry/sentry/helpers.py", line 56, in <genexpr>
    return dict((k,
     varmap(func,
     v)) for k,
     v in var.iteritems())

  File "/Users/cadams/Projects/django-sentry/sentry/helpers.py", line 58, in varmap
    return 
    [
        varmap(func,
         f) for f in var
    ]


  File "/Users/cadams/Projects/django-sentry/sentry/helpers.py", line 58, in varmap
    return 
    [
        varmap(func,
         f) for f in var
    ]


  File "/Users/cadams/Projects/django-sentry/sentry/helpers.py", line 60, in varmap
    return func(var)

  File "/Users/cadams/Projects/django-sentry/sentry/client/base.py", line 183, in shorten
    var = transform(var)

  File "/Users/cadams/Projects/django-sentry/sentry/helpers.py", line 80, in transform
    return value.__sentry__()

TypeError: 'NoneType' object is not callable
```



Discussion:

Resolving patch:
diff --git a/sentry/helpers.py b/sentry/helpers.py
--- a/sentry/helpers.py
+++ b/sentry/helpers.py
@@ -76,7 +76,7 @@ def transform(value):
             return str(value)
         except:
             return to_unicode(value)
-    elif hasattr(value, '__sentry__'):
+    elif callable(getattr(value, '__sentry__', None)):
         return value.__sentry__()
     elif not isinstance(value, (int, bool)) and value is not None:
         # XXX: we could do transform(repr(value)) here


Test patch: