diff --git a/ddtrace/contrib/django/middleware.py b/ddtrace/contrib/django/middleware.py index 6e71d20079..8a0539a75b 100644 --- a/ddtrace/contrib/django/middleware.py +++ b/ddtrace/contrib/django/middleware.py @@ -17,33 +17,33 @@ try: from django.utils.deprecation import MiddlewareMixin + MiddlewareClass = MiddlewareMixin except ImportError: MiddlewareClass = object log = get_logger(__name__) -EXCEPTION_MIDDLEWARE = 'ddtrace.contrib.django.TraceExceptionMiddleware' -TRACE_MIDDLEWARE = 'ddtrace.contrib.django.TraceMiddleware' -MIDDLEWARE = 'MIDDLEWARE' -MIDDLEWARE_CLASSES = 'MIDDLEWARE_CLASSES' +EXCEPTION_MIDDLEWARE = "ddtrace.contrib.django.TraceExceptionMiddleware" +TRACE_MIDDLEWARE = "ddtrace.contrib.django.TraceMiddleware" +MIDDLEWARE = "MIDDLEWARE" +MIDDLEWARE_CLASSES = "MIDDLEWARE_CLASSES" # Default views list available from: # https://github.com/django/django/blob/38e2fdadfd9952e751deed662edf4c496d238f28/django/views/defaults.py # DEV: Django doesn't call `process_view` when falling back to one of these internal error handling views # DEV: We only use these names when `span.resource == 'unknown'` and we have one of these status codes _django_default_views = { - 400: 'django.views.defaults.bad_request', - 403: 'django.views.defaults.permission_denied', - 404: 'django.views.defaults.page_not_found', - 500: 'django.views.defaults.server_error', + 400: "django.views.defaults.bad_request", + 403: "django.views.defaults.permission_denied", + 404: "django.views.defaults.page_not_found", + 500: "django.views.defaults.server_error", } def _analytics_enabled(): return ( - (config.analytics_enabled and settings.ANALYTICS_ENABLED is not False) or - settings.ANALYTICS_ENABLED is True + (config.analytics_enabled and settings.ANALYTICS_ENABLED is not False) or settings.ANALYTICS_ENABLED is True ) and settings.ANALYTICS_SAMPLE_RATE is not None @@ -87,6 +87,7 @@ class InstrumentationMixin(MiddlewareClass): """ Useful mixin base class for tracing middlewares """ + def __init__(self, get_response=None): # disable the middleware if the tracer is not enabled # or if the auto instrumentation is disabled @@ -99,20 +100,22 @@ class TraceExceptionMiddleware(InstrumentationMixin): """ Middleware that traces exceptions raised """ + def process_exception(self, request, exception): try: span = _get_req_span(request) if span: - span.set_tag(http.STATUS_CODE, '500') + span.set_tag(http.STATUS_CODE, "500") span.set_traceback() # will set the exception info except Exception: - log.debug('error processing exception', exc_info=True) + log.debug("error processing exception", exc_info=True) class TraceMiddleware(InstrumentationMixin): """ Middleware that traces Django requests """ + def process_request(self, request): tracer = settings.TRACER if settings.DISTRIBUTED_TRACING: @@ -123,9 +126,9 @@ def process_request(self, request): tracer.context_provider.activate(context) try: span = tracer.trace( - 'django.request', + "django.request", service=settings.DEFAULT_SERVICE, - resource='unknown', # will be filled by process view + resource="unknown", # will be filled by process view span_type=SpanTypes.WEB, ) @@ -133,8 +136,7 @@ def process_request(self, request): # DEV: django is special case maintains separate configuration from config api if _analytics_enabled() and settings.ANALYTICS_SAMPLE_RATE is not None: span.set_tag( - ANALYTICS_SAMPLE_RATE_KEY, - settings.ANALYTICS_SAMPLE_RATE, + ANALYTICS_SAMPLE_RATE_KEY, settings.ANALYTICS_SAMPLE_RATE, ) # Set HTTP Request tags @@ -144,10 +146,10 @@ def process_request(self, request): if trace_query_string is None: trace_query_string = config.django.trace_query_string if trace_query_string: - span.set_tag(http.QUERY_STRING, request.META['QUERY_STRING']) + span.set_tag(http.QUERY_STRING, request.META["QUERY_STRING"]) _set_req_span(request, span) except Exception: - log.debug('error tracing request', exc_info=True) + log.debug("error tracing request", exc_info=True) def process_view(self, request, view_func, *args, **kwargs): span = _get_req_span(request) @@ -166,63 +168,63 @@ def process_response(self, request, response): # If `process_view` was not called, try to determine the correct `span.resource` to set # DEV: `process_view` won't get called if a middle `process_request` returns an HttpResponse # DEV: `process_view` won't get called when internal error handlers are used (e.g. for 404 responses) - if span.resource == 'unknown': + if span.resource == "unknown": try: # Attempt to lookup the view function from the url resolver # https://github.com/django/django/blob/38e2fdadfd9952e751deed662edf4c496d238f28/django/core/handlers/base.py#L104-L113 # noqa urlconf = None - if hasattr(request, 'urlconf'): + if hasattr(request, "urlconf"): urlconf = request.urlconf resolver = get_resolver(urlconf) # Try to resolve the Django view for handling this request - if getattr(request, 'request_match', None): + if getattr(request, "request_match", None): request_match = request.request_match else: # This may raise a `django.urls.exceptions.Resolver404` exception request_match = resolver.resolve(request.path_info) span.resource = func_name(request_match.func) except Exception: - log.debug('error determining request view function', exc_info=True) + log.debug("error determining request view function", exc_info=True) # If the view could not be found, try to set from a static list of # known internal error handler views - span.resource = _django_default_views.get(response.status_code, 'unknown') + span.resource = _django_default_views.get(response.status_code, "unknown") span.set_tag(http.STATUS_CODE, response.status_code) span = _set_auth_tags(span, request) span.finish() except Exception: - log.debug('error tracing request', exc_info=True) + log.debug("error tracing request", exc_info=True) finally: return response def _get_req_span(request): """ Return the datadog span from the given request. """ - return getattr(request, '_datadog_request_span', None) + 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) + 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) + user = getattr(request, "user", None) if not user: return span - if hasattr(user, 'is_authenticated'): - span.set_tag('django.user.is_authenticated', user_is_authenticated(user)) + if hasattr(user, "is_authenticated"): + span.set_tag("django.user.is_authenticated", user_is_authenticated(user)) - uid = getattr(user, 'pk', None) + uid = getattr(user, "pk", None) if uid: - span.set_tag('django.user.id', uid) + span.set_tag("django.user.id", uid) - uname = getattr(user, 'username', None) + uname = getattr(user, "username", None) if uname: - span.set_tag('django.user.name', uname) + span.set_tag("django.user.name", uname) return span diff --git a/ddtrace/contrib/grpc/client_interceptor.py b/ddtrace/contrib/grpc/client_interceptor.py index 5aa763dc0d..be1e66efa9 100644 --- a/ddtrace/contrib/grpc/client_interceptor.py +++ b/ddtrace/contrib/grpc/client_interceptor.py @@ -28,9 +28,9 @@ def create_client_interceptor(pin, host, port): def intercept_channel(wrapped, instance, args, kwargs): channel = args[0] interceptors = args[1:] - if isinstance(getattr(channel, '_interceptor', None), _ClientInterceptor): + if isinstance(getattr(channel, "_interceptor", None), _ClientInterceptor): dd_interceptor = channel._interceptor - base_channel = getattr(channel, '_channel', None) + base_channel = getattr(channel, "_channel", None) if base_channel: new_channel = wrapped(channel._channel, *interceptors) return grpc.intercept_channel(new_channel, dd_interceptor) @@ -39,10 +39,9 @@ def intercept_channel(wrapped, instance, args, kwargs): class _ClientCallDetails( - collections.namedtuple( - '_ClientCallDetails', - ('method', 'timeout', 'metadata', 'credentials')), - grpc.ClientCallDetails): + collections.namedtuple("_ClientCallDetails", ("method", "timeout", "metadata", "credentials")), + grpc.ClientCallDetails, +): pass @@ -74,9 +73,9 @@ def _handle_error(span, response_error, status_code): # exception() and traceback() methods if a computation has resulted in an # exception being raised if ( - not callable(getattr(response_error, 'cancelled', None)) and - not callable(getattr(response_error, 'exception', None)) and - not callable(getattr(response_error, 'traceback', None)) + not callable(getattr(response_error, "cancelled", None)) + and not callable(getattr(response_error, "exception", None)) + and not callable(getattr(response_error, "traceback", None)) ): return @@ -129,7 +128,7 @@ def __next__(self): raise except Exception: # DEV: added for safety though should not be reached since wrapped response - log.debug('unexpected non-grpc exception raised, closing open span', exc_info=True) + log.debug("unexpected non-grpc exception raised, closing open span", exc_info=True) self._span.set_traceback() self._span.finish() raise @@ -139,9 +138,11 @@ def next(self): class _ClientInterceptor( - grpc.UnaryUnaryClientInterceptor, grpc.UnaryStreamClientInterceptor, - grpc.StreamUnaryClientInterceptor, grpc.StreamStreamClientInterceptor): - + grpc.UnaryUnaryClientInterceptor, + grpc.UnaryStreamClientInterceptor, + grpc.StreamUnaryClientInterceptor, + grpc.StreamStreamClientInterceptor, +): def __init__(self, pin, host, port): self._pin = pin self._host = host @@ -151,10 +152,7 @@ def _intercept_client_call(self, method_kind, client_call_details): tracer = self._pin.tracer span = tracer.trace( - 'grpc', - span_type=SpanTypes.GRPC, - service=self._pin.service, - resource=client_call_details.method, + "grpc", span_type=SpanTypes.GRPC, service=self._pin.service, resource=client_call_details.method, ) # tags for method details @@ -189,19 +187,13 @@ def _intercept_client_call(self, method_kind, client_call_details): metadata.extend(headers.items()) client_call_details = _ClientCallDetails( - client_call_details.method, - client_call_details.timeout, - metadata, - client_call_details.credentials, + client_call_details.method, client_call_details.timeout, metadata, client_call_details.credentials, ) return span, client_call_details def intercept_unary_unary(self, continuation, client_call_details, request): - span, client_call_details = self._intercept_client_call( - constants.GRPC_METHOD_KIND_UNARY, - client_call_details, - ) + span, client_call_details = self._intercept_client_call(constants.GRPC_METHOD_KIND_UNARY, client_call_details,) try: response = continuation(client_call_details, request) _handle_response(span, response) @@ -216,8 +208,7 @@ def intercept_unary_unary(self, continuation, client_call_details, request): def intercept_unary_stream(self, continuation, client_call_details, request): span, client_call_details = self._intercept_client_call( - constants.GRPC_METHOD_KIND_SERVER_STREAMING, - client_call_details, + constants.GRPC_METHOD_KIND_SERVER_STREAMING, client_call_details, ) response_iterator = continuation(client_call_details, request) response_iterator = _WrappedResponseCallFuture(response_iterator, span) @@ -225,8 +216,7 @@ def intercept_unary_stream(self, continuation, client_call_details, request): def intercept_stream_unary(self, continuation, client_call_details, request_iterator): span, client_call_details = self._intercept_client_call( - constants.GRPC_METHOD_KIND_CLIENT_STREAMING, - client_call_details, + constants.GRPC_METHOD_KIND_CLIENT_STREAMING, client_call_details, ) try: response = continuation(client_call_details, request_iterator) @@ -242,8 +232,7 @@ def intercept_stream_unary(self, continuation, client_call_details, request_iter def intercept_stream_stream(self, continuation, client_call_details, request_iterator): span, client_call_details = self._intercept_client_call( - constants.GRPC_METHOD_KIND_BIDI_STREAMING, - client_call_details, + constants.GRPC_METHOD_KIND_BIDI_STREAMING, client_call_details, ) response_iterator = continuation(client_call_details, request_iterator) response_iterator = _WrappedResponseCallFuture(response_iterator, span) diff --git a/ddtrace/contrib/requests/connection.py b/ddtrace/contrib/requests/connection.py index e1536599e8..503d4a56c2 100644 --- a/ddtrace/contrib/requests/connection.py +++ b/ddtrace/contrib/requests/connection.py @@ -26,13 +26,11 @@ def _extract_service_name(session, span, hostname=None): Updated service name > parent service name > default to `requests`. """ cfg = config.get_from(session) - if cfg['split_by_domain'] and hostname: + if cfg["split_by_domain"] and hostname: return hostname - service_name = cfg['service_name'] - if (service_name == DEFAULT_SERVICE and - span._parent is not None and - span._parent.service is not None): + service_name = cfg["service_name"] + if service_name == DEFAULT_SERVICE and span._parent is not None and span._parent.service is not None: service_name = span._parent.service return service_name @@ -43,13 +41,13 @@ def _wrap_send(func, instance, args, kwargs): # and is ddtrace.tracer; it's used only inside our tests and can # be easily changed by providing a TracingTestCase that sets common # tracing functionalities. - tracer = getattr(instance, 'datadog_tracer', ddtrace.tracer) + tracer = getattr(instance, "datadog_tracer", ddtrace.tracer) # skip if tracing is not enabled if not tracer.enabled: return func(*args, **kwargs) - request = kwargs.get('request') or args[0] + request = kwargs.get("request") or args[0] if not request: return func(*args, **kwargs) @@ -57,32 +55,31 @@ def _wrap_send(func, instance, args, kwargs): parsed_uri = parse.urlparse(request.url) hostname = parsed_uri.hostname if parsed_uri.port: - hostname = '{}:{}'.format(hostname, parsed_uri.port) - sanitized_url = parse.urlunparse(( - parsed_uri.scheme, - parsed_uri.netloc, - parsed_uri.path, - parsed_uri.params, - None, # drop parsed_uri.query - parsed_uri.fragment - )) - - with tracer.trace('requests.request', span_type=SpanTypes.HTTP) as span: + hostname = "{}:{}".format(hostname, parsed_uri.port) + sanitized_url = parse.urlunparse( + ( + parsed_uri.scheme, + parsed_uri.netloc, + parsed_uri.path, + parsed_uri.params, + None, # drop parsed_uri.query + parsed_uri.fragment, + ) + ) + + with tracer.trace("requests.request", span_type=SpanTypes.HTTP) as span: # update the span service name before doing any action span.service = _extract_service_name(instance, span, hostname=hostname) # Configure trace search sample rate # DEV: analytics enabled on per-session basis cfg = config.get_from(instance) - analytics_enabled = cfg.get('analytics_enabled') + analytics_enabled = cfg.get("analytics_enabled") if analytics_enabled: - span.set_tag( - ANALYTICS_SAMPLE_RATE_KEY, - cfg.get('analytics_sample_rate', True) - ) + span.set_tag(ANALYTICS_SAMPLE_RATE_KEY, cfg.get("analytics_sample_rate", True)) # propagate distributed tracing headers - if cfg.get('distributed_tracing'): + if cfg.get("distributed_tracing"): propagator = HTTPPropagator() propagator.inject(span.context, request.headers) @@ -95,7 +92,7 @@ def _wrap_send(func, instance, args, kwargs): # Storing response headers in the span. Note that response.headers is not a dict, but an iterable # requests custom structure, that we convert to a dict - if hasattr(response, 'headers'): + if hasattr(response, "headers"): store_response_headers(dict(response.headers), span, config.requests) return response finally: @@ -111,7 +108,7 @@ def _wrap_send(func, instance, args, kwargs): # Storing response headers in the span. # Note that response.headers is not a dict, but an iterable # requests custom structure, that we convert to a dict - response_headers = dict(getattr(response, 'headers', {})) + response_headers = dict(getattr(response, "headers", {})) store_response_headers(response_headers, span, config.requests) except Exception: - log.debug('requests: error adding tags', exc_info=True) + log.debug("requests: error adding tags", exc_info=True) diff --git a/pyproject.toml b/pyproject.toml index 64561bce5e..8790a1e7ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,79 @@ exclude = ''' [^/]+\.py | commands/ | contrib/ + ( + aiobotocore + | aiohttp + | aiopg + | algoliasearch + | asyncio + | boto + | botocore + | bottle + | cassandra + | celery + | consul + | dbapi + | django/ + ( + __init__.py + | apps.py + | cache.py + | compat.py + | conf.py + | db.py + | patch.py + | restframework.py + | templates.py + | utils.py + ) + | dogpile_cache + | elasticsearch + | falcon + | flask + | flask_cache + | futures + | gevent + | grpc/ + ( + __init__.py + | constants.py + | patch.py + | server_interceptor.py + | utils.py + ) + | httplib + | jinja2 + | kombu + | logging + | mako + | molten + | mongoengine + | mysql + | mysqldb + | psycopg + | pylibmc + | pylons + | pymemcache + | pymongo + | pymysql + | pyramid + | redis + | rediscluster + | requests/ + ( + __init__.py + | constants.py + | legacy.py + | patch.py + | session.py + ) + | sqlalchemy + | sqlite3 + | tornado + | util.py + | vertica + ) | ext/ | http/ | opentracer/ @@ -26,5 +99,113 @@ exclude = ''' | vendor/ ) | tests/ + ( + base + | benchmark.py + | commands + | contrib/ + ( + aiobotocore + | aiohttp + | aiopg + | algoliasearch + | asyncio + | boto + | botocore + | bottle + | cassandra + | celery + | config.py + | consul + | dbapi + | django + | djangorestframework + | elasticsearch + | falcon + | flask + | flask_autopatch + | flask_cache + | futures + | gevent + | grpc + | httplib + | jinja2 + | kombu + | logging + | mako + | molten + | mongoengine + | mysql + | mysqldb + | patch.py + | psycopg + | pylibmc + | pylons + | pymemcache + | pymongo + | pymysql + | pyramid/ + ( + app/web.py + | __init__.py + | test_pyramid.py + | test_pyramid_autopatch.py + ) + | redis + | rediscluster + | requests + | requests_gevent + | sqlalchemy + | sqlite3 + | test_utils.py + | tornado + | vertica + ) + | ddtrace_run.py + | internal/ + ( + runtime/ + | test_context_manager.py + | test_hostname.py + | test_logger.py + | test_rate_limiter.py + ) + | memory.py + | opentracer/ + ( + conftest.py + | test_dd_compatibility.py + | test_span.py + | test_span_context.py + | test_tracer_asyncio.py + | test_tracer_gevent.py + | test_tracer_tornado.py + | test_utils.py + ) + | propagation/test_utils.py + | subprocesstest.py + | test_api.py + | test_compat.py + | test_context.py + | test_encoders.py + | test_filters.py + | test_global_config.py + | test_helpers.py + | test_hook.py + | test_instance_config.py + | test_integration.py + | test_payload.py + | test_pin.py + | test_sampler.py + | test_span.py + | test_tracer.py + | test_utils.py + | test_worker.py + | unit + | util.py + | utils + | vendor + | wait-for-services.py + ) ) -''' +''' \ No newline at end of file diff --git a/tests/contrib/dogpile_cache/test_tracing.py b/tests/contrib/dogpile_cache/test_tracing.py index 79e4259206..1548bf24e1 100644 --- a/tests/contrib/dogpile_cache/test_tracing.py +++ b/tests/contrib/dogpile_cache/test_tracing.py @@ -17,8 +17,8 @@ def region(tracer): patch() # Setup a simple dogpile cache region for testing. # The backend is trivial so we can use memory to simplify test setup. - test_region = dogpile.cache.make_region(name='TestRegion') - test_region.configure('dogpile.cache.memory') + test_region = dogpile.cache.make_region(name="TestRegion") + test_region.configure("dogpile.cache.memory") Pin.override(dogpile.cache, tracer=tracer) return test_region @@ -34,6 +34,7 @@ def single_cache(region): @region.cache_on_arguments() def fn(x): return x * 2 + return fn @@ -74,13 +75,13 @@ def test_traces_get_or_create(tracer, single_cache): spans = traces[0] assert len(spans) == 1 span = spans[0] - assert span.name == 'dogpile.cache' - assert span.resource == 'get_or_create' - assert span.meta['key'] == 'tests.contrib.dogpile_cache.test_tracing:fn|1' - assert span.meta['hit'] == 'False' - assert span.meta['expired'] == 'True' - assert span.meta['backend'] == 'MemoryBackend' - assert span.meta['region'] == 'TestRegion' + assert span.name == "dogpile.cache" + assert span.resource == "get_or_create" + assert span.meta["key"] == "tests.contrib.dogpile_cache.test_tracing:fn|1" + assert span.meta["hit"] == "False" + assert span.meta["expired"] == "True" + assert span.meta["backend"] == "MemoryBackend" + assert span.meta["region"] == "TestRegion" # Now the results should be cached. assert single_cache(1) == 2 @@ -89,13 +90,13 @@ def test_traces_get_or_create(tracer, single_cache): spans = traces[0] assert len(spans) == 1 span = spans[0] - assert span.name == 'dogpile.cache' - assert span.resource == 'get_or_create' - assert span.meta['key'] == 'tests.contrib.dogpile_cache.test_tracing:fn|1' - assert span.meta['hit'] == 'True' - assert span.meta['expired'] == 'False' - assert span.meta['backend'] == 'MemoryBackend' - assert span.meta['region'] == 'TestRegion' + assert span.name == "dogpile.cache" + assert span.resource == "get_or_create" + assert span.meta["key"] == "tests.contrib.dogpile_cache.test_tracing:fn|1" + assert span.meta["hit"] == "True" + assert span.meta["expired"] == "False" + assert span.meta["backend"] == "MemoryBackend" + assert span.meta["region"] == "TestRegion" def test_traces_get_or_create_multi(tracer, multi_cache): @@ -105,14 +106,13 @@ def test_traces_get_or_create_multi(tracer, multi_cache): spans = traces[0] assert len(spans) == 1 span = spans[0] - assert span.meta['keys'] == ( - "['tests.contrib.dogpile_cache.test_tracing:fn|2', " + - "'tests.contrib.dogpile_cache.test_tracing:fn|3']" + assert span.meta["keys"] == ( + "['tests.contrib.dogpile_cache.test_tracing:fn|2', " + "'tests.contrib.dogpile_cache.test_tracing:fn|3']" ) - assert span.meta['hit'] == 'False' - assert span.meta['expired'] == 'True' - assert span.meta['backend'] == 'MemoryBackend' - assert span.meta['region'] == 'TestRegion' + assert span.meta["hit"] == "False" + assert span.meta["expired"] == "True" + assert span.meta["backend"] == "MemoryBackend" + assert span.meta["region"] == "TestRegion" # Partial hit assert multi_cache(2, 4) == [4, 8] @@ -121,14 +121,13 @@ def test_traces_get_or_create_multi(tracer, multi_cache): spans = traces[0] assert len(spans) == 1 span = spans[0] - assert span.meta['keys'] == ( - "['tests.contrib.dogpile_cache.test_tracing:fn|2', " + - "'tests.contrib.dogpile_cache.test_tracing:fn|4']" + assert span.meta["keys"] == ( + "['tests.contrib.dogpile_cache.test_tracing:fn|2', " + "'tests.contrib.dogpile_cache.test_tracing:fn|4']" ) - assert span.meta['hit'] == 'False' - assert span.meta['expired'] == 'True' - assert span.meta['backend'] == 'MemoryBackend' - assert span.meta['region'] == 'TestRegion' + assert span.meta["hit"] == "False" + assert span.meta["expired"] == "True" + assert span.meta["backend"] == "MemoryBackend" + assert span.meta["region"] == "TestRegion" # Full hit assert multi_cache(2, 4) == [4, 8] @@ -137,14 +136,13 @@ def test_traces_get_or_create_multi(tracer, multi_cache): spans = traces[0] assert len(spans) == 1 span = spans[0] - assert span.meta['keys'] == ( - "['tests.contrib.dogpile_cache.test_tracing:fn|2', " + - "'tests.contrib.dogpile_cache.test_tracing:fn|4']" + assert span.meta["keys"] == ( + "['tests.contrib.dogpile_cache.test_tracing:fn|2', " + "'tests.contrib.dogpile_cache.test_tracing:fn|4']" ) - assert span.meta['hit'] == 'True' - assert span.meta['expired'] == 'False' - assert span.meta['backend'] == 'MemoryBackend' - assert span.meta['region'] == 'TestRegion' + assert span.meta["hit"] == "True" + assert span.meta["expired"] == "False" + assert span.meta["backend"] == "MemoryBackend" + assert span.meta["region"] == "TestRegion" class TestInnerFunctionCalls(object): @@ -156,8 +154,8 @@ def multi_cache(self, *x): def test_calls_inner_functions_correctly(self, region, mocker): """ This ensures the get_or_create behavior of dogpile is not altered. """ - spy_single_cache = mocker.spy(self, 'single_cache') - spy_multi_cache = mocker.spy(self, 'multi_cache') + spy_single_cache = mocker.spy(self, "single_cache") + spy_multi_cache = mocker.spy(self, "multi_cache") single_cache = region.cache_on_arguments()(self.single_cache) multi_cache = region.cache_multi_on_arguments()(self.multi_cache) diff --git a/tests/contrib/pyramid/utils.py b/tests/contrib/pyramid/utils.py index f3c97e1f54..3e9ee9dc81 100644 --- a/tests/contrib/pyramid/utils.py +++ b/tests/contrib/pyramid/utils.py @@ -19,6 +19,7 @@ class PyramidBase(BaseTracerTestCase): """Base Pyramid test application""" + def setUp(self): super(PyramidBase, self).setUp() self.create_app() @@ -27,7 +28,7 @@ def create_app(self, settings=None): # get default settings or use what is provided settings = settings or self.get_settings() # always set the dummy tracer as a default tracer - settings.update({'datadog_tracer': self.tracer}) + settings.update({"datadog_tracer": self.tracer}) app, renderer = create_app(settings, self.instrument) self.app = webtest.TestApp(app) @@ -42,37 +43,38 @@ def override_settings(self, settings): class PyramidTestCase(PyramidBase): """Pyramid TestCase that includes tests for automatic instrumentation""" + instrument = True def get_settings(self): return { - 'datadog_trace_service': 'foobar', + "datadog_trace_service": "foobar", } - def test_200(self, query_string=''): + def test_200(self, query_string=""): if query_string: - fqs = '?' + query_string + fqs = "?" + query_string else: - fqs = '' - res = self.app.get('/' + fqs, status=200) - assert b'idx' in res.body + fqs = "" + res = self.app.get("/" + fqs, status=200) + assert b"idx" in res.body writer = self.tracer.writer spans = writer.pop() assert len(spans) == 1 s = spans[0] - assert s.service == 'foobar' - assert s.resource == 'GET index' + assert s.service == "foobar" + assert s.resource == "GET index" assert s.error == 0 - assert s.span_type == 'web' - assert s.meta.get('http.method') == 'GET' + assert s.span_type == "web" + assert s.meta.get("http.method") == "GET" assert_span_http_status_code(s, 200) - assert s.meta.get(http.URL) == 'http://localhost/' + assert s.meta.get(http.URL) == "http://localhost/" if config.pyramid.trace_query_string: assert s.meta.get(http.QUERY_STRING) == query_string else: assert http.QUERY_STRING not in s.meta - assert s.meta.get('pyramid.route.name') == 'index' + assert s.meta.get("pyramid.route.name") == "index" # ensure services are set correctly services = writer.pop_services() @@ -80,11 +82,11 @@ def test_200(self, query_string=''): assert services == expected def test_200_query_string(self): - return self.test_200('foo=bar') + return self.test_200("foo=bar") def test_200_query_string_trace(self): - with self.override_http_config('pyramid', dict(trace_query_string=True)): - return self.test_200('foo=bar') + with self.override_http_config("pyramid", dict(trace_query_string=True)): + return self.test_200("foo=bar") def test_analytics_global_on_integration_default(self): """ @@ -93,12 +95,10 @@ def test_analytics_global_on_integration_default(self): We expect the root span to have the appropriate tag """ with self.override_global_config(dict(analytics_enabled=True)): - res = self.app.get('/', status=200) - assert b'idx' in res.body + res = self.app.get("/", status=200) + assert b"idx" in res.body - self.assert_structure( - dict(name='pyramid.request', metrics={ANALYTICS_SAMPLE_RATE_KEY: 1.0}), - ) + self.assert_structure(dict(name="pyramid.request", metrics={ANALYTICS_SAMPLE_RATE_KEY: 1.0}),) def test_analytics_global_on_integration_on(self): """ @@ -108,12 +108,10 @@ def test_analytics_global_on_integration_on(self): """ with self.override_global_config(dict(analytics_enabled=True)): self.override_settings(dict(datadog_analytics_enabled=True, datadog_analytics_sample_rate=0.5)) - res = self.app.get('/', status=200) - assert b'idx' in res.body + res = self.app.get("/", status=200) + assert b"idx" in res.body - self.assert_structure( - dict(name='pyramid.request', metrics={ANALYTICS_SAMPLE_RATE_KEY: 0.5}), - ) + self.assert_structure(dict(name="pyramid.request", metrics={ANALYTICS_SAMPLE_RATE_KEY: 0.5}),) def test_analytics_global_off_integration_default(self): """ @@ -122,8 +120,8 @@ def test_analytics_global_off_integration_default(self): We expect the root span to not include tag """ with self.override_global_config(dict(analytics_enabled=False)): - res = self.app.get('/', status=200) - assert b'idx' in res.body + res = self.app.get("/", status=200) + assert b"idx" in res.body root = self.get_root_span() self.assertIsNone(root.get_metric(ANALYTICS_SAMPLE_RATE_KEY)) @@ -136,61 +134,59 @@ def test_analytics_global_off_integration_on(self): """ with self.override_global_config(dict(analytics_enabled=False)): self.override_settings(dict(datadog_analytics_enabled=True, datadog_analytics_sample_rate=0.5)) - res = self.app.get('/', status=200) - assert b'idx' in res.body + res = self.app.get("/", status=200) + assert b"idx" in res.body - self.assert_structure( - dict(name='pyramid.request', metrics={ANALYTICS_SAMPLE_RATE_KEY: 0.5}), - ) + self.assert_structure(dict(name="pyramid.request", metrics={ANALYTICS_SAMPLE_RATE_KEY: 0.5}),) def test_404(self): - self.app.get('/404', status=404) + self.app.get("/404", status=404) writer = self.tracer.writer spans = writer.pop() assert len(spans) == 1 s = spans[0] - assert s.service == 'foobar' - assert s.resource == '404' + assert s.service == "foobar" + assert s.resource == "404" assert s.error == 0 - assert s.span_type == 'web' - assert s.meta.get('http.method') == 'GET' + assert s.span_type == "web" + assert s.meta.get("http.method") == "GET" assert_span_http_status_code(s, 404) - assert s.meta.get(http.URL) == 'http://localhost/404' + assert s.meta.get(http.URL) == "http://localhost/404" def test_302(self): - self.app.get('/redirect', status=302) + self.app.get("/redirect", status=302) writer = self.tracer.writer spans = writer.pop() assert len(spans) == 1 s = spans[0] - assert s.service == 'foobar' - assert s.resource == 'GET raise_redirect' + assert s.service == "foobar" + assert s.resource == "GET raise_redirect" assert s.error == 0 - assert s.span_type == 'web' - assert s.meta.get('http.method') == 'GET' + assert s.span_type == "web" + assert s.meta.get("http.method") == "GET" assert_span_http_status_code(s, 302) - assert s.meta.get(http.URL) == 'http://localhost/redirect' + assert s.meta.get(http.URL) == "http://localhost/redirect" def test_204(self): - self.app.get('/nocontent', status=204) + self.app.get("/nocontent", status=204) writer = self.tracer.writer spans = writer.pop() assert len(spans) == 1 s = spans[0] - assert s.service == 'foobar' - assert s.resource == 'GET raise_no_content' + assert s.service == "foobar" + assert s.resource == "GET raise_no_content" assert s.error == 0 - assert s.span_type == 'web' - assert s.meta.get('http.method') == 'GET' + assert s.span_type == "web" + assert s.meta.get("http.method") == "GET" assert_span_http_status_code(s, 204) - assert s.meta.get(http.URL) == 'http://localhost/nocontent' + assert s.meta.get(http.URL) == "http://localhost/nocontent" def test_exception(self): try: - self.app.get('/exception', status=500) + self.app.get("/exception", status=500) except ZeroDivisionError: pass @@ -198,146 +194,145 @@ def test_exception(self): spans = writer.pop() assert len(spans) == 1 s = spans[0] - assert s.service == 'foobar' - assert s.resource == 'GET exception' + assert s.service == "foobar" + assert s.resource == "GET exception" assert s.error == 1 - assert s.span_type == 'web' - assert s.meta.get('http.method') == 'GET' + assert s.span_type == "web" + assert s.meta.get("http.method") == "GET" assert_span_http_status_code(s, 500) - assert s.meta.get(http.URL) == 'http://localhost/exception' - assert s.meta.get('pyramid.route.name') == 'exception' + assert s.meta.get(http.URL) == "http://localhost/exception" + assert s.meta.get("pyramid.route.name") == "exception" def test_500(self): - self.app.get('/error', status=500) + self.app.get("/error", status=500) writer = self.tracer.writer spans = writer.pop() assert len(spans) == 1 s = spans[0] - assert s.service == 'foobar' - assert s.resource == 'GET error' + assert s.service == "foobar" + assert s.resource == "GET error" assert s.error == 1 - assert s.span_type == 'web' - assert s.meta.get('http.method') == 'GET' + assert s.span_type == "web" + assert s.meta.get("http.method") == "GET" assert_span_http_status_code(s, 500) - assert s.meta.get(http.URL) == 'http://localhost/error' - assert s.meta.get('pyramid.route.name') == 'error' + assert s.meta.get(http.URL) == "http://localhost/error" + assert s.meta.get("pyramid.route.name") == "error" assert type(s.error) == int def test_json(self): - res = self.app.get('/json', status=200) + res = self.app.get("/json", status=200) parsed = json.loads(compat.to_unicode(res.body)) - assert parsed == {'a': 1} + assert parsed == {"a": 1} writer = self.tracer.writer spans = writer.pop() assert len(spans) == 2 spans_by_name = {s.name: s for s in spans} - s = spans_by_name['pyramid.request'] - assert s.service == 'foobar' - assert s.resource == 'GET json' + s = spans_by_name["pyramid.request"] + assert s.service == "foobar" + assert s.resource == "GET json" assert s.error == 0 - assert s.span_type == 'web' - assert s.meta.get('http.method') == 'GET' + assert s.span_type == "web" + assert s.meta.get("http.method") == "GET" assert_span_http_status_code(s, 200) - assert s.meta.get(http.URL) == 'http://localhost/json' - assert s.meta.get('pyramid.route.name') == 'json' + assert s.meta.get(http.URL) == "http://localhost/json" + assert s.meta.get("pyramid.route.name") == "json" - s = spans_by_name['pyramid.render'] - assert s.service == 'foobar' + s = spans_by_name["pyramid.render"] + assert s.service == "foobar" assert s.error == 0 - assert s.span_type == 'template' + assert s.span_type == "template" def test_renderer(self): - self.app.get('/renderer', status=200) - assert self.renderer._received['request'] is not None + self.app.get("/renderer", status=200) + assert self.renderer._received["request"] is not None - self.renderer.assert_(foo='bar') + self.renderer.assert_(foo="bar") writer = self.tracer.writer spans = writer.pop() assert len(spans) == 2 spans_by_name = {s.name: s for s in spans} - s = spans_by_name['pyramid.request'] - assert s.service == 'foobar' - assert s.resource == 'GET renderer' + s = spans_by_name["pyramid.request"] + assert s.service == "foobar" + assert s.resource == "GET renderer" assert s.error == 0 - assert s.span_type == 'web' - assert s.meta.get('http.method') == 'GET' + assert s.span_type == "web" + assert s.meta.get("http.method") == "GET" assert_span_http_status_code(s, 200) - assert s.meta.get(http.URL) == 'http://localhost/renderer' - assert s.meta.get('pyramid.route.name') == 'renderer' + assert s.meta.get(http.URL) == "http://localhost/renderer" + assert s.meta.get("pyramid.route.name") == "renderer" - s = spans_by_name['pyramid.render'] - assert s.service == 'foobar' + s = spans_by_name["pyramid.render"] + assert s.service == "foobar" assert s.error == 0 - assert s.span_type == 'template' + assert s.span_type == "template" def test_http_exception_response(self): with pytest.raises(HTTPException): - self.app.get('/404/raise_exception', status=404) + self.app.get("/404/raise_exception", status=404) writer = self.tracer.writer spans = writer.pop() assert len(spans) == 1 s = spans[0] - assert s.service == 'foobar' - assert s.resource == '404' + assert s.service == "foobar" + assert s.resource == "404" assert s.error == 1 - assert s.span_type == 'web' - assert s.meta.get('http.method') == 'GET' + assert s.span_type == "web" + assert s.meta.get("http.method") == "GET" assert_span_http_status_code(s, 404) - assert s.meta.get(http.URL) == 'http://localhost/404/raise_exception' + assert s.meta.get(http.URL) == "http://localhost/404/raise_exception" def test_insert_tween_if_needed_already_set(self): - settings = {'pyramid.tweens': 'ddtrace.contrib.pyramid:trace_tween_factory'} + settings = {"pyramid.tweens": "ddtrace.contrib.pyramid:trace_tween_factory"} insert_tween_if_needed(settings) - assert settings['pyramid.tweens'] == 'ddtrace.contrib.pyramid:trace_tween_factory' + assert settings["pyramid.tweens"] == "ddtrace.contrib.pyramid:trace_tween_factory" def test_insert_tween_if_needed_none(self): - settings = {'pyramid.tweens': ''} + settings = {"pyramid.tweens": ""} insert_tween_if_needed(settings) - assert settings['pyramid.tweens'] == '' + assert settings["pyramid.tweens"] == "" def test_insert_tween_if_needed_excview(self): - settings = {'pyramid.tweens': 'pyramid.tweens.excview_tween_factory'} + settings = {"pyramid.tweens": "pyramid.tweens.excview_tween_factory"} insert_tween_if_needed(settings) assert ( - settings['pyramid.tweens'] == - 'ddtrace.contrib.pyramid:trace_tween_factory\npyramid.tweens.excview_tween_factory' + settings["pyramid.tweens"] + == "ddtrace.contrib.pyramid:trace_tween_factory\npyramid.tweens.excview_tween_factory" ) def test_insert_tween_if_needed_excview_and_other(self): - settings = {'pyramid.tweens': 'a.first.tween\npyramid.tweens.excview_tween_factory\na.last.tween\n'} + settings = {"pyramid.tweens": "a.first.tween\npyramid.tweens.excview_tween_factory\na.last.tween\n"} insert_tween_if_needed(settings) assert ( - settings['pyramid.tweens'] == - 'a.first.tween\n' - 'ddtrace.contrib.pyramid:trace_tween_factory\n' - 'pyramid.tweens.excview_tween_factory\n' - 'a.last.tween\n') + settings["pyramid.tweens"] == "a.first.tween\n" + "ddtrace.contrib.pyramid:trace_tween_factory\n" + "pyramid.tweens.excview_tween_factory\n" + "a.last.tween\n" + ) def test_insert_tween_if_needed_others(self): - settings = {'pyramid.tweens': 'a.random.tween\nand.another.one'} + settings = {"pyramid.tweens": "a.random.tween\nand.another.one"} insert_tween_if_needed(settings) assert ( - settings['pyramid.tweens'] == - 'a.random.tween\nand.another.one\nddtrace.contrib.pyramid:trace_tween_factory' + settings["pyramid.tweens"] == "a.random.tween\nand.another.one\nddtrace.contrib.pyramid:trace_tween_factory" ) def test_include_conflicts(self): # test that includes do not create conflicts - self.override_settings({'pyramid.includes': 'tests.contrib.pyramid.test_pyramid'}) - self.app.get('/404', status=404) + self.override_settings({"pyramid.includes": "tests.contrib.pyramid.test_pyramid"}) + self.app.get("/404", status=404) spans = self.tracer.writer.pop() assert len(spans) == 1 def test_200_ot(self): """OpenTracing version of test_200.""" - ot_tracer = init_tracer('pyramid_svc', self.tracer) + ot_tracer = init_tracer("pyramid_svc", self.tracer) - with ot_tracer.start_active_span('pyramid_get'): - res = self.app.get('/', status=200) - assert b'idx' in res.body + with ot_tracer.start_active_span("pyramid_get"): + res = self.app.get("/", status=200) + assert b"idx" in res.body writer = self.tracer.writer spans = writer.pop() @@ -349,14 +344,14 @@ def test_200_ot(self): assert ot_span.parent_id is None assert dd_span.parent_id == ot_span.span_id - assert ot_span.name == 'pyramid_get' - assert ot_span.service == 'pyramid_svc' + assert ot_span.name == "pyramid_get" + assert ot_span.service == "pyramid_svc" - assert dd_span.service == 'foobar' - assert dd_span.resource == 'GET index' + assert dd_span.service == "foobar" + assert dd_span.resource == "GET index" assert dd_span.error == 0 - assert dd_span.span_type == 'web' - assert dd_span.meta.get('http.method') == 'GET' + assert dd_span.span_type == "web" + assert dd_span.meta.get("http.method") == "GET" assert_span_http_status_code(dd_span, 200) - assert dd_span.meta.get(http.URL) == 'http://localhost/' - assert dd_span.meta.get('pyramid.route.name') == 'index' + assert dd_span.meta.get(http.URL) == "http://localhost/" + assert dd_span.meta.get("pyramid.route.name") == "index" diff --git a/tests/internal/test_writer.py b/tests/internal/test_writer.py index 3f28dae1ec..4ee0087dfc 100644 --- a/tests/internal/test_writer.py +++ b/tests/internal/test_writer.py @@ -10,7 +10,7 @@ from ..base import BaseTestCase -class RemoveAllFilter(): +class RemoveAllFilter: def __init__(self): self.filtered_traces = 0 @@ -19,7 +19,7 @@ def process_trace(self, trace): return None -class KeepAllFilter(): +class KeepAllFilter: def __init__(self): self.filtered_traces = 0 @@ -28,7 +28,7 @@ def process_trace(self, trace): return trace -class AddTagFilter(): +class AddTagFilter: def __init__(self, tag_name): self.tag_name = tag_name self.filtered_traces = 0 @@ -36,14 +36,14 @@ def __init__(self, tag_name): def process_trace(self, trace): self.filtered_traces += 1 for span in trace: - span.set_tag(self.tag_name, 'A value') + span.set_tag(self.tag_name, "A value") return trace class DummyAPI(API): def __init__(self): # Call API.__init__ to setup required properties - super(DummyAPI, self).__init__(hostname='localhost', port=8126) + super(DummyAPI, self).__init__(hostname="localhost", port=8126) self.traces = [] @@ -58,10 +58,9 @@ def send_traces(self, traces): class FailingAPI(object): - @staticmethod def send_traces(traces): - return [Exception('oops')] + return [Exception("oops")] class AgentWriterTests(BaseTestCase): @@ -75,10 +74,9 @@ def create_worker(self, filters=None, api_class=DummyAPI, enable_stats=False): self.api = api_class() worker.api = self.api for i in range(self.N_TRACES): - worker.write([ - Span(tracer=None, name='name', trace_id=i, span_id=j, parent_id=j - 1 or None) - for j in range(7) - ]) + worker.write( + [Span(tracer=None, name="name", trace_id=i, span_id=j, parent_id=j - 1 or None) for j in range(7)] + ) worker.stop() worker.join() return worker @@ -108,7 +106,7 @@ def test_filters_remove_all(self): self.assertEqual(filtr.filtered_traces, self.N_TRACES) def test_filters_add_tag(self): - tag_name = 'Tag' + tag_name = "Tag" filtr = AddTagFilter(tag_name) self.create_worker([filtr]) self.assertEqual(len(self.api.traces), self.N_TRACES) @@ -127,72 +125,71 @@ def test_filters_short_circuit(self): def test_no_dogstats(self): worker = self.create_worker() assert worker._send_stats is False - assert [ - ] == self.dogstatsd.gauge.mock_calls + assert [] == self.dogstatsd.gauge.mock_calls def test_dogstatsd(self): self.create_worker(enable_stats=True) assert [ - mock.call('datadog.tracer.heartbeat', 1), - mock.call('datadog.tracer.queue.max_length', 1000), + mock.call("datadog.tracer.heartbeat", 1), + mock.call("datadog.tracer.queue.max_length", 1000), ] == self.dogstatsd.gauge.mock_calls assert [ - mock.call('datadog.tracer.flushes'), - mock.call('datadog.tracer.flush.traces.total', 11, tags=None), - mock.call('datadog.tracer.flush.spans.total', 77, tags=None), - mock.call('datadog.tracer.flush.traces_filtered.total', 0, tags=None), - mock.call('datadog.tracer.api.requests.total', 11, tags=None), - mock.call('datadog.tracer.api.errors.total', 0, tags=None), - mock.call('datadog.tracer.api.responses.total', 11, tags=['status:200']), - mock.call('datadog.tracer.queue.dropped.traces', 0), - mock.call('datadog.tracer.queue.enqueued.traces', 11), - mock.call('datadog.tracer.queue.enqueued.spans', 77), - mock.call('datadog.tracer.shutdown'), + mock.call("datadog.tracer.flushes"), + mock.call("datadog.tracer.flush.traces.total", 11, tags=None), + mock.call("datadog.tracer.flush.spans.total", 77, tags=None), + mock.call("datadog.tracer.flush.traces_filtered.total", 0, tags=None), + mock.call("datadog.tracer.api.requests.total", 11, tags=None), + mock.call("datadog.tracer.api.errors.total", 0, tags=None), + mock.call("datadog.tracer.api.responses.total", 11, tags=["status:200"]), + mock.call("datadog.tracer.queue.dropped.traces", 0), + mock.call("datadog.tracer.queue.enqueued.traces", 11), + mock.call("datadog.tracer.queue.enqueued.spans", 77), + mock.call("datadog.tracer.shutdown"), ] == self.dogstatsd.increment.mock_calls histogram_calls = [ - mock.call('datadog.tracer.flush.traces', 11, tags=None), - mock.call('datadog.tracer.flush.spans', 77, tags=None), - mock.call('datadog.tracer.flush.traces_filtered', 0, tags=None), - mock.call('datadog.tracer.api.requests', 11, tags=None), - mock.call('datadog.tracer.api.errors', 0, tags=None), - mock.call('datadog.tracer.api.responses', 11, tags=['status:200']), + mock.call("datadog.tracer.flush.traces", 11, tags=None), + mock.call("datadog.tracer.flush.spans", 77, tags=None), + mock.call("datadog.tracer.flush.traces_filtered", 0, tags=None), + mock.call("datadog.tracer.api.requests", 11, tags=None), + mock.call("datadog.tracer.api.errors", 0, tags=None), + mock.call("datadog.tracer.api.responses", 11, tags=["status:200"]), ] - if hasattr(time, 'thread_time'): - histogram_calls.append(mock.call('datadog.tracer.writer.cpu_time', mock.ANY)) + if hasattr(time, "thread_time"): + histogram_calls.append(mock.call("datadog.tracer.writer.cpu_time", mock.ANY)) assert histogram_calls == self.dogstatsd.histogram.mock_calls def test_dogstatsd_failing_api(self): self.create_worker(api_class=FailingAPI, enable_stats=True) assert [ - mock.call('datadog.tracer.heartbeat', 1), - mock.call('datadog.tracer.queue.max_length', 1000), + mock.call("datadog.tracer.heartbeat", 1), + mock.call("datadog.tracer.queue.max_length", 1000), ] == self.dogstatsd.gauge.mock_calls assert [ - mock.call('datadog.tracer.flushes'), - mock.call('datadog.tracer.flush.traces.total', 11, tags=None), - mock.call('datadog.tracer.flush.spans.total', 77, tags=None), - mock.call('datadog.tracer.flush.traces_filtered.total', 0, tags=None), - mock.call('datadog.tracer.api.requests.total', 1, tags=None), - mock.call('datadog.tracer.api.errors.total', 1, tags=None), - mock.call('datadog.tracer.queue.dropped.traces', 0), - mock.call('datadog.tracer.queue.enqueued.traces', 11), - mock.call('datadog.tracer.queue.enqueued.spans', 77), - mock.call('datadog.tracer.shutdown'), + mock.call("datadog.tracer.flushes"), + mock.call("datadog.tracer.flush.traces.total", 11, tags=None), + mock.call("datadog.tracer.flush.spans.total", 77, tags=None), + mock.call("datadog.tracer.flush.traces_filtered.total", 0, tags=None), + mock.call("datadog.tracer.api.requests.total", 1, tags=None), + mock.call("datadog.tracer.api.errors.total", 1, tags=None), + mock.call("datadog.tracer.queue.dropped.traces", 0), + mock.call("datadog.tracer.queue.enqueued.traces", 11), + mock.call("datadog.tracer.queue.enqueued.spans", 77), + mock.call("datadog.tracer.shutdown"), ] == self.dogstatsd.increment.mock_calls histogram_calls = [ - mock.call('datadog.tracer.flush.traces', 11, tags=None), - mock.call('datadog.tracer.flush.spans', 77, tags=None), - mock.call('datadog.tracer.flush.traces_filtered', 0, tags=None), - mock.call('datadog.tracer.api.requests', 1, tags=None), - mock.call('datadog.tracer.api.errors', 1, tags=None), + mock.call("datadog.tracer.flush.traces", 11, tags=None), + mock.call("datadog.tracer.flush.spans", 77, tags=None), + mock.call("datadog.tracer.flush.traces_filtered", 0, tags=None), + mock.call("datadog.tracer.api.requests", 1, tags=None), + mock.call("datadog.tracer.api.errors", 1, tags=None), ] - if hasattr(time, 'thread_time'): - histogram_calls.append(mock.call('datadog.tracer.writer.cpu_time', mock.ANY)) + if hasattr(time, "thread_time"): + histogram_calls.append(mock.call("datadog.tracer.writer.cpu_time", mock.ANY)) assert histogram_calls == self.dogstatsd.histogram.mock_calls @@ -203,9 +200,7 @@ def test_queue_full(): q.put(2) q.put([3]) q.put([4, 4]) - assert (list(q.queue) == [[1], 2, [4, 4]] or - list(q.queue) == [[1], [4, 4], [3]] or - list(q.queue) == [[4, 4], 2, [3]]) + assert list(q.queue) == [[1], 2, [4, 4]] or list(q.queue) == [[1], [4, 4], [3]] or list(q.queue) == [[4, 4], 2, [3]] assert q.dropped == 1 assert q.accepted == 4 assert q.accepted_lengths == 5 diff --git a/tests/opentracer/test_tracer.py b/tests/opentracer/test_tracer.py index 5ca46eb30c..7888e5973f 100644 --- a/tests/opentracer/test_tracer.py +++ b/tests/opentracer/test_tracer.py @@ -23,80 +23,77 @@ class TestTracerConfig(object): def test_config(self): """Test the configuration of the tracer""" - config = {'enabled': True} - tracer = Tracer(service_name='myservice', config=config) + config = {"enabled": True} + tracer = Tracer(service_name="myservice", config=config) - assert tracer._service_name == 'myservice' + assert tracer._service_name == "myservice" assert tracer._enabled is True def test_no_service_name(self): """A service_name should be generated if one is not provided.""" tracer = Tracer() - assert tracer._service_name == 'pytest' + assert tracer._service_name == "pytest" def test_multiple_tracer_configs(self): """Ensure that a tracer config is a copy of the passed config.""" - config = {'enabled': True} + config = {"enabled": True} - tracer1 = Tracer(service_name='serv1', config=config) - assert tracer1._service_name == 'serv1' + tracer1 = Tracer(service_name="serv1", config=config) + assert tracer1._service_name == "serv1" - config['enabled'] = False - tracer2 = Tracer(service_name='serv2', config=config) + config["enabled"] = False + tracer2 = Tracer(service_name="serv2", config=config) # Ensure tracer1's config was not mutated - assert tracer1._service_name == 'serv1' + assert tracer1._service_name == "serv1" assert tracer1._enabled is True - assert tracer2._service_name == 'serv2' + assert tracer2._service_name == "serv2" assert tracer2._enabled is False def test_invalid_config_key(self): """A config with an invalid key should raise a ConfigException.""" - config = {'enabeld': False} + config = {"enabeld": False} # No debug flag should not raise an error - tracer = Tracer(service_name='mysvc', config=config) + tracer = Tracer(service_name="mysvc", config=config) # With debug flag should raise an error - config['debug'] = True + config["debug"] = True with pytest.raises(ConfigException) as ce_info: tracer = Tracer(config=config) - assert 'enabeld' in str(ce_info) + assert "enabeld" in str(ce_info) assert tracer is not None # Test with multiple incorrect keys - config['setttings'] = {} + config["setttings"] = {} with pytest.raises(ConfigException) as ce_info: - tracer = Tracer(service_name='mysvc', config=config) - assert ['enabeld', 'setttings'] in str(ce_info) + tracer = Tracer(service_name="mysvc", config=config) + assert ["enabeld", "setttings"] in str(ce_info) assert tracer is not None def test_global_tags(self): """Global tags should be passed from the opentracer to the tracer.""" config = { - 'global_tags': { - 'tag1': 'value1', - 'tag2': 2, - }, + "global_tags": {"tag1": "value1", "tag2": 2,}, } - tracer = Tracer(service_name='mysvc', config=config) - with tracer.start_span('myop') as span: + tracer = Tracer(service_name="mysvc", config=config) + with tracer.start_span("myop") as span: # global tags should be attached to generated all datadog spans - assert span._dd_span.get_tag('tag1') == 'value1' - assert span._dd_span.get_metric('tag2') == 2 + assert span._dd_span.get_tag("tag1") == "value1" + assert span._dd_span.get_metric("tag2") == 2 - with tracer.start_span('myop2') as span2: - assert span2._dd_span.get_tag('tag1') == 'value1' - assert span2._dd_span.get_metric('tag2') == 2 + with tracer.start_span("myop2") as span2: + assert span2._dd_span.get_tag("tag1") == "value1" + assert span2._dd_span.get_metric("tag2") == 2 class TestTracer(object): def test_start_span(self, ot_tracer, writer): """Start and finish a span.""" - with ot_tracer.start_span('myop') as span: + with ot_tracer.start_span("myop") as span: pass # span should be finished when the context manager exits @@ -108,16 +105,16 @@ def test_start_span(self, ot_tracer, writer): def test_start_span_references(self, ot_tracer, writer): """Start a span using references.""" - with ot_tracer.start_span('one', references=[child_of()]): + with ot_tracer.start_span("one", references=[child_of()]): pass spans = writer.pop() assert spans[0].parent_id is None - root = ot_tracer.start_active_span('root') + root = ot_tracer.start_active_span("root") # create a child using a parent reference that is not the context parent - with ot_tracer.start_active_span('one'): - with ot_tracer.start_active_span('two', references=[child_of(root.span)]): + with ot_tracer.start_active_span("one"): + with ot_tracer.start_active_span("two", references=[child_of(root.span)]): pass root.close() @@ -127,9 +124,9 @@ def test_start_span_references(self, ot_tracer, writer): def test_start_span_custom_start_time(self, ot_tracer): """Start a span with a custom start time.""" t = 100 - with mock.patch('ddtrace.span.time_ns') as time: + with mock.patch("ddtrace.span.time_ns") as time: time.return_value = 102 * 1e9 - with ot_tracer.start_span('myop', start_time=t) as span: + with ot_tracer.start_span("myop", start_time=t) as span: pass assert span._dd_span.start == t @@ -139,8 +136,8 @@ def test_start_span_with_spancontext(self, ot_tracer, writer): """Start and finish a span using a span context as the child_of reference. """ - with ot_tracer.start_span('myop') as span: - with ot_tracer.start_span('myop', child_of=span.context) as span2: + with ot_tracer.start_span("myop") as span: + with ot_tracer.start_span("myop", child_of=span.context) as span2: pass # span should be finished when the context manager exits @@ -155,36 +152,36 @@ def test_start_span_with_spancontext(self, ot_tracer, writer): def test_start_span_with_tags(self, ot_tracer): """Create a span with initial tags.""" - tags = {'key': 'value', 'key2': 'value2'} - with ot_tracer.start_span('myop', tags=tags) as span: + tags = {"key": "value", "key2": "value2"} + with ot_tracer.start_span("myop", tags=tags) as span: pass - assert span._dd_span.get_tag('key') == 'value' - assert span._dd_span.get_tag('key2') == 'value2' + assert span._dd_span.get_tag("key") == "value" + assert span._dd_span.get_tag("key2") == "value2" def test_start_span_with_resource_name_tag(self, ot_tracer): """Create a span with the tag to set the resource name""" - tags = {'resource.name': 'value', 'key2': 'value2'} - with ot_tracer.start_span('myop', tags=tags) as span: + tags = {"resource.name": "value", "key2": "value2"} + with ot_tracer.start_span("myop", tags=tags) as span: pass # Span resource name should be set to tag value, and should not get set as # a tag on the underlying span. - assert span._dd_span.resource == 'value' - assert span._dd_span.get_tag('resource.name') is None + assert span._dd_span.resource == "value" + assert span._dd_span.get_tag("resource.name") is None # Other tags are set as normal - assert span._dd_span.get_tag('key2') == 'value2' + assert span._dd_span.get_tag("key2") == "value2" def test_start_active_span_multi_child(self, ot_tracer, writer): """Start and finish multiple child spans. This should ensure that child spans can be created 2 levels deep. """ - with ot_tracer.start_active_span('myfirstop') as scope1: + with ot_tracer.start_active_span("myfirstop") as scope1: time.sleep(0.009) - with ot_tracer.start_active_span('mysecondop') as scope2: + with ot_tracer.start_active_span("mysecondop") as scope2: time.sleep(0.007) - with ot_tracer.start_active_span('mythirdop') as scope3: + with ot_tracer.start_active_span("mythirdop") as scope3: time.sleep(0.005) # spans should be finished when the context manager exits @@ -213,11 +210,11 @@ def test_start_active_span_multi_child_siblings(self, ot_tracer, writer): This should test to ensure a parent can have multiple child spans at the same level. """ - with ot_tracer.start_active_span('myfirstop') as scope1: + with ot_tracer.start_active_span("myfirstop") as scope1: time.sleep(0.009) - with ot_tracer.start_active_span('mysecondop') as scope2: + with ot_tracer.start_active_span("mysecondop") as scope2: time.sleep(0.007) - with ot_tracer.start_active_span('mythirdop') as scope3: + with ot_tracer.start_active_span("mythirdop") as scope3: time.sleep(0.005) # spans should be finished when the context manager exits @@ -246,11 +243,11 @@ def test_start_span_manual_child_of(self, ot_tracer, writer): Spans should be created without parents since there will be no call for the active span. """ - root = ot_tracer.start_span('zero') + root = ot_tracer.start_span("zero") - with ot_tracer.start_span('one', child_of=root): - with ot_tracer.start_span('two', child_of=root): - with ot_tracer.start_span('three', child_of=root): + with ot_tracer.start_span("one", child_of=root): + with ot_tracer.start_span("two", child_of=root): + with ot_tracer.start_span("three", child_of=root): pass root.finish() @@ -261,20 +258,17 @@ def test_start_span_manual_child_of(self, ot_tracer, writer): assert spans[1].parent_id is root._dd_span.span_id assert spans[2].parent_id is root._dd_span.span_id assert spans[3].parent_id is root._dd_span.span_id - assert ( - spans[0].trace_id == spans[1].trace_id and - spans[1].trace_id == spans[2].trace_id - ) + assert spans[0].trace_id == spans[1].trace_id and spans[1].trace_id == spans[2].trace_id def test_start_span_no_active_span(self, ot_tracer, writer): """Start spans without using a scope manager. Spans should be created without parents since there will be no call for the active span. """ - with ot_tracer.start_span('one', ignore_active_span=True): - with ot_tracer.start_span('two', ignore_active_span=True): + with ot_tracer.start_span("one", ignore_active_span=True): + with ot_tracer.start_span("two", ignore_active_span=True): pass - with ot_tracer.start_span('three', ignore_active_span=True): + with ot_tracer.start_span("three", ignore_active_span=True): pass spans = writer.pop() @@ -285,15 +279,15 @@ def test_start_span_no_active_span(self, ot_tracer, writer): assert spans[2].parent_id is None # and that each span is a new trace assert ( - spans[0].trace_id != spans[1].trace_id and - spans[1].trace_id != spans[2].trace_id and - spans[0].trace_id != spans[2].trace_id + spans[0].trace_id != spans[1].trace_id + and spans[1].trace_id != spans[2].trace_id + and spans[0].trace_id != spans[2].trace_id ) def test_start_active_span_child_finish_after_parent(self, ot_tracer, writer): """Start a child span and finish it after its parent.""" - span1 = ot_tracer.start_active_span('one').span - span2 = ot_tracer.start_active_span('two').span + span1 = ot_tracer.start_active_span("one").span + span2 = ot_tracer.start_active_span("two").span span1.finish() time.sleep(0.005) span2.finish() @@ -314,7 +308,7 @@ def test_start_span_multi_intertwined(self, ot_tracer, writer): event = threading.Event() def trace_one(): - id = 11 # noqa: A001 + id = 11 # noqa: A001 with ot_tracer.start_active_span(str(id)): id += 1 with ot_tracer.start_active_span(str(id)): @@ -323,7 +317,7 @@ def trace_one(): event.set() def trace_two(): - id = 21 # noqa: A001 + id = 21 # noqa: A001 event.wait() with ot_tracer.start_active_span(str(id)): id += 1 @@ -347,12 +341,12 @@ def trace_two(): # trace_one will finish before trace_two so its spans should be written # before the spans from trace_two, let's confirm this - assert spans[0].name == '11' - assert spans[1].name == '12' - assert spans[2].name == '13' - assert spans[3].name == '21' - assert spans[4].name == '22' - assert spans[5].name == '23' + assert spans[0].name == "11" + assert spans[1].name == "12" + assert spans[2].name == "13" + assert spans[3].name == "21" + assert spans[4].name == "22" + assert spans[5].name == "23" # next let's ensure that each span has the correct parent: # trace_one @@ -366,61 +360,53 @@ def trace_two(): # finally we should ensure that the trace_ids are reasonable # trace_one - assert ( - spans[0].trace_id == spans[1].trace_id and - spans[1].trace_id == spans[2].trace_id - ) + assert spans[0].trace_id == spans[1].trace_id and spans[1].trace_id == spans[2].trace_id # traces should be independent assert spans[2].trace_id != spans[3].trace_id # trace_two - assert ( - spans[3].trace_id == spans[4].trace_id and - spans[4].trace_id == spans[5].trace_id - ) + assert spans[3].trace_id == spans[4].trace_id and spans[4].trace_id == spans[5].trace_id def test_start_active_span(self, ot_tracer, writer): - with ot_tracer.start_active_span('one') as scope: + with ot_tracer.start_active_span("one") as scope: pass - assert scope.span._dd_span.name == 'one' + assert scope.span._dd_span.name == "one" assert scope.span.finished spans = writer.pop() assert spans def test_start_active_span_finish_on_close(self, ot_tracer, writer): - with ot_tracer.start_active_span('one', finish_on_close=False) as scope: + with ot_tracer.start_active_span("one", finish_on_close=False) as scope: pass - assert scope.span._dd_span.name == 'one' + assert scope.span._dd_span.name == "one" assert not scope.span.finished spans = writer.pop() assert not spans def test_start_active_span_nested(self, ot_tracer): """Test the active span of multiple nested calls of start_active_span.""" - with ot_tracer.start_active_span('one') as outer_scope: + with ot_tracer.start_active_span("one") as outer_scope: assert ot_tracer.active_span == outer_scope.span - with ot_tracer.start_active_span('two') as inner_scope: + with ot_tracer.start_active_span("two") as inner_scope: assert ot_tracer.active_span == inner_scope.span - with ot_tracer.start_active_span( - 'three' - ) as innest_scope: # why isn't it innest? innermost so verbose + with ot_tracer.start_active_span("three") as innest_scope: # why isn't it innest? innermost so verbose assert ot_tracer.active_span == innest_scope.span - with ot_tracer.start_active_span('two') as inner_scope: + with ot_tracer.start_active_span("two") as inner_scope: assert ot_tracer.active_span == inner_scope.span assert ot_tracer.active_span == outer_scope.span assert ot_tracer.active_span is None def test_start_active_span_trace(self, ot_tracer, writer): """Test the active span of multiple nested calls of start_active_span.""" - with ot_tracer.start_active_span('one') as outer_scope: - outer_scope.span.set_tag('outer', 2) - with ot_tracer.start_active_span('two') as inner_scope: - inner_scope.span.set_tag('inner', 3) - with ot_tracer.start_active_span('two') as inner_scope: - inner_scope.span.set_tag('inner', 3) - with ot_tracer.start_active_span('three') as innest_scope: - innest_scope.span.set_tag('innerest', 4) + with ot_tracer.start_active_span("one") as outer_scope: + outer_scope.span.set_tag("outer", 2) + with ot_tracer.start_active_span("two") as inner_scope: + inner_scope.span.set_tag("inner", 3) + with ot_tracer.start_active_span("two") as inner_scope: + inner_scope.span.set_tag("inner", 3) + with ot_tracer.start_active_span("three") as innest_scope: + innest_scope.span.set_tag("innerest", 4) spans = writer.pop() @@ -474,9 +460,7 @@ def test_http_headers_base(self, ot_tracer): def test_http_headers_baggage(self, ot_tracer): """extract should undo inject for http headers.""" - span_ctx = SpanContext( - trace_id=123, span_id=456, baggage={'test': 4, 'test2': 'string'} - ) + span_ctx = SpanContext(trace_id=123, span_id=456, baggage={"test": 4, "test2": "string"}) carrier = {} ot_tracer.inject(span_ctx, Format.HTTP_HEADERS, carrier) @@ -497,9 +481,7 @@ def test_empty_propagated_context(self, ot_tracer): def test_text(self, ot_tracer): """extract should undo inject for http headers""" - span_ctx = SpanContext( - trace_id=123, span_id=456, baggage={'test': 4, 'test2': 'string'} - ) + span_ctx = SpanContext(trace_id=123, span_id=456, baggage={"test": 4, "test2": "string"}) carrier = {} ot_tracer.inject(span_ctx, Format.TEXT_MAP, carrier) @@ -512,9 +494,7 @@ def test_text(self, ot_tracer): def test_corrupted_propagated_context(self, ot_tracer): """Corrupted context should raise a SpanContextCorruptedException.""" - span_ctx = SpanContext( - trace_id=123, span_id=456, baggage={'test': 4, 'test2': 'string'} - ) + span_ctx = SpanContext(trace_id=123, span_id=456, baggage={"test": 4, "test2": "string"}) carrier = {} ot_tracer.inject(span_ctx, Format.TEXT_MAP, carrier) @@ -530,12 +510,12 @@ def test_corrupted_propagated_context(self, ot_tracer): def test_immutable_span_context(self, ot_tracer): """Span contexts should be immutable.""" - with ot_tracer.start_span('root') as root: + with ot_tracer.start_span("root") as root: ctx_before = root.context - root.set_baggage_item('test', 2) + root.set_baggage_item("test", 2) assert ctx_before is not root.context - with ot_tracer.start_span('child') as level1: - with ot_tracer.start_span('child') as level2: + with ot_tracer.start_span("child") as level1: + with ot_tracer.start_span("child") as level2: pass assert root.context is not level1.context assert level2.context is not level1.context @@ -543,27 +523,27 @@ def test_immutable_span_context(self, ot_tracer): def test_inherited_baggage(self, ot_tracer): """Baggage should be inherited by child spans.""" - with ot_tracer.start_active_span('root') as root: + with ot_tracer.start_active_span("root") as root: # this should be passed down to the child - root.span.set_baggage_item('root', 1) - root.span.set_baggage_item('root2', 1) - with ot_tracer.start_active_span('child') as level1: - level1.span.set_baggage_item('level1', 1) - with ot_tracer.start_active_span('child') as level2: - level2.span.set_baggage_item('level2', 1) + root.span.set_baggage_item("root", 1) + root.span.set_baggage_item("root2", 1) + with ot_tracer.start_active_span("child") as level1: + level1.span.set_baggage_item("level1", 1) + with ot_tracer.start_active_span("child") as level2: + level2.span.set_baggage_item("level2", 1) # ensure immutability assert level1.span.context is not root.span.context assert level2.span.context is not level1.span.context # level1 should have inherited the baggage of root - assert level1.span.get_baggage_item('root') - assert level1.span.get_baggage_item('root2') + assert level1.span.get_baggage_item("root") + assert level1.span.get_baggage_item("root2") # level2 should have inherited the baggage of both level1 and level2 - assert level2.span.get_baggage_item('root') - assert level2.span.get_baggage_item('root2') - assert level2.span.get_baggage_item('level1') - assert level2.span.get_baggage_item('level2') + assert level2.span.get_baggage_item("root") + assert level2.span.get_baggage_item("root2") + assert level2.span.get_baggage_item("level1") + assert level2.span.get_baggage_item("level2") class TestTracerCompatibility(object): @@ -574,14 +554,14 @@ def test_required_dd_fields(self): by the underlying datadog tracer. """ # a service name is required - tracer = Tracer('service') - with tracer.start_span('my_span') as span: + tracer = Tracer("service") + with tracer.start_span("my_span") as span: assert span._dd_span.service def test_set_global_tracer(): """Sanity check for set_global_tracer""" - my_tracer = Tracer('service') + my_tracer = Tracer("service") set_global_tracer(my_tracer) assert opentracing.tracer is my_tracer diff --git a/tests/propagation/test_http.py b/tests/propagation/test_http.py index 6249c037a4..267954fd08 100644 --- a/tests/propagation/test_http.py +++ b/tests/propagation/test_http.py @@ -19,61 +19,55 @@ class TestHttpPropagation(TestCase): def test_inject(self): tracer = get_dummy_tracer() - with tracer.trace('global_root_span') as span: + with tracer.trace("global_root_span") as span: span.context.sampling_priority = 2 - span.context._dd_origin = 'synthetics' + span.context._dd_origin = "synthetics" headers = {} propagator = HTTPPropagator() propagator.inject(span.context, headers) assert int(headers[HTTP_HEADER_TRACE_ID]) == span.trace_id assert int(headers[HTTP_HEADER_PARENT_ID]) == span.span_id - assert ( - int(headers[HTTP_HEADER_SAMPLING_PRIORITY]) == - span.context.sampling_priority - ) - assert ( - headers[HTTP_HEADER_ORIGIN] == - span.context._dd_origin - ) + assert int(headers[HTTP_HEADER_SAMPLING_PRIORITY]) == span.context.sampling_priority + assert headers[HTTP_HEADER_ORIGIN] == span.context._dd_origin def test_extract(self): tracer = get_dummy_tracer() headers = { - 'x-datadog-trace-id': '1234', - 'x-datadog-parent-id': '5678', - 'x-datadog-sampling-priority': '1', - 'x-datadog-origin': 'synthetics', + "x-datadog-trace-id": "1234", + "x-datadog-parent-id": "5678", + "x-datadog-sampling-priority": "1", + "x-datadog-origin": "synthetics", } propagator = HTTPPropagator() context = propagator.extract(headers) tracer.context_provider.activate(context) - with tracer.trace('local_root_span') as span: + with tracer.trace("local_root_span") as span: assert span.trace_id == 1234 assert span.parent_id == 5678 assert span.context.sampling_priority == 1 - assert span.context._dd_origin == 'synthetics' + assert span.context._dd_origin == "synthetics" def test_WSGI_extract(self): """Ensure we support the WSGI formatted headers as well.""" tracer = get_dummy_tracer() headers = { - 'HTTP_X_DATADOG_TRACE_ID': '1234', - 'HTTP_X_DATADOG_PARENT_ID': '5678', - 'HTTP_X_DATADOG_SAMPLING_PRIORITY': '1', - 'HTTP_X_DATADOG_ORIGIN': 'synthetics', + "HTTP_X_DATADOG_TRACE_ID": "1234", + "HTTP_X_DATADOG_PARENT_ID": "5678", + "HTTP_X_DATADOG_SAMPLING_PRIORITY": "1", + "HTTP_X_DATADOG_ORIGIN": "synthetics", } propagator = HTTPPropagator() context = propagator.extract(headers) tracer.context_provider.activate(context) - with tracer.trace('local_root_span') as span: + with tracer.trace("local_root_span") as span: assert span.trace_id == 1234 assert span.parent_id == 5678 assert span.context.sampling_priority == 1 - assert span.context._dd_origin == 'synthetics' + assert span.context._dd_origin == "synthetics" diff --git a/tox.ini b/tox.ini index f585d1dc43..5e40dd2a22 100644 --- a/tox.ini +++ b/tox.ini @@ -849,8 +849,9 @@ exclude= # Ignore: # A003: XXX is a python builtin, consider renaming the class attribute # G201 Logging: .exception(...) should be used instead of .error(..., exc_info=True) +# E231,W503: not respected by black # We ignore most of the D errors because there are too many; the goal is to fix them eventually -ignore = W504,A003,G201,D100,D101,D102,D103,D104,D105,D106,D107,D200,D202,D204,D205,D208,D210,D300,D400,D401,D403,D413 +ignore = W503,E231,A003,G201,D100,D101,D102,D103,D104,D105,D106,D107,D200,D202,D204,D205,D208,D210,D300,D400,D401,D403,D413 enable-extensions=G rst-roles = class,meth,obj,ref rst-directives = py:data