Skip to content

Commit 665a1c1

Browse files
authored
Merge branch 'master' into improve-stacktraces
2 parents c40b31f + 1010db3 commit 665a1c1

File tree

8 files changed

+105
-16
lines changed

8 files changed

+105
-16
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
CHANGELOG
33
=========
44

5+
1.1.2
6+
=====
7+
* bugfix: Fixed an issue on PynamoDB patcher where the capture didn't handle client timeout.
8+
59
1.1.1
610
=====
711
* bugfix: Handle Aiohttp Exceptions as valid responses `PR59 <https://github.com/aws/aws-xray-sdk-python/pull/59>`_.

aws_xray_sdk/core/patcher.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
'sqlite3',
1212
'mysql',
1313
'httplib',
14+
'pymongo',
1415
)
1516

1617
_PATCHED_MODULES = set()

aws_xray_sdk/ext/pymongo/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright © 2018 Clarity Movement Co. All rights reserved.
2+
from .patch import patch
3+
4+
__all__ = ['patch']

aws_xray_sdk/ext/pymongo/patch.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright © 2018 Clarity Movement Co. All rights reserved.
2+
from pymongo import monitoring
3+
from aws_xray_sdk.core import xray_recorder
4+
5+
6+
class XrayCommandListener(monitoring.CommandListener):
7+
"""
8+
A listener that traces all pymongo db commands to AWS Xray.
9+
Creates a subsegment for each mongo db conmmand.
10+
11+
name: '[email protected]:27017'
12+
records all available information provided by pymongo,
13+
except for `command` and `reply`. They may contain business secrets.
14+
If you insist to record them, specify `record_full_documents=True`.
15+
"""
16+
17+
def __init__(self, record_full_documents):
18+
super(XrayCommandListener, self).__init__()
19+
self.record_full_documents = record_full_documents
20+
21+
def started(self, event):
22+
host, port = event.connection_id
23+
host_and_port_str = f'{host}:{port}'
24+
25+
subsegment = xray_recorder.begin_subsegment(
26+
f'{event.database_name}@{host_and_port_str}', 'remote')
27+
subsegment.put_annotation('mongodb_command_name', event.command_name)
28+
subsegment.put_annotation('mongodb_connection_id', host_and_port_str)
29+
subsegment.put_annotation('mongodb_database_name', event.database_name)
30+
subsegment.put_annotation('mongodb_operation_id', event.operation_id)
31+
subsegment.put_annotation('mongodb_request_id', event.request_id)
32+
if self.record_full_documents:
33+
subsegment.put_metadata('mongodb_command', event.command)
34+
35+
def succeeded(self, event):
36+
subsegment = xray_recorder.current_subsegment()
37+
subsegment.put_annotation('mongodb_duration_micros', event.duration_micros)
38+
if self.record_full_documents:
39+
subsegment.put_metadata('mongodb_reply', event.reply)
40+
xray_recorder.end_subsegment()
41+
42+
def failed(self, event):
43+
subsegment = xray_recorder.current_subsegment()
44+
subsegment.add_fault_flag()
45+
subsegment.put_annotation('mongodb_duration_micros', event.duration_micros)
46+
subsegment.put_metadata('failure', event.failure)
47+
xray_recorder.end_subsegment()
48+
49+
50+
def patch(record_full_documents=False):
51+
# ensure `patch()` is idempotent
52+
if hasattr(monitoring, '_xray_enabled'):
53+
return
54+
setattr(monitoring, '_xray_enabled', True)
55+
monitoring.register(XrayCommandListener(record_full_documents))

aws_xray_sdk/ext/pynamodb/patch.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,24 @@ def pynamodb_meta_processor(wrapped, instance, args, kwargs, return_value,
4242
exception, subsegment, stack):
4343
operation_name = args[0].headers['X-Amz-Target'].decode('utf-8').split('.')[1]
4444
region = args[0].url.split('.')[1]
45-
request_id = return_value.headers.get('x-amzn-RequestId')
4645

4746
aws_meta = {
4847
'operation': operation_name,
49-
'request_id': request_id,
5048
'region': region
5149
}
5250

51+
# in case of client timeout the return value will be empty
52+
if return_value is not None:
53+
aws_meta['request_id'] = return_value.headers.get('x-amzn-RequestId')
54+
subsegment.put_http_meta(http.STATUS, return_value.status_code)
55+
5356
if exception:
5457
subsegment.add_error_flag()
5558
subsegment.add_exception(exception, stack, True)
5659

57-
subsegment.put_http_meta(http.STATUS, return_value.status_code)
58-
60+
resp = return_value.json() if return_value else None
5961
_extract_whitelisted_params(subsegment.name, operation_name, aws_meta,
6062
[None, json.loads(args[0].body.decode('utf-8'))],
61-
None, return_value.json())
63+
None, resp)
6264

6365
subsegment.set_aws(aws_meta)

aws_xray_sdk/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
VERSION = '1.1.1'
1+
VERSION = '1.1.2'

tests/ext/pynamodb/test_pynamodb.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,29 @@ class Meta:
5454
assert aws_meta['table_name'] == 'mytable'
5555

5656

57+
def test_empty_response():
58+
from aws_xray_sdk.ext.pynamodb.patch import pynamodb_meta_processor
59+
subsegment = xray_recorder.begin_subsegment('test')
60+
61+
class TempReq(object):
62+
def __init__(self):
63+
self.headers = {'X-Amz-Target': 'ddb.ListTables'.encode('utf-8')}
64+
self.url = 'ddb.us-west-2'
65+
self.body = '{}'.encode('utf-8')
66+
67+
prepared_request = TempReq()
68+
args = [prepared_request]
69+
70+
pynamodb_meta_processor(wrapped=None, instance=None, args=args,
71+
kwargs=None, return_value=None,
72+
exception=None, subsegment=subsegment,
73+
stack=None)
74+
75+
aws_meta = subsegment.aws
76+
assert aws_meta['region'] == 'us-west-2'
77+
assert aws_meta['operation'] == 'ListTables'
78+
79+
5780
def test_only_dynamodb_calls_are_traced():
5881
"""Test only a single subsegment is created for other AWS services.
5982

tox.ini

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[tox]
22
envlist =
33
py{27,34,35,36}
4-
py36-aiohttp3
5-
py35-aiohttp3
4+
py36-aiohttp2
5+
py35-aiohttp2
66
coverage-report
77

88
skip_missing_interpreters = True
@@ -21,38 +21,38 @@ deps =
2121
django >= 1.10, <2.0
2222
pynamodb
2323
# Python3.5+ only deps
24-
py{35,36}: aiohttp >= 2.3.0,<3.0.0
24+
py{35,36}: aiohttp >= 3.0.0
2525
py{35,36}: pytest-aiohttp
2626
py{35,36}: aiobotocore
2727

2828
commands =
2929
py{27,34}: coverage run --source aws_xray_sdk -m py.test tests --ignore tests/ext/aiohttp --ignore tests/ext/aiobotocore --ignore tests/test_async_local_storage.py --ignore tests/test_async_recorder.py
30-
py{35,36}: coverage run --source aws_xray_sdk -m py.test tests --ignore tests/ext/aiohttp/test_client.py
30+
py{35,36}: coverage run --source aws_xray_sdk -m py.test tests
3131

3232
setenv =
3333
DJANGO_SETTINGS_MODULE = tests.ext.django.app.settings
3434
AWS_SECRET_ACCESS_KEY = fake_key
3535
AWS_ACCESS_KEY_ID=fake_id
3636

37-
[testenv:py35-aiohttp3]
37+
[testenv:py35-aiohttp2]
3838
deps =
3939
pytest > 3.0.0
40-
aiohttp >= 3.0.0
40+
aiohttp >= 2.3.0,<3.0.0
4141
pytest-aiohttp
4242
coverage
4343

4444
commands =
45-
py{35}: coverage run --source aws_xray_sdk -m py.test tests/ext/aiohttp
45+
py{35}: coverage run --source aws_xray_sdk -m py.test tests/ext/aiohttp --ignore tests/ext/aiohttp/test_client.py
4646

47-
[testenv:py36-aiohttp3]
47+
[testenv:py36-aiohttp2]
4848
deps =
4949
pytest > 3.0.0
50-
aiohttp >= 3.0.0
50+
aiohttp >= 2.3.0,<3.0.0
5151
pytest-aiohttp
5252
coverage
5353

5454
commands =
55-
py{36}: coverage run --source aws_xray_sdk -m py.test tests/ext/aiohttp
55+
py{36}: coverage run --source aws_xray_sdk -m py.test tests/ext/aiohttp --ignore tests/ext/aiohttp/test_client.py
5656

5757
[testenv:coverage-report]
5858
deps = coverage

0 commit comments

Comments
 (0)