-
Notifications
You must be signed in to change notification settings - Fork 395
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Boto / Botocore integration #209
Conversation
inspired from https://github.com/DataDog/botocore/pull/4/files, which has been tested on staging (see https://dd.datad0g.com/trace/view/177373499236743437)
…e-py into raphael/contrib-boto
… into raphael/contrib-boto
ddtrace/contrib/boto/patch.py
Outdated
|
||
# Original func returns a boto.connection.HPPResponse object | ||
result = original_func(*args, **kwargs) | ||
span.set_tag(http.STATUS_CODE, getattr(result, "status", 500)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's not have it default to 500. This is a meaningful error code that influences downstream stats collection and error reporting/alerting so we do not want to set it just because there's no better candidate. Instead it's fine to set the STATUS_CODE meta only when result.status
is available
ddtrace/contrib/boto/patch.py
Outdated
return result | ||
|
||
def get_region_name(region): | ||
if type(region) == str: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use isinstance
ddtrace/contrib/botocore/patch.py
Outdated
|
||
def patch(): | ||
# Checking for the version compatibility before patching | ||
if LooseVersion(pkg_resources.get_distribution("botocore").version) >= LooseVersion("1.4.51"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't think we want version matching code at this layer. instead let the patching function fail if a patchable isn't available - and patch_all
will respond to this gracefully
ddtrace/contrib/boto/patch.py
Outdated
|
||
# s3, lambda | ||
def patched_auth_request(original_func, instance, args, kwargs): | ||
tracer = getattr(instance, 'datadog_tracer', ddtrace.tracer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ddtrace/contrib/boto/patch.py
Outdated
|
||
with pin.tracer.trace('boto.command', service=DEFAULT_SERVICE, span_type=SPAN_TYPE) as span: | ||
|
||
# Original func returns a boto.connection.HPPResponse object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo HTTP
ddtrace/contrib/boto/patch.py
Outdated
# Original func returns a boto.connection.HPPResponse object | ||
result = original_func(*args, **kwargs) | ||
span.set_tag(http.STATUS_CODE, getattr(result, "status")) | ||
span.set_tag(http.METHOD, getattr(result, "_method", "unknown")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than set "unknown", it's ok to leave metadata unset in general when the needed attribute is not available
tests/contrib/boto/test.py
Outdated
|
||
# Testing resource and service | ||
eq_(span.service, "aws") | ||
eq_(span.resource, "boto.command") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not the correct resource. update this to do something similar to what botocore does.
and also make sure the check span.name
in this test
tests/contrib/boto/test.py
Outdated
eq_(span.get_tag(http.STATUS_CODE), "200") | ||
eq_(span.get_tag(http.METHOD), "GET") | ||
eq_(span.get_tag('aws.endpoint'), "lambda") | ||
eq_(span.get_tag('aws.region'), "us-east-2") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to check span.service
, span.resource
and span.name
in all these tests
s3.get_all_buckets() | ||
spans = writer.pop() | ||
assert spans | ||
span = spans[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does length of spans
matter here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one span is generated each time the function patched is called. For each request of the S3 client https://github.com/boto/boto/blob/develop/boto/s3/connection.py#L440, patched function gets called only once. On tests on our staging env there's a unique trace per s3 call. Yet in the mocking env I get 3 spans, I'll investigate on that
ddtrace/contrib/boto/patch.py
Outdated
operation_name = None | ||
for trace in reversed(traceback.extract_stack()): | ||
# Going backwards in the traceback till first call outside off ddtrace before make_request | ||
if "ddtrace" not in trace[0].split('/') and trace[2] != 'make_request': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code worries me. if there's no more reliable way to pull an operation_name, we should at least have a length check on the stacktrace before we try to index into it arbitrarily.
ddtrace/ext/aws.py
Outdated
if endpoint_name in BLACKLIST_ENDPOINT: | ||
return True | ||
else: | ||
return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just return endpoint_name in BLACKLIST_ENDPOINT
ddtrace/ext/aws.py
Outdated
else: | ||
return False | ||
|
||
def unpacking_args(args, args_name, traced_args_list): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this needs a docstring
# Botocore and Boto integrations
Summary
Adds botocore and boto contribs with testing units:
boto : s3/ec2/sqs/lambda
botocore : s3/ec2/sqs/lambda/kinesis
Boto3 relies on botocore so it will also be traced
Compatibility
boto >=2.29.0
botocore >= 1.4.51
TODOS
Miscellanous notes