From bb512462096eece84ec82a00ed3a2c9cd4086d61 Mon Sep 17 00:00:00 2001 From: Leighton Date: Mon, 11 May 2020 12:50:21 -0700 Subject: [PATCH 01/12] django exclude --- ext/opentelemetry-ext-django/README.rst | 10 +++++ .../opentelemetry/ext/django/middleware.py | 31 ++++++++++++- .../tests/test_middleware.py | 43 ++++++++++++++++++- ext/opentelemetry-ext-django/tests/views.py | 8 ++++ .../src/opentelemetry/ext/flask/__init__.py | 36 ++++++++-------- .../src/opentelemetry/util/__init__.py | 12 ++---- 6 files changed, 111 insertions(+), 29 deletions(-) diff --git a/ext/opentelemetry-ext-django/README.rst b/ext/opentelemetry-ext-django/README.rst index b922046ca6f..834bd63249e 100644 --- a/ext/opentelemetry-ext-django/README.rst +++ b/ext/opentelemetry-ext-django/README.rst @@ -15,6 +15,16 @@ Installation pip install opentelemetry-ext-django +Configuration +------------- + +Exclude lists +************* +Excludes certain hosts and paths from being tracked. Pass in comma delimited string into environment variables. +Host refers to the entire url and path refers to the part of the url after the domain. Host matches the exact string that is given, where as path matches if the url starts with the given excluded path. + +Excluded hosts: OPENTELEMETRY_PYTHON_DJANGO_EXCLUDED_HOSTS +Excluded paths: OPENTELEMETRY_PYTHON_DJANGO_EXCLUDED_PATHS References ---------- diff --git a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py index 5974c5e5030..3abfcc03fd2 100644 --- a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py +++ b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py @@ -16,6 +16,7 @@ from django.utils.deprecation import MiddlewareMixin +from opentelemetry import configuration from opentelemetry.context import attach, detach from opentelemetry.ext.django.version import __version__ from opentelemetry.ext.wsgi import ( @@ -25,10 +26,29 @@ ) from opentelemetry.propagators import extract from opentelemetry.trace import SpanKind, get_tracer +from opentelemetry.util import ( + disable_tracing_hostname, + disable_tracing_path, +) _logger = getLogger(__name__) +def _disable_trace(url, path): + excluded_hosts = configuration.Configuration().DJANGO_EXCLUDED_HOSTS + excluded_paths = configuration.Configuration().DJANGO_EXCLUDED_PATHS + + if excluded_hosts: + excluded_hosts = str.split(excluded_hosts, ",") + if disable_tracing_hostname(url, excluded_hosts): + return True + if excluded_paths: + excluded_paths = str.split(excluded_paths, ",") + if disable_tracing_path(path, excluded_paths): + return True + return False + + class _DjangoMiddleware(MiddlewareMixin): """Django Middleware for OpenTelemetry """ @@ -50,6 +70,8 @@ def process_view( # key.lower().replace('_', '-').replace("http-", "", 1): value # for key, value in request.META.items() # } + if _disable_trace(request.build_absolute_uri('?'), request.path[1:]): + return environ = request.META @@ -79,7 +101,12 @@ def process_exception(self, request, exception): # Django can call this method and process_response later. In order # to avoid __exit__ and detach from being called twice then, the # respective keys are being removed here. - if self._environ_activation_key in request.META.keys(): + if _disable_trace(request.build_absolute_uri('?'), request.path[1:]): + return + if ( + self._environ_activation_key in request.META.keys() + and self._environ_token in request.META.keys() + ): request.META[self._environ_activation_key].__exit__( type(exception), exception, @@ -91,6 +118,8 @@ def process_exception(self, request, exception): request.META.pop(self._environ_token, None) def process_response(self, request, response): + if _disable_trace(request.build_absolute_uri('?'), request.path[1:]): + return response if ( self._environ_activation_key in request.META.keys() and self._environ_span_key in request.META.keys() diff --git a/ext/opentelemetry-ext-django/tests/test_middleware.py b/ext/opentelemetry-ext-django/tests/test_middleware.py index afee6acf77a..9f1a1eac8de 100644 --- a/ext/opentelemetry-ext-django/tests/test_middleware.py +++ b/ext/opentelemetry-ext-django/tests/test_middleware.py @@ -13,22 +13,32 @@ # limitations under the License. from sys import modules +from unittest.mock import patch from django.conf import settings from django.conf.urls import url from django.test import Client from django.test.utils import setup_test_environment, teardown_test_environment +from opentelemetry.configuration import Configuration from opentelemetry.ext.django import DjangoInstrumentor from opentelemetry.test.wsgitestutil import WsgiTestBase from opentelemetry.trace import SpanKind from opentelemetry.trace.status import StatusCanonicalCode -from .views import error, traced # pylint: disable=import-error +# pylint: disable=import-error +from .views import ( + error, + excluded, + excluded2, + traced +) urlpatterns = [ url(r"^traced/", traced), url(r"^error/", error), + url(r"^excluded/", excluded), + url(r"^excluded2/", excluded2), ] _django_instrumentor = DjangoInstrumentor() @@ -43,6 +53,7 @@ def setUp(self): super().setUp() setup_test_environment() _django_instrumentor.instrument() + Configuration._reset() # pylint: disable=protected-access def tearDown(self): super().tearDown() @@ -106,3 +117,33 @@ def test_error(self): span.attributes["http.url"], "http://testserver/error/" ) self.assertEqual(span.attributes["http.scheme"], "http") + + @patch.dict( + "os.environ", # type: ignore + { + "OPENTELEMETRY_PYTHON_DJANGO_EXCLUDED_HOSTS": ( + "http://testserver/excluded/" + ), + "OPENTELEMETRY_PYTHON_DJANGO_EXCLUDED_PATHS": "excluded2", + }, + ) + def test_exclude(self): + Client().get("/traced/") + Client().get("/excluded/") + Client().get("/excluded2/") + + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + + span = spans[0] + + self.assertEqual(span.name, "traced") + self.assertEqual(span.kind, SpanKind.SERVER) + self.assertEqual(span.status.canonical_code, StatusCanonicalCode.OK) + self.assertEqual(span.attributes["http.method"], "GET") + self.assertEqual( + span.attributes["http.url"], "http://testserver/traced/" + ) + self.assertEqual(span.attributes["http.scheme"], "http") + self.assertEqual(span.attributes["http.status_code"], 200) + self.assertEqual(span.attributes["http.status_text"], "OK") diff --git a/ext/opentelemetry-ext-django/tests/views.py b/ext/opentelemetry-ext-django/tests/views.py index 498a4518eda..9035f0ea03c 100644 --- a/ext/opentelemetry-ext-django/tests/views.py +++ b/ext/opentelemetry-ext-django/tests/views.py @@ -7,3 +7,11 @@ def traced(request): # pylint: disable=unused-argument def error(request): # pylint: disable=unused-argument raise ValueError("error") + + +def excluded(request): # pylint: disable=unused-argument + return HttpResponse() + + +def excluded2(request): # pylint: disable=unused-argument + return HttpResponse() diff --git a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py index 040c8770c6a..0aa41f9c5d2 100644 --- a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py +++ b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py @@ -58,7 +58,7 @@ def hello(): from opentelemetry.util import ( disable_tracing_hostname, disable_tracing_path, - time_ns, + time_ns ) _logger = getLogger(__name__) @@ -69,6 +69,21 @@ def hello(): _ENVIRON_TOKEN = "opentelemetry-flask.token" +def _disable_trace(url, path): + excluded_hosts = configuration.Configuration().FLASK_EXCLUDED_HOSTS + excluded_paths = configuration.Configuration().FLASK_EXCLUDED_PATHS + + if excluded_hosts: + excluded_hosts = str.split(excluded_hosts, ",") + if disable_tracing_hostname(url, excluded_hosts): + return True + if excluded_paths: + excluded_paths = str.split(excluded_paths, ",") + if disable_tracing_path(path, excluded_paths): + return True + return False + + def _rewrapped_app(wsgi_app): def _wrapped_app(environ, start_response): # We want to measure the time for route matching, etc. @@ -79,7 +94,7 @@ def _wrapped_app(environ, start_response): def _start_response(status, response_headers, *args, **kwargs): - if not _disable_trace(flask.request.url): + if not _disable_trace(flask.request.url, flask.request.path[1:]): span = flask.request.environ.get(_ENVIRON_SPAN_KEY) @@ -102,7 +117,7 @@ def _start_response(status, response_headers, *args, **kwargs): def _before_request(): - if _disable_trace(flask.request.url): + if _disable_trace(flask.request.url, flask.request.path[1:]): return environ = flask.request.environ @@ -163,21 +178,6 @@ def __init__(self, *args, **kwargs): self.teardown_request(_teardown_request) -def _disable_trace(url): - excluded_hosts = configuration.Configuration().FLASK_EXCLUDED_HOSTS - excluded_paths = configuration.Configuration().FLASK_EXCLUDED_PATHS - - if excluded_hosts: - excluded_hosts = str.split(excluded_hosts, ",") - if disable_tracing_hostname(url, excluded_hosts): - return True - if excluded_paths: - excluded_paths = str.split(excluded_paths, ",") - if disable_tracing_path(url, excluded_paths): - return True - return False - - class FlaskInstrumentor(BaseInstrumentor): # pylint: disable=protected-access,attribute-defined-outside-init """An instrumentor for flask.Flask diff --git a/opentelemetry-api/src/opentelemetry/util/__init__.py b/opentelemetry-api/src/opentelemetry/util/__init__.py index 48c350730ea..dd8e9987a42 100644 --- a/opentelemetry-api/src/opentelemetry/util/__init__.py +++ b/opentelemetry-api/src/opentelemetry/util/__init__.py @@ -53,15 +53,9 @@ def _load_provider( raise -# Pattern for matching up until the first '/' after the 'https://' part. -_URL_PATTERN = r"(https?|ftp)://.*?/" - - -def disable_tracing_path(url: str, excluded_paths: Sequence[str]) -> bool: - if excluded_paths: - # Match only the part after the first '/' that is not in _URL_PATTERN - regex = "{}({})".format(_URL_PATTERN, "|".join(excluded_paths)) - if re.match(regex, url): +def disable_tracing_path(url_path: str, excluded_paths: Sequence[str]) -> bool: + for path in excluded_paths: + if url_path.startswith(path): return True return False From 6d89ba87aba45b115d546d9ddc9fc6c3afb89b6d Mon Sep 17 00:00:00 2001 From: Leighton Date: Mon, 11 May 2020 13:59:20 -0700 Subject: [PATCH 02/12] black --- .../src/opentelemetry/ext/django/middleware.py | 11 ++++------- ext/opentelemetry-ext-django/tests/test_middleware.py | 7 +------ .../src/opentelemetry/ext/flask/__init__.py | 4 ++-- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py index 3abfcc03fd2..c8f9792ffae 100644 --- a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py +++ b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py @@ -26,10 +26,7 @@ ) from opentelemetry.propagators import extract from opentelemetry.trace import SpanKind, get_tracer -from opentelemetry.util import ( - disable_tracing_hostname, - disable_tracing_path, -) +from opentelemetry.util import disable_tracing_hostname, disable_tracing_path _logger = getLogger(__name__) @@ -70,7 +67,7 @@ def process_view( # key.lower().replace('_', '-').replace("http-", "", 1): value # for key, value in request.META.items() # } - if _disable_trace(request.build_absolute_uri('?'), request.path[1:]): + if _disable_trace(request.build_absolute_uri("?"), request.path[1:]): return environ = request.META @@ -101,7 +98,7 @@ def process_exception(self, request, exception): # Django can call this method and process_response later. In order # to avoid __exit__ and detach from being called twice then, the # respective keys are being removed here. - if _disable_trace(request.build_absolute_uri('?'), request.path[1:]): + if _disable_trace(request.build_absolute_uri("?"), request.path[1:]): return if ( self._environ_activation_key in request.META.keys() @@ -118,7 +115,7 @@ def process_exception(self, request, exception): request.META.pop(self._environ_token, None) def process_response(self, request, response): - if _disable_trace(request.build_absolute_uri('?'), request.path[1:]): + if _disable_trace(request.build_absolute_uri("?"), request.path[1:]): return response if ( self._environ_activation_key in request.META.keys() diff --git a/ext/opentelemetry-ext-django/tests/test_middleware.py b/ext/opentelemetry-ext-django/tests/test_middleware.py index 9f1a1eac8de..14db48f1cac 100644 --- a/ext/opentelemetry-ext-django/tests/test_middleware.py +++ b/ext/opentelemetry-ext-django/tests/test_middleware.py @@ -27,12 +27,7 @@ from opentelemetry.trace.status import StatusCanonicalCode # pylint: disable=import-error -from .views import ( - error, - excluded, - excluded2, - traced -) +from .views import error, excluded, excluded2, traced urlpatterns = [ url(r"^traced/", traced), diff --git a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py index 0aa41f9c5d2..5aaec4f36dc 100644 --- a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py +++ b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py @@ -58,7 +58,7 @@ def hello(): from opentelemetry.util import ( disable_tracing_hostname, disable_tracing_path, - time_ns + time_ns, ) _logger = getLogger(__name__) @@ -83,7 +83,7 @@ def _disable_trace(url, path): return True return False - + def _rewrapped_app(wsgi_app): def _wrapped_app(environ, start_response): # We want to measure the time for route matching, etc. From 60788599ce52357e3f914d8493f13b1572334658 Mon Sep 17 00:00:00 2001 From: Leighton Date: Mon, 11 May 2020 15:06:51 -0700 Subject: [PATCH 03/12] flake8 --- opentelemetry-api/src/opentelemetry/util/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/opentelemetry-api/src/opentelemetry/util/__init__.py b/opentelemetry-api/src/opentelemetry/util/__init__.py index dd8e9987a42..15869acf62c 100644 --- a/opentelemetry-api/src/opentelemetry/util/__init__.py +++ b/opentelemetry-api/src/opentelemetry/util/__init__.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import re import time from logging import getLogger from typing import Sequence, Union From b969c008e7a37a4ed706230933b1c20a4d392869 Mon Sep 17 00:00:00 2001 From: Leighton Date: Mon, 25 May 2020 19:45:48 -0700 Subject: [PATCH 04/12] add regex --- .../opentelemetry/ext/django/middleware.py | 10 +- .../tests/test_middleware.py | 4 +- .../src/opentelemetry/ext/flask/__init__.py | 8 +- .../tests/base_test.py | 108 ------------------ .../tests/test_programmatic.py | 108 +++++++++++++++++- .../src/opentelemetry/util/__init__.py | 14 ++- 6 files changed, 129 insertions(+), 123 deletions(-) diff --git a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py index 3c62d1eda9e..c2021c221e6 100644 --- a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py +++ b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py @@ -34,7 +34,7 @@ _logger = getLogger(__name__) -def _disable_trace(url, path): +def _disable_trace(url): excluded_hosts = configuration.Configuration().DJANGO_EXCLUDED_HOSTS excluded_paths = configuration.Configuration().DJANGO_EXCLUDED_PATHS @@ -44,7 +44,7 @@ def _disable_trace(url, path): return True if excluded_paths: excluded_paths = str.split(excluded_paths, ",") - if disable_tracing_path(path, excluded_paths): + if disable_tracing_path(url, excluded_paths): return True return False @@ -70,7 +70,7 @@ def process_view( # key.lower().replace('_', '-').replace("http-", "", 1): value # for key, value in request.META.items() # } - if _disable_trace(request.build_absolute_uri("?"), request.path[1:]): + if _disable_trace(request.build_absolute_uri("?")): return environ = request.META @@ -101,7 +101,7 @@ def process_exception(self, request, exception): # Django can call this method and process_response later. In order # to avoid __exit__ and detach from being called twice then, the # respective keys are being removed here. - if _disable_trace(request.build_absolute_uri("?"), request.path[1:]): + if _disable_trace(request.build_absolute_uri("?")): return if self._environ_activation_key in request.META.keys(): request.META[self._environ_activation_key].__exit__( @@ -115,7 +115,7 @@ def process_exception(self, request, exception): request.META.pop(self._environ_token, None) def process_response(self, request, response): - if _disable_trace(request.build_absolute_uri("?"), request.path[1:]): + if _disable_trace(request.build_absolute_uri("?")): return response if ( self._environ_activation_key in request.META.keys() diff --git a/ext/opentelemetry-ext-django/tests/test_middleware.py b/ext/opentelemetry-ext-django/tests/test_middleware.py index 14db48f1cac..05c4d8d0bd1 100644 --- a/ext/opentelemetry-ext-django/tests/test_middleware.py +++ b/ext/opentelemetry-ext-django/tests/test_middleware.py @@ -119,13 +119,13 @@ def test_error(self): "OPENTELEMETRY_PYTHON_DJANGO_EXCLUDED_HOSTS": ( "http://testserver/excluded/" ), - "OPENTELEMETRY_PYTHON_DJANGO_EXCLUDED_PATHS": "excluded2", + "OPENTELEMETRY_PYTHON_DJANGO_EXCLUDED_PATHS": "excluded2/", }, ) def test_exclude(self): Client().get("/traced/") Client().get("/excluded/") - Client().get("/excluded2/") + Client().get("/excluded2") spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) diff --git a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py index 5aaec4f36dc..02fd8aea7f0 100644 --- a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py +++ b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py @@ -69,7 +69,7 @@ def hello(): _ENVIRON_TOKEN = "opentelemetry-flask.token" -def _disable_trace(url, path): +def _disable_trace(url): excluded_hosts = configuration.Configuration().FLASK_EXCLUDED_HOSTS excluded_paths = configuration.Configuration().FLASK_EXCLUDED_PATHS @@ -79,7 +79,7 @@ def _disable_trace(url, path): return True if excluded_paths: excluded_paths = str.split(excluded_paths, ",") - if disable_tracing_path(path, excluded_paths): + if disable_tracing_path(url, excluded_paths): return True return False @@ -94,7 +94,7 @@ def _wrapped_app(environ, start_response): def _start_response(status, response_headers, *args, **kwargs): - if not _disable_trace(flask.request.url, flask.request.path[1:]): + if not _disable_trace(flask.request.url): span = flask.request.environ.get(_ENVIRON_SPAN_KEY) @@ -117,7 +117,7 @@ def _start_response(status, response_headers, *args, **kwargs): def _before_request(): - if _disable_trace(flask.request.url, flask.request.path[1:]): + if _disable_trace(flask.request.url): return environ = flask.request.environ diff --git a/ext/opentelemetry-ext-flask/tests/base_test.py b/ext/opentelemetry-ext-flask/tests/base_test.py index 42341826df0..c2bc646e1ba 100644 --- a/ext/opentelemetry-ext-flask/tests/base_test.py +++ b/ext/opentelemetry-ext-flask/tests/base_test.py @@ -12,34 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from unittest.mock import patch - -from flask import request from werkzeug.test import Client from werkzeug.wrappers import BaseResponse -from opentelemetry import trace from opentelemetry.configuration import Configuration -def expected_attributes(override_attributes): - default_attributes = { - "component": "http", - "http.method": "GET", - "http.server_name": "localhost", - "http.scheme": "http", - "host.port": 80, - "http.host": "localhost", - "http.target": "/", - "http.flavor": "1.1", - "http.status_text": "OK", - "http.status_code": 200, - } - for key, val in override_attributes.items(): - default_attributes[key] = val - return default_attributes - - class InstrumentationTest: def setUp(self): # pylint: disable=invalid-name super().setUp() # pylint: disable=no-member @@ -66,89 +44,3 @@ def excluded2_endpoint(): # pylint: disable=attribute-defined-outside-init self.client = Client(self.app, BaseResponse) - - # pylint: disable=no-member - def test_only_strings_in_environ(self): - """ - Some WSGI servers (such as Gunicorn) expect keys in the environ object - to be strings - - OpenTelemetry should adhere to this convention. - """ - nonstring_keys = set() - - def assert_environ(): - for key in request.environ: - if not isinstance(key, str): - nonstring_keys.add(key) - return "hi" - - self.app.route("/assert_environ")(assert_environ) - self.client.get("/assert_environ") - self.assertEqual(nonstring_keys, set()) - - def test_simple(self): - expected_attrs = expected_attributes( - {"http.target": "/hello/123", "http.route": "/hello/"} - ) - self.client.get("/hello/123") - - span_list = self.memory_exporter.get_finished_spans() - self.assertEqual(len(span_list), 1) - self.assertEqual(span_list[0].name, "_hello_endpoint") - self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) - self.assertEqual(span_list[0].attributes, expected_attrs) - - def test_404(self): - expected_attrs = expected_attributes( - { - "http.method": "POST", - "http.target": "/bye", - "http.status_text": "NOT FOUND", - "http.status_code": 404, - } - ) - - resp = self.client.post("/bye") - self.assertEqual(404, resp.status_code) - resp.close() - span_list = self.memory_exporter.get_finished_spans() - self.assertEqual(len(span_list), 1) - self.assertEqual(span_list[0].name, "/bye") - self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) - self.assertEqual(span_list[0].attributes, expected_attrs) - - def test_internal_error(self): - expected_attrs = expected_attributes( - { - "http.target": "/hello/500", - "http.route": "/hello/", - "http.status_text": "INTERNAL SERVER ERROR", - "http.status_code": 500, - } - ) - resp = self.client.get("/hello/500") - self.assertEqual(500, resp.status_code) - resp.close() - span_list = self.memory_exporter.get_finished_spans() - self.assertEqual(len(span_list), 1) - self.assertEqual(span_list[0].name, "_hello_endpoint") - self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) - self.assertEqual(span_list[0].attributes, expected_attrs) - - @patch.dict( - "os.environ", # type: ignore - { - "OPENTELEMETRY_PYTHON_FLASK_EXCLUDED_HOSTS": ( - "http://localhost/excluded" - ), - "OPENTELEMETRY_PYTHON_FLASK_EXCLUDED_PATHS": "excluded2", - }, - ) - def test_excluded_path(self): - self.client.get("/hello/123") - self.client.get("/excluded") - self.client.get("/excluded2") - span_list = self.memory_exporter.get_finished_spans() - self.assertEqual(len(span_list), 1) - self.assertEqual(span_list[0].name, "_hello_endpoint") diff --git a/ext/opentelemetry-ext-flask/tests/test_programmatic.py b/ext/opentelemetry-ext-flask/tests/test_programmatic.py index 4e17f25fdc1..b1cc8ea853b 100644 --- a/ext/opentelemetry-ext-flask/tests/test_programmatic.py +++ b/ext/opentelemetry-ext-flask/tests/test_programmatic.py @@ -12,8 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from flask import Flask +from flask import Flask, request +from unittest.mock import patch +from opentelemetry import trace from opentelemetry.ext.flask import FlaskInstrumentor from opentelemetry.test.test_base import TestBase from opentelemetry.test.wsgitestutil import WsgiTestBase @@ -22,6 +24,24 @@ from .base_test import InstrumentationTest +def expected_attributes(override_attributes): + default_attributes = { + "component": "http", + "http.method": "GET", + "http.server_name": "localhost", + "http.scheme": "http", + "host.port": 80, + "http.host": "localhost", + "http.target": "/", + "http.flavor": "1.1", + "http.status_text": "OK", + "http.status_code": 200, + } + for key, val in override_attributes.items(): + default_attributes[key] = val + return default_attributes + + class TestProgrammatic(InstrumentationTest, TestBase, WsgiTestBase): def setUp(self): super().setUp() @@ -51,3 +71,89 @@ def test_uninstrument(self): self.assertEqual([b"Hello: 123"], list(resp.response)) span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 1) + + # pylint: disable=no-member + def test_only_strings_in_environ(self): + """ + Some WSGI servers (such as Gunicorn) expect keys in the environ object + to be strings + + OpenTelemetry should adhere to this convention. + """ + nonstring_keys = set() + + def assert_environ(): + for key in request.environ: + if not isinstance(key, str): + nonstring_keys.add(key) + return "hi" + + self.app.route("/assert_environ")(assert_environ) + self.client.get("/assert_environ") + self.assertEqual(nonstring_keys, set()) + + def test_simple(self): + expected_attrs = expected_attributes( + {"http.target": "/hello/123", "http.route": "/hello/"} + ) + self.client.get("/hello/123") + + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "_hello_endpoint") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_404(self): + expected_attrs = expected_attributes( + { + "http.method": "POST", + "http.target": "/bye", + "http.status_text": "NOT FOUND", + "http.status_code": 404, + } + ) + + resp = self.client.post("/bye") + self.assertEqual(404, resp.status_code) + resp.close() + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "/bye") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + def test_internal_error(self): + expected_attrs = expected_attributes( + { + "http.target": "/hello/500", + "http.route": "/hello/", + "http.status_text": "INTERNAL SERVER ERROR", + "http.status_code": 500, + } + ) + resp = self.client.get("/hello/500") + self.assertEqual(500, resp.status_code) + resp.close() + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "_hello_endpoint") + self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) + self.assertEqual(span_list[0].attributes, expected_attrs) + + @patch.dict( + "os.environ", # type: ignore + { + "OPENTELEMETRY_PYTHON_FLASK_EXCLUDED_HOSTS": ( + "http://localhost/excluded" + ), + "OPENTELEMETRY_PYTHON_FLASK_EXCLUDED_PATHS": "excluded2", + }, + ) + def test_excluded_path(self): + self.client.get("/hello/123") + self.client.get("/excluded") + self.client.get("/excluded2") + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "_hello_endpoint") diff --git a/opentelemetry-api/src/opentelemetry/util/__init__.py b/opentelemetry-api/src/opentelemetry/util/__init__.py index 15869acf62c..1d0795a4b3f 100644 --- a/opentelemetry-api/src/opentelemetry/util/__init__.py +++ b/opentelemetry-api/src/opentelemetry/util/__init__.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import re import time from logging import getLogger from typing import Sequence, Union @@ -51,10 +52,17 @@ def _load_provider( logger.error("Failed to load configured provider %s", provider) raise +# Pattern for matching up until the first '/' after the 'https://' part. +_URL_PATTERN = r"(https?|ftp)://.*?/" -def disable_tracing_path(url_path: str, excluded_paths: Sequence[str]) -> bool: - for path in excluded_paths: - if url_path.startswith(path): + +def disable_tracing_path(url: str, excluded_paths: Sequence[str]) -> bool: + print(url) + if excluded_paths: + # Match only the part after the first '/' that is not in _URL_PATTERN + regex = "{}({})".format(_URL_PATTERN, "|".join(excluded_paths)) + print(regex) + if re.match(regex, url): return True return False From a13a611b3de93ebe1559785c81dcb34acddc5540 Mon Sep 17 00:00:00 2001 From: Leighton Date: Mon, 25 May 2020 20:00:48 -0700 Subject: [PATCH 05/12] black --- opentelemetry-api/src/opentelemetry/util/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/opentelemetry-api/src/opentelemetry/util/__init__.py b/opentelemetry-api/src/opentelemetry/util/__init__.py index 1d0795a4b3f..1f9e258427b 100644 --- a/opentelemetry-api/src/opentelemetry/util/__init__.py +++ b/opentelemetry-api/src/opentelemetry/util/__init__.py @@ -52,6 +52,7 @@ def _load_provider( logger.error("Failed to load configured provider %s", provider) raise + # Pattern for matching up until the first '/' after the 'https://' part. _URL_PATTERN = r"(https?|ftp)://.*?/" From 0c6aff3b454728df51b34ec8f8406dd96cd6179f Mon Sep 17 00:00:00 2001 From: Leighton Date: Mon, 25 May 2020 21:13:43 -0700 Subject: [PATCH 06/12] lint --- ext/opentelemetry-ext-flask/tests/test_programmatic.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/opentelemetry-ext-flask/tests/test_programmatic.py b/ext/opentelemetry-ext-flask/tests/test_programmatic.py index b1cc8ea853b..48a744afcda 100644 --- a/ext/opentelemetry-ext-flask/tests/test_programmatic.py +++ b/ext/opentelemetry-ext-flask/tests/test_programmatic.py @@ -12,9 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from flask import Flask, request from unittest.mock import patch +from flask import Flask, request + from opentelemetry import trace from opentelemetry.ext.flask import FlaskInstrumentor from opentelemetry.test.test_base import TestBase From 6b2b1500c0ce09ab5b6e071bb89dd8037ddc3df1 Mon Sep 17 00:00:00 2001 From: Leighton Date: Tue, 26 May 2020 11:34:19 -0700 Subject: [PATCH 07/12] address comments --- .../opentelemetry/ext/django/middleware.py | 44 +++++++++------- .../tests/test_middleware.py | 2 +- .../src/opentelemetry/ext/flask/__init__.py | 51 ++++++++++++------- .../tests/test_programmatic.py | 19 ------- .../src/opentelemetry/util/__init__.py | 11 +++- 5 files changed, 68 insertions(+), 59 deletions(-) diff --git a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py index c2021c221e6..7ace04f524e 100644 --- a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py +++ b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py @@ -24,7 +24,7 @@ ) from opentelemetry.propagators import extract from opentelemetry.trace import SpanKind, get_tracer -from opentelemetry.util import disable_tracing_hostname, disable_tracing_path +from opentelemetry.util import disable_trace try: from django.utils.deprecation import MiddlewareMixin @@ -34,21 +34,6 @@ _logger = getLogger(__name__) -def _disable_trace(url): - excluded_hosts = configuration.Configuration().DJANGO_EXCLUDED_HOSTS - excluded_paths = configuration.Configuration().DJANGO_EXCLUDED_PATHS - - if excluded_hosts: - excluded_hosts = str.split(excluded_hosts, ",") - if disable_tracing_hostname(url, excluded_hosts): - return True - if excluded_paths: - excluded_paths = str.split(excluded_paths, ",") - if disable_tracing_path(url, excluded_paths): - return True - return False - - class _DjangoMiddleware(MiddlewareMixin): """Django Middleware for OpenTelemetry """ @@ -59,6 +44,13 @@ class _DjangoMiddleware(MiddlewareMixin): _environ_token = "opentelemetry-instrumentor-django.token" _environ_span_key = "opentelemetry-instrumentor-django.span_key" + _excluded_hosts = configuration.Configuration().DJANGO_EXCLUDED_HOSTS or [] + if _excluded_hosts: + _excluded_hosts = str.split(_excluded_hosts, ",") + _excluded_paths = configuration.Configuration().DJANGO_EXCLUDED_PATHS or [] + if _excluded_paths: + _excluded_paths = str.split(_excluded_paths, ",") + def process_view( self, request, view_func, view_args, view_kwargs ): # pylint: disable=unused-argument @@ -70,7 +62,11 @@ def process_view( # key.lower().replace('_', '-').replace("http-", "", 1): value # for key, value in request.META.items() # } - if _disable_trace(request.build_absolute_uri("?")): + if disable_trace( + request.build_absolute_uri("?"), + self._excluded_hosts, + self._excluded_paths + ): return environ = request.META @@ -101,8 +97,13 @@ def process_exception(self, request, exception): # Django can call this method and process_response later. In order # to avoid __exit__ and detach from being called twice then, the # respective keys are being removed here. - if _disable_trace(request.build_absolute_uri("?")): + if disable_trace( + request.build_absolute_uri("?"), + self._excluded_hosts, + self._excluded_paths + ): return + if self._environ_activation_key in request.META.keys(): request.META[self._environ_activation_key].__exit__( type(exception), @@ -115,8 +116,13 @@ def process_exception(self, request, exception): request.META.pop(self._environ_token, None) def process_response(self, request, response): - if _disable_trace(request.build_absolute_uri("?")): + if disable_trace( + request.build_absolute_uri("?"), + self._excluded_hosts, + self._excluded_paths + ): return response + if ( self._environ_activation_key in request.META.keys() and self._environ_span_key in request.META.keys() diff --git a/ext/opentelemetry-ext-django/tests/test_middleware.py b/ext/opentelemetry-ext-django/tests/test_middleware.py index 05c4d8d0bd1..3ce34f176b6 100644 --- a/ext/opentelemetry-ext-django/tests/test_middleware.py +++ b/ext/opentelemetry-ext-django/tests/test_middleware.py @@ -125,7 +125,7 @@ def test_error(self): def test_exclude(self): Client().get("/traced/") Client().get("/excluded/") - Client().get("/excluded2") + Client().get("/excluded2/") spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) diff --git a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py index 02fd8aea7f0..2bdc99e0f5d 100644 --- a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py +++ b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py @@ -56,8 +56,7 @@ def hello(): from opentelemetry.auto_instrumentation.instrumentor import BaseInstrumentor from opentelemetry.ext.flask.version import __version__ from opentelemetry.util import ( - disable_tracing_hostname, - disable_tracing_path, + disable_trace, time_ns, ) @@ -69,19 +68,22 @@ def hello(): _ENVIRON_TOKEN = "opentelemetry-flask.token" -def _disable_trace(url): - excluded_hosts = configuration.Configuration().FLASK_EXCLUDED_HOSTS - excluded_paths = configuration.Configuration().FLASK_EXCLUDED_PATHS +def get_excluded_hosts(): + hosts = configuration.Configuration().FLASK_EXCLUDED_HOSTS or [] + if hosts: + hosts = str.split(hosts, ",") + return hosts - if excluded_hosts: - excluded_hosts = str.split(excluded_hosts, ",") - if disable_tracing_hostname(url, excluded_hosts): - return True - if excluded_paths: - excluded_paths = str.split(excluded_paths, ",") - if disable_tracing_path(url, excluded_paths): - return True - return False + +def get_excluded_paths(): + paths = configuration.Configuration().FLASK_EXCLUDED_PATHS or [] + if paths: + paths = str.split(paths, ",") + return paths + + +_excluded_hosts = get_excluded_hosts() +_excluded_paths = get_excluded_paths() def _rewrapped_app(wsgi_app): @@ -93,9 +95,11 @@ def _wrapped_app(environ, start_response): environ[_ENVIRON_STARTTIME_KEY] = time_ns() def _start_response(status, response_headers, *args, **kwargs): - - if not _disable_trace(flask.request.url): - + if not disable_trace( + flask.request.url, + _excluded_hosts, + _excluded_paths + ): span = flask.request.environ.get(_ENVIRON_SPAN_KEY) if span: @@ -117,7 +121,11 @@ def _start_response(status, response_headers, *args, **kwargs): def _before_request(): - if _disable_trace(flask.request.url): + if disable_trace( + flask.request.url, + _excluded_hosts, + _excluded_paths + ): return environ = flask.request.environ @@ -149,6 +157,13 @@ def _before_request(): def _teardown_request(exc): + if disable_trace( + flask.request.url, + _excluded_hosts, + _excluded_paths + ): + return + activation = flask.request.environ.get(_ENVIRON_ACTIVATION_KEY) if not activation: _logger.warning( diff --git a/ext/opentelemetry-ext-flask/tests/test_programmatic.py b/ext/opentelemetry-ext-flask/tests/test_programmatic.py index 48a744afcda..95f82373e3d 100644 --- a/ext/opentelemetry-ext-flask/tests/test_programmatic.py +++ b/ext/opentelemetry-ext-flask/tests/test_programmatic.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from unittest.mock import patch - from flask import Flask, request from opentelemetry import trace @@ -141,20 +139,3 @@ def test_internal_error(self): self.assertEqual(span_list[0].name, "_hello_endpoint") self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER) self.assertEqual(span_list[0].attributes, expected_attrs) - - @patch.dict( - "os.environ", # type: ignore - { - "OPENTELEMETRY_PYTHON_FLASK_EXCLUDED_HOSTS": ( - "http://localhost/excluded" - ), - "OPENTELEMETRY_PYTHON_FLASK_EXCLUDED_PATHS": "excluded2", - }, - ) - def test_excluded_path(self): - self.client.get("/hello/123") - self.client.get("/excluded") - self.client.get("/excluded2") - span_list = self.memory_exporter.get_finished_spans() - self.assertEqual(len(span_list), 1) - self.assertEqual(span_list[0].name, "_hello_endpoint") diff --git a/opentelemetry-api/src/opentelemetry/util/__init__.py b/opentelemetry-api/src/opentelemetry/util/__init__.py index 1f9e258427b..11d72c10596 100644 --- a/opentelemetry-api/src/opentelemetry/util/__init__.py +++ b/opentelemetry-api/src/opentelemetry/util/__init__.py @@ -58,11 +58,9 @@ def _load_provider( def disable_tracing_path(url: str, excluded_paths: Sequence[str]) -> bool: - print(url) if excluded_paths: # Match only the part after the first '/' that is not in _URL_PATTERN regex = "{}({})".format(_URL_PATTERN, "|".join(excluded_paths)) - print(regex) if re.match(regex, url): return True return False @@ -72,3 +70,12 @@ def disable_tracing_hostname( url: str, excluded_hostnames: Sequence[str] ) -> bool: return url in excluded_hostnames + + +def disable_trace( + url: str, + excluded_hosts: Sequence[str], + excluded_paths: Sequence[str] +) -> bool: + return disable_tracing_hostname(url, excluded_hosts) or \ + disable_tracing_path(url, excluded_paths) From 5dbd8c713504981aaebea158757b03fa41981fcd Mon Sep 17 00:00:00 2001 From: Leighton Date: Tue, 26 May 2020 14:53:20 -0700 Subject: [PATCH 08/12] fix tests --- .../opentelemetry/ext/django/middleware.py | 23 +++++++++++++------ .../tests/test_middleware.py | 15 ++++-------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py index 7ace04f524e..cf66c3649ca 100644 --- a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py +++ b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py @@ -34,6 +34,20 @@ _logger = getLogger(__name__) +def get_excluded_hosts(): + hosts = configuration.Configuration().DJANGO_EXCLUDED_HOSTS or [] + if hosts: + hosts = str.split(hosts, ",") + return hosts + + +def get_excluded_paths(): + paths = configuration.Configuration().DJANGO_EXCLUDED_PATHS or [] + if paths: + paths = str.split(paths, ",") + return paths + + class _DjangoMiddleware(MiddlewareMixin): """Django Middleware for OpenTelemetry """ @@ -44,13 +58,8 @@ class _DjangoMiddleware(MiddlewareMixin): _environ_token = "opentelemetry-instrumentor-django.token" _environ_span_key = "opentelemetry-instrumentor-django.span_key" - _excluded_hosts = configuration.Configuration().DJANGO_EXCLUDED_HOSTS or [] - if _excluded_hosts: - _excluded_hosts = str.split(_excluded_hosts, ",") - _excluded_paths = configuration.Configuration().DJANGO_EXCLUDED_PATHS or [] - if _excluded_paths: - _excluded_paths = str.split(_excluded_paths, ",") - + _excluded_hosts = get_excluded_hosts() + _excluded_paths = get_excluded_paths() def process_view( self, request, view_func, view_args, view_kwargs ): # pylint: disable=unused-argument diff --git a/ext/opentelemetry-ext-django/tests/test_middleware.py b/ext/opentelemetry-ext-django/tests/test_middleware.py index 3ce34f176b6..a13ae479667 100644 --- a/ext/opentelemetry-ext-django/tests/test_middleware.py +++ b/ext/opentelemetry-ext-django/tests/test_middleware.py @@ -113,16 +113,11 @@ def test_error(self): ) self.assertEqual(span.attributes["http.scheme"], "http") - @patch.dict( - "os.environ", # type: ignore - { - "OPENTELEMETRY_PYTHON_DJANGO_EXCLUDED_HOSTS": ( - "http://testserver/excluded/" - ), - "OPENTELEMETRY_PYTHON_DJANGO_EXCLUDED_PATHS": "excluded2/", - }, - ) - def test_exclude(self): + @patch("opentelemetry.ext.django.middleware.get_excluded_hosts") + @patch("opentelemetry.ext.django.middleware.get_excluded_paths") + def test_exclude(self, path_mock, host_mock): + host_mock.return_value = ["http://testserver/excluded/"] + host_mock.return_value = "excluded2/" Client().get("/traced/") Client().get("/excluded/") Client().get("/excluded2/") From f105b458c16ed295ea3f54cc261ee27a7e328c7b Mon Sep 17 00:00:00 2001 From: Leighton Date: Tue, 26 May 2020 16:11:30 -0700 Subject: [PATCH 09/12] changelog --- ext/opentelemetry-ext-django/CHANGELOG.md | 3 +++ .../opentelemetry/ext/django/middleware.py | 24 ++++++------------ .../tests/test_middleware.py | 25 ------------------- 3 files changed, 10 insertions(+), 42 deletions(-) diff --git a/ext/opentelemetry-ext-django/CHANGELOG.md b/ext/opentelemetry-ext-django/CHANGELOG.md index 43990fab16e..11fc8ea83c1 100644 --- a/ext/opentelemetry-ext-django/CHANGELOG.md +++ b/ext/opentelemetry-ext-django/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +- Add exclude lists + ([#670](https://github.com/open-telemetry/opentelemetry-python/pull/670)) + ## 0.7b1 Released 2020-05-12 diff --git a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py index cf66c3649ca..ffc82e1af24 100644 --- a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py +++ b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py @@ -14,7 +14,7 @@ from logging import getLogger -from opentelemetry import configuration +from opentelemetry.configuration import Configuration from opentelemetry.context import attach, detach from opentelemetry.ext.django.version import __version__ from opentelemetry.ext.wsgi import ( @@ -34,20 +34,6 @@ _logger = getLogger(__name__) -def get_excluded_hosts(): - hosts = configuration.Configuration().DJANGO_EXCLUDED_HOSTS or [] - if hosts: - hosts = str.split(hosts, ",") - return hosts - - -def get_excluded_paths(): - paths = configuration.Configuration().DJANGO_EXCLUDED_PATHS or [] - if paths: - paths = str.split(paths, ",") - return paths - - class _DjangoMiddleware(MiddlewareMixin): """Django Middleware for OpenTelemetry """ @@ -58,8 +44,12 @@ class _DjangoMiddleware(MiddlewareMixin): _environ_token = "opentelemetry-instrumentor-django.token" _environ_span_key = "opentelemetry-instrumentor-django.span_key" - _excluded_hosts = get_excluded_hosts() - _excluded_paths = get_excluded_paths() + _excluded_hosts = Configuration().DJANGO_EXCLUDED_HOSTS or [] + _excluded_paths = Configuration().DJANGO_EXCLUDED_PATHS or [] + if _excluded_hosts: + _excluded_hosts = str.split(_excluded_hosts, ",") + if _excluded_paths: + _excluded_paths = str.split(_excluded_paths, ",") def process_view( self, request, view_func, view_args, view_kwargs ): # pylint: disable=unused-argument diff --git a/ext/opentelemetry-ext-django/tests/test_middleware.py b/ext/opentelemetry-ext-django/tests/test_middleware.py index a13ae479667..e2be6e60614 100644 --- a/ext/opentelemetry-ext-django/tests/test_middleware.py +++ b/ext/opentelemetry-ext-django/tests/test_middleware.py @@ -112,28 +112,3 @@ def test_error(self): span.attributes["http.url"], "http://testserver/error/" ) self.assertEqual(span.attributes["http.scheme"], "http") - - @patch("opentelemetry.ext.django.middleware.get_excluded_hosts") - @patch("opentelemetry.ext.django.middleware.get_excluded_paths") - def test_exclude(self, path_mock, host_mock): - host_mock.return_value = ["http://testserver/excluded/"] - host_mock.return_value = "excluded2/" - Client().get("/traced/") - Client().get("/excluded/") - Client().get("/excluded2/") - - spans = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans), 1) - - span = spans[0] - - self.assertEqual(span.name, "traced") - self.assertEqual(span.kind, SpanKind.SERVER) - self.assertEqual(span.status.canonical_code, StatusCanonicalCode.OK) - self.assertEqual(span.attributes["http.method"], "GET") - self.assertEqual( - span.attributes["http.url"], "http://testserver/traced/" - ) - self.assertEqual(span.attributes["http.scheme"], "http") - self.assertEqual(span.attributes["http.status_code"], 200) - self.assertEqual(span.attributes["http.status_text"], "OK") From 18f1c699f1c189fac77ea01279ce4e2998296c17 Mon Sep 17 00:00:00 2001 From: Leighton Date: Tue, 26 May 2020 18:01:39 -0700 Subject: [PATCH 10/12] lint --- opentelemetry-api/src/opentelemetry/util/__init__.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/util/__init__.py b/opentelemetry-api/src/opentelemetry/util/__init__.py index 11d72c10596..bab42b0bde2 100644 --- a/opentelemetry-api/src/opentelemetry/util/__init__.py +++ b/opentelemetry-api/src/opentelemetry/util/__init__.py @@ -73,9 +73,8 @@ def disable_tracing_hostname( def disable_trace( - url: str, - excluded_hosts: Sequence[str], - excluded_paths: Sequence[str] + url: str, excluded_hosts: Sequence[str], excluded_paths: Sequence[str] ) -> bool: - return disable_tracing_hostname(url, excluded_hosts) or \ - disable_tracing_path(url, excluded_paths) + return disable_tracing_hostname( + url, excluded_hosts + ) or disable_tracing_path(url, excluded_paths) From aec932e593a09001e30cbdb18dbb5ef9faeaae52 Mon Sep 17 00:00:00 2001 From: Leighton Date: Tue, 26 May 2020 20:19:05 -0700 Subject: [PATCH 11/12] lint --- .../opentelemetry/ext/django/middleware.py | 7 ++++--- .../src/opentelemetry/ext/flask/__init__.py | 21 ++++--------------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py index ffc82e1af24..0ce03b97cb7 100644 --- a/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py +++ b/ext/opentelemetry-ext-django/src/opentelemetry/ext/django/middleware.py @@ -50,6 +50,7 @@ class _DjangoMiddleware(MiddlewareMixin): _excluded_hosts = str.split(_excluded_hosts, ",") if _excluded_paths: _excluded_paths = str.split(_excluded_paths, ",") + def process_view( self, request, view_func, view_args, view_kwargs ): # pylint: disable=unused-argument @@ -64,7 +65,7 @@ def process_view( if disable_trace( request.build_absolute_uri("?"), self._excluded_hosts, - self._excluded_paths + self._excluded_paths, ): return @@ -99,7 +100,7 @@ def process_exception(self, request, exception): if disable_trace( request.build_absolute_uri("?"), self._excluded_hosts, - self._excluded_paths + self._excluded_paths, ): return @@ -118,7 +119,7 @@ def process_response(self, request, response): if disable_trace( request.build_absolute_uri("?"), self._excluded_hosts, - self._excluded_paths + self._excluded_paths, ): return response diff --git a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py index 2bdc99e0f5d..cd94dc7e47b 100644 --- a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py +++ b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py @@ -55,10 +55,7 @@ def hello(): from opentelemetry import configuration, context, propagators, trace from opentelemetry.auto_instrumentation.instrumentor import BaseInstrumentor from opentelemetry.ext.flask.version import __version__ -from opentelemetry.util import ( - disable_trace, - time_ns, -) +from opentelemetry.util import disable_trace, time_ns _logger = getLogger(__name__) @@ -96,9 +93,7 @@ def _wrapped_app(environ, start_response): def _start_response(status, response_headers, *args, **kwargs): if not disable_trace( - flask.request.url, - _excluded_hosts, - _excluded_paths + flask.request.url, _excluded_hosts, _excluded_paths ): span = flask.request.environ.get(_ENVIRON_SPAN_KEY) @@ -121,11 +116,7 @@ def _start_response(status, response_headers, *args, **kwargs): def _before_request(): - if disable_trace( - flask.request.url, - _excluded_hosts, - _excluded_paths - ): + if disable_trace(flask.request.url, _excluded_hosts, _excluded_paths): return environ = flask.request.environ @@ -157,11 +148,7 @@ def _before_request(): def _teardown_request(exc): - if disable_trace( - flask.request.url, - _excluded_hosts, - _excluded_paths - ): + if disable_trace(flask.request.url, _excluded_hosts, _excluded_paths): return activation = flask.request.environ.get(_ENVIRON_ACTIVATION_KEY) From d7bd1643824857b1dfbcf4c4bc19e512f2e9d9ae Mon Sep 17 00:00:00 2001 From: Leighton Date: Tue, 26 May 2020 21:40:17 -0700 Subject: [PATCH 12/12] address comments --- ext/opentelemetry-ext-django/CHANGELOG.md | 4 ++-- ext/opentelemetry-ext-django/tests/test_middleware.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ext/opentelemetry-ext-django/CHANGELOG.md b/ext/opentelemetry-ext-django/CHANGELOG.md index 3515a7e9969..c7c4966dc96 100644 --- a/ext/opentelemetry-ext-django/CHANGELOG.md +++ b/ext/opentelemetry-ext-django/CHANGELOG.md @@ -2,9 +2,9 @@ ## Unreleased -- Add exclude lists +- Add exclude list for paths and hosts to prevent from tracing ([#670](https://github.com/open-telemetry/opentelemetry-python/pull/670)) -- Add support for django >= 1.10 (#717) +- Add support for django >= 1.10 (#717) ## 0.7b1 diff --git a/ext/opentelemetry-ext-django/tests/test_middleware.py b/ext/opentelemetry-ext-django/tests/test_middleware.py index e2be6e60614..e0ac92de521 100644 --- a/ext/opentelemetry-ext-django/tests/test_middleware.py +++ b/ext/opentelemetry-ext-django/tests/test_middleware.py @@ -13,7 +13,6 @@ # limitations under the License. from sys import modules -from unittest.mock import patch from django.conf import settings from django.conf.urls import url