Skip to content

Commit 3abc5e3

Browse files
author
Emanuele Palazzetti
authored
Merge pull request #307 from palazzem/aiobotocore-response
[aiobotocore] update async with context manager
2 parents e164347 + 334ec31 commit 3abc5e3

File tree

3 files changed

+70
-10
lines changed

3 files changed

+70
-10
lines changed

ddtrace/contrib/aiobotocore/patch.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,19 @@ def unpatch():
3333
class WrappedClientResponseContentProxy(wrapt.ObjectProxy):
3434
def __init__(self, body, pin, parent_span):
3535
super(WrappedClientResponseContentProxy, self).__init__(body)
36-
self.__pin = pin
37-
self.__parent_span = parent_span
36+
self._self_pin = pin
37+
self._self_parent_span = parent_span
3838

3939
@asyncio.coroutine
4040
def read(self, *args, **kwargs):
4141
# async read that must be child of the parent span operation
42-
operation_name = '{}.read'.format(self.__parent_span.name)
42+
operation_name = '{}.read'.format(self._self_parent_span.name)
4343

44-
with self.__pin.tracer.start_span(operation_name, child_of=self.__parent_span) as span:
44+
with self._self_pin.tracer.start_span(operation_name, child_of=self._self_parent_span) as span:
4545
# inherit parent attributes
46-
span.resource = self.__parent_span.resource
47-
span.span_type = self.__parent_span.span_type
48-
span.meta = dict(self.__parent_span.meta)
46+
span.resource = self._self_parent_span.resource
47+
span.span_type = self._self_parent_span.span_type
48+
span.meta = dict(self._self_parent_span.meta)
4949

5050
result = yield from self.__wrapped__.read(*args, **kwargs) # noqa: E999
5151
span.set_tag('Length', len(result))
@@ -56,11 +56,14 @@ def read(self, *args, **kwargs):
5656
if PYTHON_VERSION >= (3, 5, 0):
5757
@asyncio.coroutine
5858
def __aenter__(self):
59-
return self.__wrapped__.__aenter__()
59+
# call the wrapped method but return the object proxy
60+
yield from self.__wrapped__.__aenter__()
61+
return self
6062

6163
@asyncio.coroutine
6264
def __aexit__(self, *args, **kwargs):
63-
return self.__wrapped__.__aexit__(*args, **kwargs)
65+
response = yield from self.__wrapped__.__aexit__(*args, **kwargs)
66+
return response
6467

6568

6669
def truncate_arg_value(value, max_len=1024):
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from nose.tools import eq_, ok_, assert_raises
2+
from botocore.errorfactory import ClientError
3+
4+
from ddtrace.contrib.aiobotocore.patch import patch, unpatch
5+
6+
from .utils import aiobotocore_client
7+
from ..asyncio.utils import AsyncioTestCase, mark_asyncio
8+
from ...test_tracer import get_dummy_tracer
9+
10+
11+
class AIOBotocoreTest(AsyncioTestCase):
12+
"""Botocore integration testsuite"""
13+
def setUp(self):
14+
super(AIOBotocoreTest, self).setUp()
15+
patch()
16+
self.tracer = get_dummy_tracer()
17+
18+
def tearDown(self):
19+
super(AIOBotocoreTest, self).tearDown()
20+
unpatch()
21+
self.tracer = None
22+
23+
@mark_asyncio
24+
async def test_response_context_manager(self):
25+
# the client should call the wrapped __aenter__ and return the
26+
# object proxy
27+
with aiobotocore_client('s3', self.tracer) as s3:
28+
# prepare S3 and flush traces if any
29+
await s3.create_bucket(Bucket='tracing')
30+
await s3.put_object(Bucket='tracing', Key='apm', Body=b'')
31+
self.tracer.writer.pop_traces()
32+
# `async with` under test
33+
response = await s3.get_object(Bucket='tracing', Key='apm')
34+
async with response['Body'] as stream:
35+
await stream.read()
36+
37+
traces = self.tracer.writer.pop_traces()
38+
eq_(len(traces), 2)
39+
eq_(len(traces[0]), 1)
40+
eq_(len(traces[1]), 1)
41+
42+
span = traces[0][0]
43+
eq_(span.get_tag('aws.operation'), 'GetObject')
44+
eq_(span.get_tag('http.status_code'), '200')
45+
eq_(span.service, 'aws.s3')
46+
eq_(span.resource, 's3.getobject')
47+
48+
read_span = traces[1][0]
49+
eq_(read_span.get_tag('aws.operation'), 'GetObject')
50+
eq_(read_span.get_tag('http.status_code'), '200')
51+
eq_(read_span.service, 'aws.s3')
52+
eq_(read_span.resource, 's3.getobject')
53+
eq_(read_span.name, 's3.command.read')
54+
# enforce parenting
55+
eq_(read_span.parent_id, span.span_id)
56+
eq_(read_span.trace_id, span.trace_id)

tox.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ commands =
210210
{py27}-pylons: nosetests {posargs} tests/contrib/pylons
211211
{py27,py34}-boto: nosetests {posargs} tests/contrib/boto
212212
{py27,py34}-botocore: nosetests {posargs} tests/contrib/botocore
213-
aiobotocore{02,03,04}: nosetests {posargs} tests/contrib/aiobotocore
213+
py{34}-aiobotocore{02,03,04}: nosetests {posargs} --exclude=".*(test_35).*" tests/contrib/aiobotocore
214+
py{35,36}-aiobotocore{02,03,04}: nosetests {posargs} tests/contrib/aiobotocore
214215
bottle{12}: nosetests {posargs} tests/contrib/bottle/test.py
215216
bottle-autopatch{12}: ddtrace-run nosetests {posargs} tests/contrib/bottle/test_autopatch.py
216217
cassandra{35,36,37,38}: nosetests {posargs} tests/contrib/cassandra

0 commit comments

Comments
 (0)