diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9b5e1e5438..ae470547ca 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,7 @@ on: - 'release/*' pull_request: env: - CORE_REPO_SHA: cad261e5dae1fe986c87e6965664b45cc9ab73c3 + CORE_REPO_SHA: f6b04c483f6c416e1927f010c07e71a17a5d79d0 jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index e398cd8d9d..3321c80910 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#299](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/299)) - `opentelemetry-instrumenation-django` now supports request and response hooks. ([#407](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/407)) +- `opentelemetry-instrumenation-falcon` added trace response headers support to Falcon. + ([#432](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/432)) ### Removed - Remove `http.status_text` from span attributes diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index 41db811287..8b22f563e5 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -52,6 +52,10 @@ def on_get(self, req, resp): from opentelemetry import context, trace from opentelemetry.instrumentation.falcon.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.instrumentation.propagators import ( + FuncSetter, + get_global_back_propagator, +) from opentelemetry.instrumentation.utils import ( extract_attributes_from_object, http_status_to_status_code, @@ -148,6 +152,8 @@ def _start_response(status, response_headers, *args, **kwargs): class _TraceMiddleware: # pylint:disable=R0201,W0613 + back_propagation_setter = FuncSetter(falcon.api.Response.append_header) + def __init__(self, tracer=None, traced_request_attrs=None): self.tracer = tracer self._traced_request_attrs = _traced_request_attrs @@ -209,3 +215,7 @@ def process_response( description=reason, ) ) + + propagator = get_global_back_propagator() + if propagator: + propagator.inject(resp, setter=self.back_propagation_setter) diff --git a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py index 74882fd681..ae61f62c44 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py @@ -17,8 +17,13 @@ from falcon import testing from opentelemetry.instrumentation.falcon import FalconInstrumentor +from opentelemetry.instrumentation.propagators import ( + TraceResponsePropagator, + get_global_back_propagator, + set_global_back_propagator, +) from opentelemetry.test.test_base import TestBase -from opentelemetry.trace import StatusCode +from opentelemetry.trace import StatusCode, format_span_id, format_trace_id from opentelemetry.util.http import get_excluded_urls, get_traced_request_attrs from .app import make_app @@ -192,6 +197,28 @@ def test_traced_request_attributes(self): self.assertEqual(span.attributes["query_string"], "q=abc") self.assertNotIn("not_available_attr", span.attributes) + def test_trace_response(self): + orig = get_global_back_propagator() + set_global_back_propagator(TraceResponsePropagator()) + + response = self.client().simulate_get(path="/hello?q=abc") + headers = response.headers + span = self.memory_exporter.get_finished_spans()[0] + + self.assertIn("traceresponse", headers) + self.assertEqual( + headers["access-control-expose-headers"], "traceresponse", + ) + self.assertEqual( + headers["traceresponse"], + "00-{0}-{1}-01".format( + format_trace_id(span.get_span_context().trace_id), + format_span_id(span.get_span_context().span_id), + ), + ) + + set_global_back_propagator(orig) + def test_traced_not_recording(self): mock_tracer = Mock() mock_span = Mock()