diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2235798121..dc58ca283b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,53 +45,53 @@ jobs: key: v4-build-tox-cache-${{ env.RUN_MATRIX_COMBINATION }}-${{ hashFiles('tox.ini', 'gen-requirements.txt', 'dev-requirements.txt') }} - name: run tox run: tox -f ${{ matrix.python-version }}-${{ matrix.package }} -- --benchmark-json=${{ env.RUN_MATRIX_COMBINATION }}-benchmark.json - - name: Find and merge ${{ matrix.package }} benchmarks - # TODO: Add at least one benchmark to every package type to remove this (#249) - if: matrix.package == 'sdkextension' || matrix.package == 'propagator' - run: >- - mkdir -p benchmarks; - jq -s '.[0].benchmarks = ([.[].benchmarks] | add) - | if .[0].benchmarks == null then null else .[0] end' - **/**/tests/*${{ matrix.package }}*-benchmark.json > benchmarks/output_${{ matrix.package }}.json - - name: Upload all benchmarks under same key as an artifact - if: ${{ success() }} - uses: actions/upload-artifact@v2 - with: - name: benchmarks - path: benchmarks/output_${{ matrix.package }}.json - combine-benchmarks: - runs-on: ubuntu-latest - needs: build - if: ${{ always() }} - name: Combine benchmarks from previous build job - steps: - - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} - uses: actions/checkout@v2 - - name: Download all benchmarks as artifact using key - uses: actions/download-artifact@v2 - with: - name: benchmarks - path: benchmarks - - name: Find and merge all benchmarks - run: >- - jq -s '.[0].benchmarks = ([.[].benchmarks] | add) - | if .[0].benchmarks == null then null else .[0] end' - benchmarks/output_*.json > output.json; - - name: Report on benchmark results - uses: benchmark-action/github-action-benchmark@v1 - with: - name: OpenTelemetry Python Benchmarks - Python ${{ env[matrix.python-version ]}} - ${{ matrix.package }} - tool: pytest - output-file-path: output.json - github-token: ${{ secrets.GITHUB_TOKEN }} - max-items-in-chart: 100 - # Alert with a commit comment on possible performance regression - alert-threshold: 200% - fail-on-alert: true - # Make a commit on `gh-pages` with benchmarks from previous step - auto-push: ${{ github.ref == 'refs/heads/main' }} - gh-pages-branch: gh-pages - benchmark-data-dir-path: benchmarks + # - name: Find and merge ${{ matrix.package }} benchmarks + # # TODO: Add at least one benchmark to every package type to remove this (#249) + # if: matrix.package == 'sdkextension' || matrix.package == 'propagator' + # run: >- + # mkdir -p benchmarks; + # jq -s '.[0].benchmarks = ([.[].benchmarks] | add) + # | if .[0].benchmarks == null then null else .[0] end' + # **/**/tests/*${{ matrix.package }}*-benchmark.json > benchmarks/output_${{ matrix.package }}.json + # - name: Upload all benchmarks under same key as an artifact + # if: ${{ success() }} + # uses: actions/upload-artifact@v2 + # with: + # name: benchmarks + # path: benchmarks/output_${{ matrix.package }}.json + # combine-benchmarks: + # runs-on: ubuntu-latest + # needs: build + # if: ${{ always() }} + # name: Combine benchmarks from previous build job + # steps: + # - name: Checkout Contrib Repo @ SHA - ${{ github.sha }} + # uses: actions/checkout@v2 + # - name: Download all benchmarks as artifact using key + # uses: actions/download-artifact@v2 + # with: + # name: benchmarks + # path: benchmarks + # - name: Find and merge all benchmarks + # run: >- + # jq -s '.[0].benchmarks = ([.[].benchmarks] | add) + # | if .[0].benchmarks == null then null else .[0] end' + # benchmarks/output_*.json > output.json; + # - name: Report on benchmark results + # uses: benchmark-action/github-action-benchmark@v1 + # with: + # name: OpenTelemetry Python Benchmarks - Python ${{ env[matrix.python-version ]}} - ${{ matrix.package }} + # tool: pytest + # output-file-path: output.json + # github-token: ${{ secrets.GITHUB_TOKEN }} + # max-items-in-chart: 100 + # # Alert with a commit comment on possible performance regression + # alert-threshold: 200% + # fail-on-alert: true + # # Make a commit on `gh-pages` with benchmarks from previous step + # auto-push: ${{ github.ref == 'refs/heads/main' }} + # gh-pages-branch: gh-pages + # benchmark-data-dir-path: benchmarks misc: strategy: fail-fast: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bb6fe91a1..6cd943faab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.10.0-0.29b0...HEAD) ### Added - +- `opentelemetry-instrumentation-django` Capture custom request/response headers in span attributes + ([#1024])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1024) +- `opentelemetry-instrumentation-asgi` Capture custom request/response headers in span attributes + ([#1004])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1004) - `opentelemetry-instrumentation-psycopg2` extended the sql commenter support of dbapi into psycopg2 ([#940](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/940)) - `opentelemetry-instrumentation-flask` Fix non-recording span bug @@ -24,9 +27,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.10.0-0.29b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.10.0-0.29b0) - 2022-03-10 -- `opentelemetry-instrumentation-wsgi` Capture custom request/response headers in span attributes - ([#1004])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1004) - - `opentelemetry-instrumentation-wsgi` Capture custom request/response headers in span attributes ([#925])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/925) - `opentelemetry-instrumentation-flask` Flask: Capture custom request/response headers in span attributes diff --git a/docs-requirements.txt b/docs-requirements.txt index 2ae0940a06..c7b3cb7df2 100644 --- a/docs-requirements.txt +++ b/docs-requirements.txt @@ -25,7 +25,7 @@ asyncpg>=0.12.0 boto~=2.0 botocore~=1.0 celery>=4.0 -flask~=1.0 +flask~=2.0 falcon~=2.0 grpcio~=1.27 mysql-connector-python~=8.0 diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py index d5e1f07279..ad6fa7bf36 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py @@ -76,6 +76,52 @@ def response_hook(span, request, response): Django Request object: https://docs.djangoproject.com/en/3.1/ref/request-response/#httprequest-objects Django Response object: https://docs.djangoproject.com/en/3.1/ref/request-response/#httpresponse-objects +Capture HTTP request and response headers +***************************************** +You can configure the agent to capture predefined HTTP headers as span attributes, according to the `semantic convention `_. + +Request headers +*************** +To capture predefined HTTP request headers as span attributes, set the environment variable ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST`` +to a comma-separated list of HTTP header names. + +For example, +:: + + export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST="content_type,custom_request_header" + +will extract content_type and custom_request_header from request headers and add them as span attributes. + +It is recommended that you should give the correct names of the headers to be captured in the environment variable. +Request header names in django are case insensitive. So, giving header name as ``CUStom_Header`` in environment variable will be able capture header with name ``custom-header``. + +The name of the added span attribute will follow the format ``http.request.header.`` where ```` being the normalized HTTP header name (lowercase, with - characters replaced by _ ). +The value of the attribute will be single item list containing all the header values. + +Example of the added span attribute, +``http.request.header.custom_request_header = [","]`` + +Response headers +**************** +To capture predefined HTTP response headers as span attributes, set the environment variable ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE`` +to a comma-separated list of HTTP header names. + +For example, +:: + + export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE="content_type,custom_response_header" + +will extract content_type and custom_response_header from response headers and add them as span attributes. + +It is recommended that you should give the correct names of the headers to be captured in the environment variable. +Response header names captured in django are case insensitive. So, giving header name as ``CUStomHeader`` in environment variable will be able capture header with name ``customheader``. + +The name of the added span attribute will follow the format ``http.response.header.`` where ```` being the normalized HTTP header name (lowercase, with - characters replaced by _ ). +The value of the attribute will be single item list containing all the header values. + +Example of the added span attribute, +``http.response.header.custom_response_header = [","]`` + API --- """ diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py index 6d756c665a..4524caf5a1 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware.py @@ -28,13 +28,19 @@ _start_internal_or_server_span, extract_attributes_from_object, ) +from opentelemetry.instrumentation.wsgi import ( + add_custom_request_headers as wsgi_add_custom_request_headers, +) +from opentelemetry.instrumentation.wsgi import ( + add_custom_response_headers as wsgi_add_custom_response_headers, +) from opentelemetry.instrumentation.wsgi import add_response_attributes from opentelemetry.instrumentation.wsgi import ( collect_request_attributes as wsgi_collect_request_attributes, ) from opentelemetry.instrumentation.wsgi import wsgi_getter from opentelemetry.semconv.trace import SpanAttributes -from opentelemetry.trace import Span, use_span +from opentelemetry.trace import Span, SpanKind, use_span from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs try: @@ -77,7 +83,13 @@ def __call__(self, request): # try/except block exclusive for optional ASGI imports. try: - from opentelemetry.instrumentation.asgi import asgi_getter + from opentelemetry.instrumentation.asgi import asgi_getter, asgi_setter + from opentelemetry.instrumentation.asgi import ( + collect_custom_request_headers_attributes as asgi_collect_custom_request_attributes, + ) + from opentelemetry.instrumentation.asgi import ( + collect_custom_response_headers_attributes as asgi_collect_custom_response_attributes, + ) from opentelemetry.instrumentation.asgi import ( collect_request_attributes as asgi_collect_request_attributes, ) @@ -213,6 +225,13 @@ def process_request(self, request): self._traced_request_attrs, attributes, ) + if span.is_recording() and span.kind == SpanKind.SERVER: + attributes.update( + asgi_collect_custom_request_attributes(carrier) + ) + else: + if span.is_recording() and span.kind == SpanKind.SERVER: + wsgi_add_custom_request_headers(span, carrier) for key, value in attributes.items(): span.set_attribute(key, value) @@ -257,6 +276,7 @@ def process_exception(self, request, exception): if self._environ_activation_key in request.META.keys(): request.META[self._environ_exception_key] = exception + # pylint: disable=too-many-branches def process_response(self, request, response): if self._excluded_urls.url_disabled(request.build_absolute_uri("?")): return response @@ -271,12 +291,25 @@ def process_response(self, request, response): if activation and span: if is_asgi_request: set_status_code(span, response.status_code) + + if span.is_recording() and span.kind == SpanKind.SERVER: + custom_headers = {} + for key, value in response.items(): + asgi_setter.set(custom_headers, key, value) + + custom_res_attributes = ( + asgi_collect_custom_response_attributes(custom_headers) + ) + for key, value in custom_res_attributes.items(): + span.set_attribute(key, value) else: add_response_attributes( span, f"{response.status_code} {response.reason_phrase}", response.items(), ) + if span.is_recording() and span.kind == SpanKind.SERVER: + wsgi_add_custom_response_headers(span, response.items()) propagator = get_global_response_propagator() if propagator: diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py index 32bd1d03fa..855cf3e389 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py @@ -43,7 +43,12 @@ format_span_id, format_trace_id, ) -from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs +from opentelemetry.util.http import ( + OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST, + OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE, + get_excluded_urls, + get_traced_request_attrs, +) # pylint: disable=import-error from .views import ( @@ -51,6 +56,7 @@ excluded, excluded_noarg, excluded_noarg2, + response_with_custom_header, route_span_name, traced, traced_template, @@ -67,6 +73,7 @@ urlpatterns = [ re_path(r"^traced/", traced), + re_path(r"^traced_custom_header/", response_with_custom_header), re_path(r"^route/(?P[0-9]{4})/template/$", traced_template), re_path(r"^error/", error), re_path(r"^excluded_arg/", excluded), @@ -451,3 +458,107 @@ def test_django_with_wsgi_instrumented(self): parent_span.get_span_context().span_id, span_list[0].parent.span_id, ) + + +class TestMiddlewareWsgiWithCustomHeaders(TestBase, WsgiTestBase): + @classmethod + def setUpClass(cls): + conf.settings.configure(ROOT_URLCONF=modules[__name__]) + super().setUpClass() + + def setUp(self): + super().setUp() + setup_test_environment() + tracer_provider, exporter = self.create_tracer_provider() + self.exporter = exporter + _django_instrumentor.instrument(tracer_provider=tracer_provider) + self.env_patch = patch.dict( + "os.environ", + { + OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST: "Custom-Test-Header-1,Custom-Test-Header-2,Custom-Test-Header-3", + OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE: "Custom-Test-Header-1,Custom-Test-Header-2,Custom-Test-Header-3", + }, + ) + self.env_patch.start() + + def tearDown(self): + super().tearDown() + self.env_patch.stop() + teardown_test_environment() + _django_instrumentor.uninstrument() + + @classmethod + def tearDownClass(cls): + super().tearDownClass() + conf.settings = conf.LazySettings() + + def test_http_custom_request_headers_in_span_attributes(self): + expected = { + "http.request.header.custom_test_header_1": ( + "test-header-value-1", + ), + "http.request.header.custom_test_header_2": ( + "test-header-value-2", + ), + } + Client( + HTTP_CUSTOM_TEST_HEADER_1="test-header-value-1", + HTTP_CUSTOM_TEST_HEADER_2="test-header-value-2", + ).get("/traced/") + spans = self.exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + + span = spans[0] + self.assertEqual(span.kind, SpanKind.SERVER) + self.assertSpanHasAttributes(span, expected) + self.memory_exporter.clear() + + def test_http_custom_request_headers_not_in_span_attributes(self): + not_expected = { + "http.request.header.custom_test_header_2": ( + "test-header-value-2", + ), + } + Client(HTTP_CUSTOM_TEST_HEADER_1="test-header-value-1").get("/traced/") + spans = self.exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + + span = spans[0] + self.assertEqual(span.kind, SpanKind.SERVER) + for key, _ in not_expected.items(): + self.assertNotIn(key, span.attributes) + self.memory_exporter.clear() + + def test_http_custom_response_headers_in_span_attributes(self): + expected = { + "http.response.header.custom_test_header_1": ( + "test-header-value-1", + ), + "http.response.header.custom_test_header_2": ( + "test-header-value-2", + ), + } + Client().get("/traced_custom_header/") + spans = self.exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + + span = spans[0] + self.assertEqual(span.kind, SpanKind.SERVER) + self.assertSpanHasAttributes(span, expected) + self.memory_exporter.clear() + + def test_http_custom_response_headers_not_in_span_attributes(self): + not_expected = { + "http.response.header.custom_test_header_3": ( + "test-header-value-3", + ), + } + Client().get("/traced_custom_header/") + spans = self.exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + + span = spans[0] + self.assertEqual(span.kind, SpanKind.SERVER) + for key, _ in not_expected.items(): + self.assertNotIn(key, span.attributes) + self.memory_exporter.clear() diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py index baf1a92894..14a1ce82a9 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py @@ -42,7 +42,12 @@ format_span_id, format_trace_id, ) -from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs +from opentelemetry.util.http import ( + OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST, + OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE, + get_excluded_urls, + get_traced_request_attrs, +) # pylint: disable=import-error from .views import ( @@ -53,6 +58,7 @@ async_route_span_name, async_traced, async_traced_template, + async_with_custom_header, ) DJANGO_2_0 = VERSION >= (2, 0) @@ -65,6 +71,7 @@ urlpatterns = [ re_path(r"^traced/", async_traced), + re_path(r"^traced_custom_header/", async_with_custom_header), re_path(r"^route/(?P[0-9]{4})/template/$", async_traced_template), re_path(r"^error/", async_error), re_path(r"^excluded_arg/", async_excluded), @@ -415,3 +422,116 @@ async def test_tracer_provider_traced(self): self.assertEqual( span.resource.attributes["resource-key"], "resource-value" ) + + +class TestMiddlewareAsgiWithCustomHeaders(SimpleTestCase, TestBase): + @classmethod + def setUpClass(cls): + conf.settings.configure(ROOT_URLCONF=modules[__name__]) + super().setUpClass() + + def setUp(self): + super().setUp() + setup_test_environment() + + tracer_provider, exporter = self.create_tracer_provider() + self.exporter = exporter + _django_instrumentor.instrument(tracer_provider=tracer_provider) + self.env_patch = patch.dict( + "os.environ", + { + OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST: "Custom-Test-Header-1,Custom-Test-Header-2,Custom-Test-Header-3", + OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE: "Custom-Test-Header-1,Custom-Test-Header-2,Custom-Test-Header-3", + }, + ) + self.env_patch.start() + + def tearDown(self): + super().tearDown() + self.env_patch.stop() + teardown_test_environment() + _django_instrumentor.uninstrument() + + @classmethod + def tearDownClass(cls): + super().tearDownClass() + conf.settings = conf.LazySettings() + + async def test_http_custom_request_headers_in_span_attributes(self): + expected = { + "http.request.header.custom_test_header_1": ( + "test-header-value-1", + ), + "http.request.header.custom_test_header_2": ( + "test-header-value-2", + ), + } + await self.async_client.get( + "/traced/", + **{ + "custom-test-header-1": "test-header-value-1", + "custom-test-header-2": "test-header-value-2", + }, + ) + spans = self.exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + + span = spans[0] + self.assertEqual(span.kind, SpanKind.SERVER) + self.assertSpanHasAttributes(span, expected) + self.memory_exporter.clear() + + async def test_http_custom_request_headers_not_in_span_attributes(self): + not_expected = { + "http.request.header.custom_test_header_2": ( + "test-header-value-2", + ), + } + await self.async_client.get( + "/traced/", + **{ + "custom-test-header-1": "test-header-value-1", + }, + ) + spans = self.exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + + span = spans[0] + self.assertEqual(span.kind, SpanKind.SERVER) + for key, _ in not_expected.items(): + self.assertNotIn(key, span.attributes) + self.memory_exporter.clear() + + async def test_http_custom_response_headers_in_span_attributes(self): + expected = { + "http.response.header.custom_test_header_1": ( + "test-header-value-1", + ), + "http.response.header.custom_test_header_2": ( + "test-header-value-2", + ), + } + await self.async_client.get("/traced_custom_header/") + spans = self.exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + + span = spans[0] + self.assertEqual(span.kind, SpanKind.SERVER) + self.assertSpanHasAttributes(span, expected) + self.memory_exporter.clear() + + async def test_http_custom_response_headers_not_in_span_attributes(self): + not_expected = { + "http.response.header.custom_test_header_3": ( + "test-header-value-3", + ), + } + await self.async_client.get("/traced_custom_header/") + spans = self.exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + + span = spans[0] + self.assertEqual(span.kind, SpanKind.SERVER) + for key, _ in not_expected.items(): + self.assertNotIn(key, span.attributes) + self.memory_exporter.clear() diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/views.py b/instrumentation/opentelemetry-instrumentation-django/tests/views.py index 0bcc7e95be..f97933cfd8 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/views.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/views.py @@ -31,6 +31,13 @@ def route_span_name( return HttpResponse() +def response_with_custom_header(request): + response = HttpResponse() + response["custom-test-header-1"] = "test-header-value-1" + response["custom-test-header-2"] = "test-header-value-2" + return response + + async def async_traced(request): # pylint: disable=unused-argument return HttpResponse() @@ -61,3 +68,10 @@ async def async_route_span_name( request, *args, **kwargs ): # pylint: disable=unused-argument return HttpResponse() + + +async def async_with_custom_header(request): + response = HttpResponse() + response.headers["custom-test-header-1"] = "test-header-value-1" + response.headers["custom-test-header-2"] = "test-header-value-2" + return response diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py b/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py index d5424f9079..79b1edf6ab 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/base_test.py @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from flask import Response +import flask from werkzeug.test import Client -from werkzeug.wrappers import BaseResponse +from werkzeug.wrappers import Response class InstrumentationTest: @@ -26,7 +26,7 @@ def _hello_endpoint(helloid): @staticmethod def _custom_response_headers(): - resp = Response("test response") + resp = flask.Response("test response") resp.headers["content-type"] = "text/plain; charset=utf-8" resp.headers["content-length"] = "13" resp.headers[ @@ -51,4 +51,4 @@ def excluded2_endpoint(): ) # pylint: disable=attribute-defined-outside-init - self.client = Client(self.app, BaseResponse) + self.client = Client(self.app, Response) diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/test_automatic.py b/instrumentation/opentelemetry-instrumentation-flask/tests/test_automatic.py index aeff470947..4a64c0a9e0 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/test_automatic.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/test_automatic.py @@ -14,7 +14,7 @@ import flask from werkzeug.test import Client -from werkzeug.wrappers import BaseResponse +from werkzeug.wrappers import Response from opentelemetry.instrumentation.flask import FlaskInstrumentor from opentelemetry.test.test_base import TestBase @@ -52,7 +52,7 @@ def test_uninstrument(self): self.app.route("/hello/")(self._hello_endpoint) # pylint: disable=attribute-defined-outside-init - self.client = Client(self.app, BaseResponse) + self.client = Client(self.app, Response) resp = self.client.get("/hello/123") self.assertEqual(200, resp.status_code) @@ -66,7 +66,7 @@ def test_exluded_urls_explicit(self): self.app = flask.Flask(__name__) self.app.route("/hello/")(self._hello_endpoint) - client = Client(self.app, BaseResponse) + client = Client(self.app, Response) resp = client.get("/hello/123") self.assertEqual(200, resp.status_code)