Repository: DataDog/dd-trace-py

Issue:
Exception raised with sizeof of some spans
With `master`:

```
Exception in thread AgentWriter:
Traceback (most recent call last):
  File "/opt/dogweb/pyenv/versions/2.7.12/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "/opt/dogweb/pyenv/versions/2.7.12/lib/python2.7/threading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/opt/dogweb/lib/python2.7/site-packages/ddtrace/_worker.py", line 67, in _target
    self.run_periodic()
  File "/opt/dogweb/lib/python2.7/site-packages/ddtrace/internal/writer.py", line 65, in flush_queue
    traces_queue_size = sum(map(sizeof.sizeof, traces))
  File "/opt/dogweb/lib/python2.7/site-packages/ddtrace/utils/sizeof.py", line 31, in sizeof
    return _sizeof(o)
  File "/opt/dogweb/lib/python2.7/site-packages/ddtrace/utils/sizeof.py", line 29, in _sizeof
    return sys.getsizeof(o) + sum(map(_sizeof, iter_object(o)))
  File "/opt/dogweb/lib/python2.7/site-packages/ddtrace/utils/sizeof.py", line 29, in _sizeof
    return sys.getsizeof(o) + sum(map(_sizeof, iter_object(o)))
  File "/opt/dogweb/lib/python2.7/site-packages/ddtrace/utils/sizeof.py", line 29, in _sizeof
    return sys.getsizeof(o) + sum(map(_sizeof, iter_object(o)))
  File "/opt/dogweb/lib/python2.7/site-packages/ddtrace/utils/sizeof.py", line 29, in _sizeof
    return sys.getsizeof(o) + sum(map(_sizeof, iter_object(o)))
  File "/opt/dogweb/lib/python2.7/site-packages/ddtrace/utils/sizeof.py", line 29, in _sizeof
    return sys.getsizeof(o) + sum(map(_sizeof, iter_object(o)))
  File "/opt/dogweb/lib/python2.7/site-packages/ddtrace/utils/sizeof.py", line 8, in <genexpr>
    return (getattr(o, slot) for slot in o.__slots__)
AttributeError: rate_limit
```

Might be an issue where the attribute is declared in `__slots__` but not set.


Discussion:
This is weird, the only two classes that have a `rate_limit` are `ddtrace.internal.rate_limiter.RateLimiter` and `ddtrace.internal.logger.DDLogger`

however, in both cases it should have been initialized.
I mean, the `__init__` of both of those classes set `self.rate_limit`

Resolving patch:
diff --git a/ddtrace/utils/sizeof.py b/ddtrace/utils/sizeof.py
--- a/ddtrace/utils/sizeof.py
+++ b/ddtrace/utils/sizeof.py
@@ -2,10 +2,16 @@
 import sys
 from itertools import chain
 
+_UNSET = object()
+
 
 def iter_object(o):
     if hasattr(o, '__slots__'):
-        return (getattr(o, slot) for slot in o.__slots__)
+        return (
+            s
+            for s in (getattr(o, slot, _UNSET) for slot in o.__slots__)
+            if s != _UNSET
+        )
     elif hasattr(o, '__dict__'):
         return list(o.__dict__.items())
     elif isinstance(o, dict):


Test patch:
diff --git a/tests/test_utils.py b/tests/test_utils.py
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -106,3 +106,25 @@ def test_sizeof():
     assert one_three > sizeof_list
     x = {'a': 1}
     assert sizeof.sizeof([x, x]) < sizeof.sizeof([{'a': 1}, {'a': 1}])
+
+
+class Slots(object):
+
+    __slots__ = ('foobar',)
+
+    def __init__(self):
+        self.foobar = 123
+
+
+def test_sizeof_slots():
+    assert sizeof.sizeof(Slots()) >= 1
+
+
+class BrokenSlots(object):
+
+    __slots__ = ('foobar',)
+
+
+def test_sizeof_broken_slots():
+    """https://github.com/DataDog/dd-trace-py/issues/1079"""
+    assert sizeof.sizeof(BrokenSlots()) >= 1