We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
500 Error with pylibmc+django+gunicorn
Hi, I'm integrating the Django cache in my app, if I run gunicorn without `ddtrace-run` everything works ok, but running with `ddtrace-run gunicorn app.wsgi:application --name app --workers 2 --timeout 30 --log-level=DEBUG --log-file=- --bind=unix:/projects/app/run/gunicorn.sock` I'm getting this error:

```
[2019-02-16 11:30:37 +0000] [138] [DEBUG] GET /api/accounts/me/
Internal Server Error: /api/accounts/me/
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/usr/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "/usr/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/lib/python3.6/site-packages/rest_framework/views.py", line 489, in dispatch
    response = self.handle_exception(exc)
  File "/usr/lib/python3.6/site-packages/ddtrace/contrib/django/restframework.py", line 26, in _traced_handle_exception
    return wrapped(*args, **kwargs)
  File "/usr/lib/python3.6/site-packages/rest_framework/views.py", line 449, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/usr/lib/python3.6/site-packages/rest_framework/views.py", line 486, in dispatch
    response = handler(request, *args, **kwargs)
  File "/usr/lib/python3.6/site-packages/rest_framework/generics.py", line 201, in get
    return self.list(request, *args, **kwargs)
  File "/usr/lib/python3.6/site-packages/django/utils/decorators.py", line 67, in _wrapper
    return bound_func(*args, **kwargs)
  File "/usr/lib/python3.6/site-packages/django/utils/decorators.py", line 141, in _wrapped_view
    result = middleware.process_request(request)
  File "/usr/lib/python3.6/site-packages/django/middleware/cache.py", line 133, in process_request
    cache_key = get_cache_key(request, self.key_prefix, 'GET', cache=self.cache)
  File "/usr/lib/python3.6/site-packages/django/utils/cache.py", line 362, in get_cache_key
    headerlist = cache.get(cache_key)
  File "/usr/lib/python3.6/site-packages/ddtrace/contrib/django/cache.py", line 67, in wrapped
    return method(*args, **kwargs)
  File "/usr/lib/python3.6/site-packages/django/core/cache/backends/memcached.py", line 79, in get
    val = self._cache.get(key)
  File "/usr/lib/python3.6/site-packages/ddtrace/contrib/pylibmc/client.py", line 72, in get
    return self._trace_cmd("get", *args, **kwargs)
  File "/usr/lib/python3.6/site-packages/ddtrace/contrib/pylibmc/client.py", line 115, in _trace_cmd
    with self._span(method_name) as span:
AttributeError: __enter__
```

My lib versions:
```
ddtrace==0.20.4
Django==1.11.12
gunicorn==19.4.5
pylibmc==1.6.0
```

And my settings:
```
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
        'LOCATION': os.environ.get('MEMCACHED_HOST', 'memcached:11211'),
    }
}
```
Any idea?

Thanks!

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ddtrace/contrib/pylibmc/client.py`
Content:
```
1 import random
2 
3 # 3p
4 from ddtrace.vendor.wrapt import ObjectProxy
5 import pylibmc
6 
7 # project
8 import ddtrace
9 from ...constants import ANALYTICS_SAMPLE_RATE_KEY
10 from ...ext import memcached
11 from ...ext import net
12 from ...internal.logger import get_logger
13 from ...settings import config
14 from .addrs import parse_addresses
15 
16 
17 # Original Client class
18 _Client = pylibmc.Client
19 
20 
21 log = get_logger(__name__)
22 
23 
24 class TracedClient(ObjectProxy):
25     """ TracedClient is a proxy for a pylibmc.Client that times it's network operations. """
26 
27     def __init__(self, client=None, service=memcached.SERVICE, tracer=None, *args, **kwargs):
28         """ Create a traced client that wraps the given memcached client.
29 
30         """
31         # The client instance/service/tracer attributes are kept for compatibility
32         # with the old interface: TracedClient(client=pylibmc.Client(['localhost:11211']))
33         # TODO(Benjamin): Remove these in favor of patching.
34         if not isinstance(client, _Client):
35             # We are in the patched situation, just pass down all arguments to the pylibmc.Client
36             # Note that, in that case, client isn't a real client (just the first argument)
37             client = _Client(client, *args, **kwargs)
38         else:
39             log.warning('TracedClient instantiation is deprecated and will be remove '
40                         'in future versions (0.6.0). Use patching instead (see the docs).')
41 
42         super(TracedClient, self).__init__(client)
43 
44         pin = ddtrace.Pin(service=service, tracer=tracer)
45         pin.onto(self)
46 
47         # attempt to collect the pool of urls this client talks to
48         try:
49             self._addresses = parse_addresses(client.addresses)
50         except Exception:
51             log.debug('error setting addresses', exc_info=True)
52 
53     def clone(self, *args, **kwargs):
54         # rewrap new connections.
55         cloned = self.__wrapped__.clone(*args, **kwargs)
56         traced_client = TracedClient(cloned)
57         pin = ddtrace.Pin.get_from(self)
58         if pin:
59             pin.clone().onto(traced_client)
60         return traced_client
61 
62     def get(self, *args, **kwargs):
63         return self._trace_cmd('get', *args, **kwargs)
64 
65     def set(self, *args, **kwargs):
66         return self._trace_cmd('set', *args, **kwargs)
67 
68     def delete(self, *args, **kwargs):
69         return self._trace_cmd('delete', *args, **kwargs)
70 
71     def gets(self, *args, **kwargs):
72         return self._trace_cmd('gets', *args, **kwargs)
73 
74     def touch(self, *args, **kwargs):
75         return self._trace_cmd('touch', *args, **kwargs)
76 
77     def cas(self, *args, **kwargs):
78         return self._trace_cmd('cas', *args, **kwargs)
79 
80     def incr(self, *args, **kwargs):
81         return self._trace_cmd('incr', *args, **kwargs)
82 
83     def decr(self, *args, **kwargs):
84         return self._trace_cmd('decr', *args, **kwargs)
85 
86     def append(self, *args, **kwargs):
87         return self._trace_cmd('append', *args, **kwargs)
88 
89     def prepend(self, *args, **kwargs):
90         return self._trace_cmd('prepend', *args, **kwargs)
91 
92     def get_multi(self, *args, **kwargs):
93         return self._trace_multi_cmd('get_multi', *args, **kwargs)
94 
95     def set_multi(self, *args, **kwargs):
96         return self._trace_multi_cmd('set_multi', *args, **kwargs)
97 
98     def delete_multi(self, *args, **kwargs):
99         return self._trace_multi_cmd('delete_multi', *args, **kwargs)
100 
101     def _trace_cmd(self, method_name, *args, **kwargs):
102         """ trace the execution of the method with the given name and will
103             patch the first arg.
104         """
105         method = getattr(self.__wrapped__, method_name)
106         with self._span(method_name) as span:
107 
108             if span and args:
109                 span.set_tag(memcached.QUERY, '%s %s' % (method_name, args[0]))
110 
111             return method(*args, **kwargs)
112 
113     def _trace_multi_cmd(self, method_name, *args, **kwargs):
114         """ trace the execution of the multi command with the given name. """
115         method = getattr(self.__wrapped__, method_name)
116         with self._span(method_name) as span:
117 
118             pre = kwargs.get('key_prefix')
119             if span and pre:
120                 span.set_tag(memcached.QUERY, '%s %s' % (method_name, pre))
121 
122             return method(*args, **kwargs)
123 
124     def _span(self, cmd_name):
125         """ Return a span timing the given command. """
126         pin = ddtrace.Pin.get_from(self)
127         if pin and pin.enabled():
128             span = pin.tracer.trace(
129                 'memcached.cmd',
130                 service=pin.service,
131                 resource=cmd_name,
132                 # TODO(Benjamin): set a better span type
133                 span_type='cache')
134 
135             try:
136                 self._tag_span(span)
137             except Exception:
138                 log.debug('error tagging span', exc_info=True)
139             return span
140 
141     def _tag_span(self, span):
142         # FIXME[matt] the host selection is buried in c code. we can't tell what it's actually
143         # using, so fallback to randomly choosing one. can we do better?
144         if self._addresses:
145             _, host, port, _ = random.choice(self._addresses)
146             span.set_meta(net.TARGET_HOST, host)
147             span.set_meta(net.TARGET_PORT, port)
148 
149         # set analytics sample rate
150         span.set_tag(
151             ANALYTICS_SAMPLE_RATE_KEY,
152             config.pylibmc.get_analytics_sample_rate()
153         )
154
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/ddtrace/contrib/pylibmc/client.py b/ddtrace/contrib/pylibmc/client.py
--- a/ddtrace/contrib/pylibmc/client.py
+++ b/ddtrace/contrib/pylibmc/client.py
@@ -1,3 +1,4 @@
+from contextlib import contextmanager
 import random
 
 # 3p
@@ -121,22 +122,28 @@
 
             return method(*args, **kwargs)
 
+    @contextmanager
+    def _no_span(self):
+        yield None
+
     def _span(self, cmd_name):
         """ Return a span timing the given command. """
         pin = ddtrace.Pin.get_from(self)
-        if pin and pin.enabled():
-            span = pin.tracer.trace(
-                'memcached.cmd',
-                service=pin.service,
-                resource=cmd_name,
-                # TODO(Benjamin): set a better span type
-                span_type='cache')
-
-            try:
-                self._tag_span(span)
-            except Exception:
-                log.debug('error tagging span', exc_info=True)
-            return span
+        if not pin or not pin.enabled():
+            return self._no_span()
+
+        span = pin.tracer.trace(
+            'memcached.cmd',
+            service=pin.service,
+            resource=cmd_name,
+            # TODO(Benjamin): set a better span type
+            span_type='cache')
+
+        try:
+            self._tag_span(span)
+        except Exception:
+            log.debug('error tagging span', exc_info=True)
+        return span
 
     def _tag_span(self, span):
         # FIXME[matt] the host selection is buried in c code. we can't tell what it's actually

{"golden_diff": "diff --git a/ddtrace/contrib/pylibmc/client.py b/ddtrace/contrib/pylibmc/client.py\n--- a/ddtrace/contrib/pylibmc/client.py\n+++ b/ddtrace/contrib/pylibmc/client.py\n@@ -1,3 +1,4 @@\n+from contextlib import contextmanager\n import random\n \n # 3p\n@@ -121,22 +122,28 @@\n \n             return method(*args, **kwargs)\n \n+    @contextmanager\n+    def _no_span(self):\n+        yield None\n+\n     def _span(self, cmd_name):\n         \"\"\" Return a span timing the given command. \"\"\"\n         pin = ddtrace.Pin.get_from(self)\n-        if pin and pin.enabled():\n-            span = pin.tracer.trace(\n-                'memcached.cmd',\n-                service=pin.service,\n-                resource=cmd_name,\n-                # TODO(Benjamin): set a better span type\n-                span_type='cache')\n-\n-            try:\n-                self._tag_span(span)\n-            except Exception:\n-                log.debug('error tagging span', exc_info=True)\n-            return span\n+        if not pin or not pin.enabled():\n+            return self._no_span()\n+\n+        span = pin.tracer.trace(\n+            'memcached.cmd',\n+            service=pin.service,\n+            resource=cmd_name,\n+            # TODO(Benjamin): set a better span type\n+            span_type='cache')\n+\n+        try:\n+            self._tag_span(span)\n+        except Exception:\n+            log.debug('error tagging span', exc_info=True)\n+        return span\n \n     def _tag_span(self, span):\n         # FIXME[matt] the host selection is buried in c code. we can't tell what it's actually\n", "issue": "500 Error with pylibmc+django+gunicorn\nHi, I'm integrating the Django cache in my app, if I run gunicorn without `ddtrace-run` everything works ok, but running with `ddtrace-run gunicorn app.wsgi:application --name app --workers 2 --timeout 30 --log-level=DEBUG --log-file=- --bind=unix:/projects/app/run/gunicorn.sock` I'm getting this error:\r\n\r\n```\r\n[2019-02-16 11:30:37 +0000] [138] [DEBUG] GET /api/accounts/me/\r\nInternal Server Error: /api/accounts/me/\r\nTraceback (most recent call last):\r\n  File \"/usr/lib/python3.6/site-packages/django/core/handlers/exception.py\", line 41, in inner\r\n    response = get_response(request)\r\n  File \"/usr/lib/python3.6/site-packages/django/core/handlers/base.py\", line 187, in _get_response\r\n    response = self.process_exception_by_middleware(e, request)\r\n  File \"/usr/lib/python3.6/site-packages/django/core/handlers/base.py\", line 185, in _get_response\r\n    response = wrapped_callback(request, *callback_args, **callback_kwargs)\r\n  File \"/usr/lib/python3.6/site-packages/django/views/decorators/csrf.py\", line 58, in wrapped_view\r\n    return view_func(*args, **kwargs)\r\n  File \"/usr/lib/python3.6/site-packages/django/views/generic/base.py\", line 68, in view\r\n    return self.dispatch(request, *args, **kwargs)\r\n  File \"/usr/lib/python3.6/site-packages/rest_framework/views.py\", line 489, in dispatch\r\n    response = self.handle_exception(exc)\r\n  File \"/usr/lib/python3.6/site-packages/ddtrace/contrib/django/restframework.py\", line 26, in _traced_handle_exception\r\n    return wrapped(*args, **kwargs)\r\n  File \"/usr/lib/python3.6/site-packages/rest_framework/views.py\", line 449, in handle_exception\r\n    self.raise_uncaught_exception(exc)\r\n  File \"/usr/lib/python3.6/site-packages/rest_framework/views.py\", line 486, in dispatch\r\n    response = handler(request, *args, **kwargs)\r\n  File \"/usr/lib/python3.6/site-packages/rest_framework/generics.py\", line 201, in get\r\n    return self.list(request, *args, **kwargs)\r\n  File \"/usr/lib/python3.6/site-packages/django/utils/decorators.py\", line 67, in _wrapper\r\n    return bound_func(*args, **kwargs)\r\n  File \"/usr/lib/python3.6/site-packages/django/utils/decorators.py\", line 141, in _wrapped_view\r\n    result = middleware.process_request(request)\r\n  File \"/usr/lib/python3.6/site-packages/django/middleware/cache.py\", line 133, in process_request\r\n    cache_key = get_cache_key(request, self.key_prefix, 'GET', cache=self.cache)\r\n  File \"/usr/lib/python3.6/site-packages/django/utils/cache.py\", line 362, in get_cache_key\r\n    headerlist = cache.get(cache_key)\r\n  File \"/usr/lib/python3.6/site-packages/ddtrace/contrib/django/cache.py\", line 67, in wrapped\r\n    return method(*args, **kwargs)\r\n  File \"/usr/lib/python3.6/site-packages/django/core/cache/backends/memcached.py\", line 79, in get\r\n    val = self._cache.get(key)\r\n  File \"/usr/lib/python3.6/site-packages/ddtrace/contrib/pylibmc/client.py\", line 72, in get\r\n    return self._trace_cmd(\"get\", *args, **kwargs)\r\n  File \"/usr/lib/python3.6/site-packages/ddtrace/contrib/pylibmc/client.py\", line 115, in _trace_cmd\r\n    with self._span(method_name) as span:\r\nAttributeError: __enter__\r\n```\r\n\r\nMy lib versions:\r\n```\r\nddtrace==0.20.4\r\nDjango==1.11.12\r\ngunicorn==19.4.5\r\npylibmc==1.6.0\r\n```\r\n\r\nAnd my settings:\r\n```\r\nCACHES = {\r\n    'default': {\r\n        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',\r\n        'LOCATION': os.environ.get('MEMCACHED_HOST', 'memcached:11211'),\r\n    }\r\n}\r\n```\r\nAny idea?\r\n\r\nThanks!\n", "before_files": [{"content": "import random\n\n# 3p\nfrom ddtrace.vendor.wrapt import ObjectProxy\nimport pylibmc\n\n# project\nimport ddtrace\nfrom ...constants import ANALYTICS_SAMPLE_RATE_KEY\nfrom ...ext import memcached\nfrom ...ext import net\nfrom ...internal.logger import get_logger\nfrom ...settings import config\nfrom .addrs import parse_addresses\n\n\n# Original Client class\n_Client = pylibmc.Client\n\n\nlog = get_logger(__name__)\n\n\nclass TracedClient(ObjectProxy):\n    \"\"\" TracedClient is a proxy for a pylibmc.Client that times it's network operations. \"\"\"\n\n    def __init__(self, client=None, service=memcached.SERVICE, tracer=None, *args, **kwargs):\n        \"\"\" Create a traced client that wraps the given memcached client.\n\n        \"\"\"\n        # The client instance/service/tracer attributes are kept for compatibility\n        # with the old interface: TracedClient(client=pylibmc.Client(['localhost:11211']))\n        # TODO(Benjamin): Remove these in favor of patching.\n        if not isinstance(client, _Client):\n            # We are in the patched situation, just pass down all arguments to the pylibmc.Client\n            # Note that, in that case, client isn't a real client (just the first argument)\n            client = _Client(client, *args, **kwargs)\n        else:\n            log.warning('TracedClient instantiation is deprecated and will be remove '\n                        'in future versions (0.6.0). Use patching instead (see the docs).')\n\n        super(TracedClient, self).__init__(client)\n\n        pin = ddtrace.Pin(service=service, tracer=tracer)\n        pin.onto(self)\n\n        # attempt to collect the pool of urls this client talks to\n        try:\n            self._addresses = parse_addresses(client.addresses)\n        except Exception:\n            log.debug('error setting addresses', exc_info=True)\n\n    def clone(self, *args, **kwargs):\n        # rewrap new connections.\n        cloned = self.__wrapped__.clone(*args, **kwargs)\n        traced_client = TracedClient(cloned)\n        pin = ddtrace.Pin.get_from(self)\n        if pin:\n            pin.clone().onto(traced_client)\n        return traced_client\n\n    def get(self, *args, **kwargs):\n        return self._trace_cmd('get', *args, **kwargs)\n\n    def set(self, *args, **kwargs):\n        return self._trace_cmd('set', *args, **kwargs)\n\n    def delete(self, *args, **kwargs):\n        return self._trace_cmd('delete', *args, **kwargs)\n\n    def gets(self, *args, **kwargs):\n        return self._trace_cmd('gets', *args, **kwargs)\n\n    def touch(self, *args, **kwargs):\n        return self._trace_cmd('touch', *args, **kwargs)\n\n    def cas(self, *args, **kwargs):\n        return self._trace_cmd('cas', *args, **kwargs)\n\n    def incr(self, *args, **kwargs):\n        return self._trace_cmd('incr', *args, **kwargs)\n\n    def decr(self, *args, **kwargs):\n        return self._trace_cmd('decr', *args, **kwargs)\n\n    def append(self, *args, **kwargs):\n        return self._trace_cmd('append', *args, **kwargs)\n\n    def prepend(self, *args, **kwargs):\n        return self._trace_cmd('prepend', *args, **kwargs)\n\n    def get_multi(self, *args, **kwargs):\n        return self._trace_multi_cmd('get_multi', *args, **kwargs)\n\n    def set_multi(self, *args, **kwargs):\n        return self._trace_multi_cmd('set_multi', *args, **kwargs)\n\n    def delete_multi(self, *args, **kwargs):\n        return self._trace_multi_cmd('delete_multi', *args, **kwargs)\n\n    def _trace_cmd(self, method_name, *args, **kwargs):\n        \"\"\" trace the execution of the method with the given name and will\n            patch the first arg.\n        \"\"\"\n        method = getattr(self.__wrapped__, method_name)\n        with self._span(method_name) as span:\n\n            if span and args:\n                span.set_tag(memcached.QUERY, '%s %s' % (method_name, args[0]))\n\n            return method(*args, **kwargs)\n\n    def _trace_multi_cmd(self, method_name, *args, **kwargs):\n        \"\"\" trace the execution of the multi command with the given name. \"\"\"\n        method = getattr(self.__wrapped__, method_name)\n        with self._span(method_name) as span:\n\n            pre = kwargs.get('key_prefix')\n            if span and pre:\n                span.set_tag(memcached.QUERY, '%s %s' % (method_name, pre))\n\n            return method(*args, **kwargs)\n\n    def _span(self, cmd_name):\n        \"\"\" Return a span timing the given command. \"\"\"\n        pin = ddtrace.Pin.get_from(self)\n        if pin and pin.enabled():\n            span = pin.tracer.trace(\n                'memcached.cmd',\n                service=pin.service,\n                resource=cmd_name,\n                # TODO(Benjamin): set a better span type\n                span_type='cache')\n\n            try:\n                self._tag_span(span)\n            except Exception:\n                log.debug('error tagging span', exc_info=True)\n            return span\n\n    def _tag_span(self, span):\n        # FIXME[matt] the host selection is buried in c code. we can't tell what it's actually\n        # using, so fallback to randomly choosing one. can we do better?\n        if self._addresses:\n            _, host, port, _ = random.choice(self._addresses)\n            span.set_meta(net.TARGET_HOST, host)\n            span.set_meta(net.TARGET_PORT, port)\n\n        # set analytics sample rate\n        span.set_tag(\n            ANALYTICS_SAMPLE_RATE_KEY,\n            config.pylibmc.get_analytics_sample_rate()\n        )\n", "path": "ddtrace/contrib/pylibmc/client.py"}], "after_files": [{"content": "from contextlib import contextmanager\nimport random\n\n# 3p\nfrom ddtrace.vendor.wrapt import ObjectProxy\nimport pylibmc\n\n# project\nimport ddtrace\nfrom ...constants import ANALYTICS_SAMPLE_RATE_KEY\nfrom ...ext import memcached\nfrom ...ext import net\nfrom ...internal.logger import get_logger\nfrom ...settings import config\nfrom .addrs import parse_addresses\n\n\n# Original Client class\n_Client = pylibmc.Client\n\n\nlog = get_logger(__name__)\n\n\nclass TracedClient(ObjectProxy):\n    \"\"\" TracedClient is a proxy for a pylibmc.Client that times it's network operations. \"\"\"\n\n    def __init__(self, client=None, service=memcached.SERVICE, tracer=None, *args, **kwargs):\n        \"\"\" Create a traced client that wraps the given memcached client.\n\n        \"\"\"\n        # The client instance/service/tracer attributes are kept for compatibility\n        # with the old interface: TracedClient(client=pylibmc.Client(['localhost:11211']))\n        # TODO(Benjamin): Remove these in favor of patching.\n        if not isinstance(client, _Client):\n            # We are in the patched situation, just pass down all arguments to the pylibmc.Client\n            # Note that, in that case, client isn't a real client (just the first argument)\n            client = _Client(client, *args, **kwargs)\n        else:\n            log.warning('TracedClient instantiation is deprecated and will be remove '\n                        'in future versions (0.6.0). Use patching instead (see the docs).')\n\n        super(TracedClient, self).__init__(client)\n\n        pin = ddtrace.Pin(service=service, tracer=tracer)\n        pin.onto(self)\n\n        # attempt to collect the pool of urls this client talks to\n        try:\n            self._addresses = parse_addresses(client.addresses)\n        except Exception:\n            log.debug('error setting addresses', exc_info=True)\n\n    def clone(self, *args, **kwargs):\n        # rewrap new connections.\n        cloned = self.__wrapped__.clone(*args, **kwargs)\n        traced_client = TracedClient(cloned)\n        pin = ddtrace.Pin.get_from(self)\n        if pin:\n            pin.clone().onto(traced_client)\n        return traced_client\n\n    def get(self, *args, **kwargs):\n        return self._trace_cmd('get', *args, **kwargs)\n\n    def set(self, *args, **kwargs):\n        return self._trace_cmd('set', *args, **kwargs)\n\n    def delete(self, *args, **kwargs):\n        return self._trace_cmd('delete', *args, **kwargs)\n\n    def gets(self, *args, **kwargs):\n        return self._trace_cmd('gets', *args, **kwargs)\n\n    def touch(self, *args, **kwargs):\n        return self._trace_cmd('touch', *args, **kwargs)\n\n    def cas(self, *args, **kwargs):\n        return self._trace_cmd('cas', *args, **kwargs)\n\n    def incr(self, *args, **kwargs):\n        return self._trace_cmd('incr', *args, **kwargs)\n\n    def decr(self, *args, **kwargs):\n        return self._trace_cmd('decr', *args, **kwargs)\n\n    def append(self, *args, **kwargs):\n        return self._trace_cmd('append', *args, **kwargs)\n\n    def prepend(self, *args, **kwargs):\n        return self._trace_cmd('prepend', *args, **kwargs)\n\n    def get_multi(self, *args, **kwargs):\n        return self._trace_multi_cmd('get_multi', *args, **kwargs)\n\n    def set_multi(self, *args, **kwargs):\n        return self._trace_multi_cmd('set_multi', *args, **kwargs)\n\n    def delete_multi(self, *args, **kwargs):\n        return self._trace_multi_cmd('delete_multi', *args, **kwargs)\n\n    def _trace_cmd(self, method_name, *args, **kwargs):\n        \"\"\" trace the execution of the method with the given name and will\n            patch the first arg.\n        \"\"\"\n        method = getattr(self.__wrapped__, method_name)\n        with self._span(method_name) as span:\n\n            if span and args:\n                span.set_tag(memcached.QUERY, '%s %s' % (method_name, args[0]))\n\n            return method(*args, **kwargs)\n\n    def _trace_multi_cmd(self, method_name, *args, **kwargs):\n        \"\"\" trace the execution of the multi command with the given name. \"\"\"\n        method = getattr(self.__wrapped__, method_name)\n        with self._span(method_name) as span:\n\n            pre = kwargs.get('key_prefix')\n            if span and pre:\n                span.set_tag(memcached.QUERY, '%s %s' % (method_name, pre))\n\n            return method(*args, **kwargs)\n\n    @contextmanager\n    def _no_span(self):\n        yield None\n\n    def _span(self, cmd_name):\n        \"\"\" Return a span timing the given command. \"\"\"\n        pin = ddtrace.Pin.get_from(self)\n        if not pin or not pin.enabled():\n            return self._no_span()\n\n        span = pin.tracer.trace(\n            'memcached.cmd',\n            service=pin.service,\n            resource=cmd_name,\n            # TODO(Benjamin): set a better span type\n            span_type='cache')\n\n        try:\n            self._tag_span(span)\n        except Exception:\n            log.debug('error tagging span', exc_info=True)\n        return span\n\n    def _tag_span(self, span):\n        # FIXME[matt] the host selection is buried in c code. we can't tell what it's actually\n        # using, so fallback to randomly choosing one. can we do better?\n        if self._addresses:\n            _, host, port, _ = random.choice(self._addresses)\n            span.set_meta(net.TARGET_HOST, host)\n            span.set_meta(net.TARGET_PORT, port)\n\n        # set analytics sample rate\n        span.set_tag(\n            ANALYTICS_SAMPLE_RATE_KEY,\n            config.pylibmc.get_analytics_sample_rate()\n        )\n", "path": "ddtrace/contrib/pylibmc/client.py"}]}