Skip to content

Commit

Permalink
Merge pull request #766 from DataDog/0.17.1-dev
Browse files Browse the repository at this point in the history
v0.17.1
  • Loading branch information
Kyle-Verhoog authored Dec 5, 2018
2 parents 6656236 + 74f5fb7 commit 47ecf1d
Show file tree
Hide file tree
Showing 63 changed files with 172 additions and 101 deletions.
2 changes: 1 addition & 1 deletion ddtrace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from .tracer import Tracer
from .settings import config

__version__ = '0.17.0'
__version__ = '0.17.1'

# a global tracer instance with integration settings
tracer = Tracer()
Expand Down
6 changes: 4 additions & 2 deletions ddtrace/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@
'compatibility_mode': False,
'fallback': 'v0.3'},
'v0.3': {'traces': '/v0.3/traces',
'services': '/v0.3/services',
'services': '/v0.3/services',
'compatibility_mode': False,
'fallback': 'v0.2'},
'v0.2': {'traces': '/v0.2/traces',
'services': '/v0.2/services',
'services': '/v0.2/services',
'compatibility_mode': True,
'fallback': None}}


def _parse_response_json(response):
"""
Parse the content of a response object, and return the right type,
Expand All @@ -48,6 +49,7 @@ def _parse_response_json(response):
except (ValueError, TypeError) as err:
log.debug("unable to load JSON '%s': %s" % (body, err))


class API(object):
"""
Send data to the trace agent using the HTTP protocol and JSON format
Expand Down
4 changes: 2 additions & 2 deletions ddtrace/commands/ddtrace_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
DATADOG_PRIORITY_SAMPLING=true|false : (default: false): enables Priority Sampling.
""" # noqa


def _ddtrace_root():
from ddtrace import __file__
return os.path.dirname(__file__)
Expand All @@ -46,8 +47,7 @@ def _add_bootstrap_to_pythonpath(bootstrap_dir):
python_path = os.environ.get('PYTHONPATH', '')

if python_path:
new_path = "%s%s%s" % (bootstrap_dir, os.path.pathsep,
os.environ['PYTHONPATH'])
new_path = "%s%s%s" % (bootstrap_dir, os.path.pathsep, os.environ['PYTHONPATH'])
os.environ['PYTHONPATH'] = new_path
else:
os.environ['PYTHONPATH'] = bootstrap_dir
Expand Down
3 changes: 2 additions & 1 deletion ddtrace/contrib/bottle/patch.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import os

from .trace import TracePlugin
Expand All @@ -7,6 +6,7 @@

import wrapt


def patch():
"""Patch the bottle.Bottle class
"""
Expand All @@ -16,6 +16,7 @@ def patch():
setattr(bottle, '_datadog_patch', True)
wrapt.wrap_function_wrapper('bottle', 'Bottle.__init__', traced_init)


def traced_init(wrapped, instance, args, kwargs):
wrapped(*args, **kwargs)

Expand Down
1 change: 1 addition & 0 deletions ddtrace/contrib/bottle/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

SPAN_TYPE = 'web'


class TracePlugin(object):
name = 'trace'
api = 2
Expand Down
20 changes: 17 additions & 3 deletions ddtrace/contrib/cassandra/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,26 @@
# Original connect connect function
_connect = cassandra.cluster.Cluster.connect


def patch():
""" patch will add tracing to the cassandra library. """
setattr(cassandra.cluster.Cluster, 'connect',
wrapt.FunctionWrapper(_connect, traced_connect))
Pin(service=SERVICE, app=SERVICE, app_type="db").onto(cassandra.cluster.Cluster)


def unpatch():
cassandra.cluster.Cluster.connect = _connect


def traced_connect(func, instance, args, kwargs):
session = func(*args, **kwargs)
if not isinstance(session.execute, wrapt.FunctionWrapper):
# FIXME[matt] this should probably be private.
setattr(session, 'execute_async', wrapt.FunctionWrapper(session.execute_async, traced_execute_async))
return session


def _close_span_on_success(result, future):
span = getattr(future, CURRENT_SPAN, None)
if not span:
Expand All @@ -54,11 +58,13 @@ def _close_span_on_success(result, future):
span.finish()
delattr(future, CURRENT_SPAN)


def traced_set_final_result(func, instance, args, kwargs):
result = args[0]
_close_span_on_success(result, instance)
return func(*args, **kwargs)


def _close_span_on_error(exc, future):
span = getattr(future, CURRENT_SPAN, None)
if not span:
Expand All @@ -76,11 +82,13 @@ def _close_span_on_error(exc, future):
span.finish()
delattr(future, CURRENT_SPAN)


def traced_set_final_exception(func, instance, args, kwargs):
exc = args[0]
_close_span_on_error(exc, instance)
return func(*args, **kwargs)


def traced_start_fetching_next_page(func, instance, args, kwargs):
has_more_pages = getattr(instance, 'has_more_pages', True)
if not has_more_pages:
Expand All @@ -106,11 +114,12 @@ def traced_start_fetching_next_page(func, instance, args, kwargs):
setattr(instance, CURRENT_SPAN, span)
try:
return func(*args, **kwargs)
except:
except Exception:
with span:
span.set_exc_info(*sys.exc_info())
raise


def traced_execute_async(func, instance, args, kwargs):
cluster = getattr(instance, 'cluster', None)
pin = Pin.get_from(cluster)
Expand Down Expand Up @@ -161,11 +170,12 @@ def traced_execute_async(func, instance, args, kwargs):
)
result.clear_callbacks()
return result
except:
except Exception:
with span:
span.set_exc_info(*sys.exc_info())
raise


def _start_span_and_set_tags(pin, query, session, cluster):
service = pin.service
tracer = pin.tracer
Expand All @@ -175,6 +185,7 @@ def _start_span_and_set_tags(pin, query, session, cluster):
span.set_tags(_extract_cluster_metas(cluster))
return span


def _extract_session_metas(session):
metas = {}

Expand All @@ -185,6 +196,7 @@ def _extract_session_metas(session):

return metas


def _extract_cluster_metas(cluster):
metas = {}
if deep_getattr(cluster, "metadata.cluster_name"):
Expand All @@ -194,6 +206,7 @@ def _extract_cluster_metas(cluster):

return metas


def _extract_result_metas(result):
metas = {}
if result is None:
Expand Down Expand Up @@ -230,6 +243,7 @@ def _extract_result_metas(result):

return metas


def _sanitize_query(span, query):
# TODO (aaditya): fix this hacky type check. we need it to avoid circular imports
t = type(query).__name__
Expand All @@ -250,7 +264,7 @@ def _sanitize_query(span, query):
elif t == 'str':
resource = query
else:
resource = 'unknown-query-type' # FIXME[matt] what else do to here?
resource = 'unknown-query-type' # FIXME[matt] what else do to here?

span.resource = stringify(resource)[:RESOURCE_MAX_LENGTH]

Expand Down
2 changes: 1 addition & 1 deletion ddtrace/contrib/celery/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
retrieve_span,
)


log = logging.getLogger(__name__)
SPAN_TYPE = 'worker'


def trace_prerun(*args, **kwargs):
# safe-guard to avoid crashes in case the signals API
# changes in Celery
Expand Down
1 change: 1 addition & 0 deletions ddtrace/contrib/celery/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def patch_task(task, pin=None):
patch_app(task.app)
return task


def unpatch_task(task):
"""Deprecated API. The new API uses signals that can be deactivated
via unpatch() API. This API is now a no-op implementation so it doesn't
Expand Down
1 change: 1 addition & 0 deletions ddtrace/contrib/dbapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ def rollback(self, *args, **kwargs):
span_name = '{}.{}'.format(self._self_datadog_name, 'rollback')
return self._trace_method(self.__wrapped__.rollback, span_name, {}, *args, **kwargs)


def _get_vendor(conn):
""" Return the vendor (e.g postgres, mysql) of the given
database.
Expand Down
5 changes: 3 additions & 2 deletions ddtrace/contrib/django/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ def _trace_operation(fn, method_name):
def wrapped(self, *args, **kwargs):
# get the original function method
method = getattr(self, DATADOG_NAMESPACE.format(method=method_name))
with tracer.trace('django.cache',
span_type=TYPE, service=cache_service_name) as span:
with tracer.trace('django.cache', span_type=TYPE, service=cache_service_name) as span:
# update the resource name and tag the cache backend
span.resource = _resource_from_cache_prefix(method_name, self)
cache_backend = '{}.{}'.format(self.__module__, self.__class__.__name__)
Expand Down Expand Up @@ -93,6 +92,7 @@ def _wrap_method(cls, method_name):
for method in TRACED_METHODS:
_wrap_method(cache, method)


def unpatch_method(cls, method_name):
method = getattr(cls, DATADOG_NAMESPACE.format(method=method_name), None)
if method is None:
Expand All @@ -101,6 +101,7 @@ def unpatch_method(cls, method_name):
setattr(cls, method_name, method)
delattr(cls, DATADOG_NAMESPACE.format(method=method_name))


def unpatch_cache():
cache_backends = set([cache['BACKEND'] for cache in django_settings.CACHES.values()])
for cache_module in cache_backends:
Expand Down
6 changes: 4 additions & 2 deletions ddtrace/contrib/django/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ def import_from_string(val, setting_name):
return getattr(module, class_name)
except (ImportError, AttributeError) as e:
msg = 'Could not import "{}" for setting "{}". {}: {}.'.format(
val, setting_name,
e.__class__.__name__, e
val,
setting_name,
e.__class__.__name__,
e,
)

raise ImportError(msg)
Expand Down
9 changes: 8 additions & 1 deletion ddtrace/contrib/django/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,31 @@ def get_middleware_insertion_point():
return MIDDLEWARE, middleware
return MIDDLEWARE_CLASSES, getattr(django_settings, MIDDLEWARE_CLASSES, None)


def insert_trace_middleware():
middleware_attribute, middleware = get_middleware_insertion_point()
if middleware is not None and TRACE_MIDDLEWARE not in set(middleware):
setattr(django_settings, middleware_attribute, type(middleware)((TRACE_MIDDLEWARE,)) + middleware)


def remove_trace_middleware():
_, middleware = get_middleware_insertion_point()
if middleware and TRACE_MIDDLEWARE in set(middleware):
middleware.remove(TRACE_MIDDLEWARE)


def insert_exception_middleware():
middleware_attribute, middleware = get_middleware_insertion_point()
if middleware is not None and EXCEPTION_MIDDLEWARE not in set(middleware):
setattr(django_settings, middleware_attribute, middleware + type(middleware)((EXCEPTION_MIDDLEWARE,)))


def remove_exception_middleware():
_, middleware = get_middleware_insertion_point()
if middleware and EXCEPTION_MIDDLEWARE in set(middleware):
middleware.remove(EXCEPTION_MIDDLEWARE)


class InstrumentationMixin(MiddlewareClass):
"""
Useful mixin base class for tracing middlewares
Expand All @@ -88,7 +93,7 @@ def process_exception(self, request, exception):
span = _get_req_span(request)
if span:
span.set_tag(http.STATUS_CODE, '500')
span.set_traceback() # will set the exception info
span.set_traceback() # will set the exception info
except Exception:
log.debug("error processing exception", exc_info=True)

Expand Down Expand Up @@ -172,10 +177,12 @@ def _get_req_span(request):
""" Return the datadog span from the given request. """
return getattr(request, '_datadog_request_span', None)


def _set_req_span(request, span):
""" Set the datadog span on the given request. """
return setattr(request, '_datadog_request_span', span)


def _set_auth_tags(span, request):
""" Patch any available auth tags from the request onto the span. """
user = getattr(request, 'user', None)
Expand Down
2 changes: 2 additions & 0 deletions ddtrace/contrib/django/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import django


def patch():
"""Patch the instrumented methods
"""
Expand All @@ -12,6 +13,7 @@ def patch():
_w = wrapt.wrap_function_wrapper
_w('django', 'setup', traced_setup)


def traced_setup(wrapped, instance, args, kwargs):
from django.conf import settings

Expand Down
3 changes: 2 additions & 1 deletion ddtrace/contrib/django/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
# 3p
from django.template import Template


log = logging.getLogger(__name__)

RENDER_ATTR = '_datadog_original_render'


def patch_template(tracer):
""" will patch django's template rendering function to include timing
and trace information.
Expand All @@ -42,6 +42,7 @@ def traced_render(self, context):

Template.render = traced_render


def unpatch_template():
render = getattr(Template, RENDER_ATTR, None)
if render is None:
Expand Down
1 change: 1 addition & 0 deletions ddtrace/contrib/elasticsearch/quantize.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
INDEX_REGEXP = re.compile(r'[0-9]{2,}')
INDEX_PLACEHOLDER = r'?'


def quantize(span):
"""Quantize an elasticsearch span
Expand Down
1 change: 1 addition & 0 deletions ddtrace/contrib/falcon/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def patch():
setattr(falcon, '_datadog_patch', True)
wrapt.wrap_function_wrapper('falcon', 'API.__init__', traced_init)


def traced_init(wrapped, instance, args, kwargs):
mw = kwargs.pop('middleware', [])
service = os.environ.get('DATADOG_SERVICE_NAME') or 'falcon'
Expand Down
2 changes: 2 additions & 0 deletions ddtrace/contrib/flask/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ def _finish_span(self, span, exception=None):
span.set_tag(http.METHOD, method)
span.finish()


def _set_error_on_span(span, exception):
# The 3 next lines might not be strictly required, since `set_traceback`
# also get the exception from the sys.exc_info (and fill the error meta).
Expand All @@ -188,6 +189,7 @@ def _set_error_on_span(span, exception):
# so attach the stack trace with `set_traceback`.
span.set_traceback()


def _patch_render(tracer):
""" patch flask's render template methods with the given tracer. """
# fall back to patching global method
Expand Down
Loading

0 comments on commit 47ecf1d

Please sign in to comment.