diff --git a/ddtrace/contrib/django/__init__.py b/ddtrace/contrib/django/__init__.py index 2550bb8e40f..42f42d0c8ba 100644 --- a/ddtrace/contrib/django/__init__.py +++ b/ddtrace/contrib/django/__init__.py @@ -1,109 +1,8 @@ +from ..util import require_modules +required_modules = ['django'] -import logging -from types import MethodType - - -# project -from ... import tracer -from ...ext import http, errors -from ...contrib import func_name -from .templates import patch_template -from .db import patch_db - -# 3p -from django.apps import apps - - -log = logging.getLogger(__name__) - - -class TraceMiddleware(object): - - def __init__(self): - # override if necessary (can't initialize though) - self.tracer = tracer - self.service = "django" - - try: - patch_template(self.tracer) - except Exception: - log.exception("error patching template class") - - def process_request(self, request): - try: - patch_db(self.tracer) # ensure that connections are always patched. - - span = self.tracer.trace( - "django.request", - service=self.service, - resource="unknown", # will be filled by process view - span_type=http.TYPE) - - span.set_tag(http.METHOD, request.method) - span.set_tag(http.URL, request.path) - _set_req_span(request, span) - except Exception: - log.exception("error tracing request") - - def process_view(self, request, view_func, *args, **kwargs): - span = _get_req_span(request) - if span: - span.resource = func_name(view_func) - - def process_response(self, request, response): - try: - span = _get_req_span(request) - if span: - span.set_tag(http.STATUS_CODE, response.status_code) - - if apps.is_installed("django.contrib.auth"): - span = _set_auth_tags(span, request) - - span.finish() - - except Exception: - log.exception("error tracing request") - finally: - return response - - def process_exception(self, request, exception): - try: - span = _get_req_span(request) - if span: - span.set_tag(http.STATUS_CODE, '500') - span.set_traceback() # will set the exception info - except Exception: - log.exception("error processing exception") - - - -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) - if not user: - return - - if hasattr(user, 'is_authenticated'): - span.set_tag('django.user.is_authenticated', user.is_authenticated()) - - uid = getattr(user, 'pk', None) - if uid: - span.set_tag('django.user.id', uid) - - uname = getattr(user, 'username', None) - if uname: - span.set_tag('django.user.name', uname) - - return span - - +with require_modules(required_modules) as missing_modules: + if not missing_modules: + from .middleware import TraceMiddleware + __all__ = ['TraceMiddleware'] diff --git a/ddtrace/contrib/django/db.py b/ddtrace/contrib/django/db.py index 60f4880ac36..4fcffdfe5f8 100644 --- a/ddtrace/contrib/django/db.py +++ b/ddtrace/contrib/django/db.py @@ -79,8 +79,8 @@ def __exit__(self, type, value, traceback): def _vendor_to_prefix(vendor): if not vendor: - return "db" # should this ever happen? + return "db" # should this ever happen? elif vendor == "sqlite": - return "sqlite3" # for consitency with the sqlite3 integration + return "sqlite3" # for consistency with the sqlite3 integration else: return vendor diff --git a/ddtrace/contrib/django/middleware.py b/ddtrace/contrib/django/middleware.py new file mode 100644 index 00000000000..bd25c209675 --- /dev/null +++ b/ddtrace/contrib/django/middleware.py @@ -0,0 +1,105 @@ +import logging + +# project +from ... import tracer +from ...ext import http +from ...contrib import func_name +from .templates import patch_template +from .db import patch_db + +# 3p +from django.apps import apps +from django.conf import settings + + +log = logging.getLogger(__name__) + + +class TraceMiddleware(object): + + def __init__(self): + # override if necessary (can't initialize though) + self.tracer = tracer + self.service = getattr(settings, 'DATADOG_SERVICE', 'django') + + try: + patch_template(self.tracer) + except Exception: + log.exception("error patching template class") + + def process_request(self, request): + try: + patch_db(self.tracer) # ensure that connections are always patched. + + span = self.tracer.trace( + "django.request", + service=self.service, + resource="unknown", # will be filled by process view + span_type=http.TYPE, + ) + + span.set_tag(http.METHOD, request.method) + span.set_tag(http.URL, request.path) + _set_req_span(request, span) + except Exception: + log.exception("error tracing request") + + def process_view(self, request, view_func, *args, **kwargs): + span = _get_req_span(request) + if span: + span.resource = func_name(view_func) + + def process_response(self, request, response): + try: + span = _get_req_span(request) + if span: + span.set_tag(http.STATUS_CODE, response.status_code) + + if apps.is_installed("django.contrib.auth"): + span = _set_auth_tags(span, request) + + span.finish() + + except Exception: + log.exception("error tracing request") + finally: + return response + + def process_exception(self, request, exception): + try: + span = _get_req_span(request) + if span: + span.set_tag(http.STATUS_CODE, '500') + span.set_traceback() # will set the exception info + except Exception: + log.exception("error processing exception") + + + +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) + if not user: + return + + if hasattr(user, 'is_authenticated'): + span.set_tag('django.user.is_authenticated', user.is_authenticated()) + + uid = getattr(user, 'pk', None) + if uid: + span.set_tag('django.user.id', uid) + + uname = getattr(user, 'username', None) + if uname: + span.set_tag('django.user.name', uname) + + return span diff --git a/ddtrace/contrib/django/templates.py b/ddtrace/contrib/django/templates.py index 68da1a62644..8fe8adb6dfd 100644 --- a/ddtrace/contrib/django/templates.py +++ b/ddtrace/contrib/django/templates.py @@ -7,7 +7,7 @@ import logging # project -from ...ext import http, errors +from ...ext import http # 3p from django.template import Template @@ -36,7 +36,8 @@ def traced_render(self, context): try: return Template._datadog_original_render(self, context) finally: - span.set_tag('django.template_name', context.template_name or 'unknown') + template_name = self.name or context.template_name or 'unknown' + span.resource = template_name + span.set_tag('django.template_name', template_name) Template.render = traced_render -