diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 562b47bc52..dffd83a7a8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,7 @@ on: - 'release/*' pull_request: env: - CORE_REPO_SHA: cad776a2031c84fb3c3a1af90ee2a939f3394b9a + CORE_REPO_SHA: c82829283d3e99aa2e089d1774ee509619650617 jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aefdf8fde..a2175252f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `opentelemetry-instrumentation-grpc` narrow protobuf dependency to exclude protobuf >= 4 ([#1109](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1109)) - cleanup type hints for textmap `Getter` and `Setter` classes - ([#1106](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1106)) +- Suppressing downstream HTTP instrumentation to avoid [extra spans](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/930) + ([#1116](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1116)) - fixed typo in `system.network.io` metric configuration ([#1135](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1135)) diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py index cf64e65d83..40a760d525 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py @@ -87,6 +87,9 @@ def response_hook(span, service_name, operation_name, result): from wrapt import wrap_function_wrapper from opentelemetry import context as context_api + +# FIXME: fix the importing of this private attribute when the location of the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is defined. +from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY from opentelemetry.instrumentation.botocore.extensions import _find_extension from opentelemetry.instrumentation.botocore.extensions.types import ( _AwsSdkCallContext, @@ -105,13 +108,6 @@ def response_hook(span, service_name, operation_name, result): logger = logging.getLogger(__name__) -# A key to a context variable to avoid creating duplicate spans when instrumenting -# both botocore.client and urllib3.connectionpool.HTTPConnectionPool.urlopen since -# botocore calls urlopen -_SUPPRESS_HTTP_INSTRUMENTATION_KEY = context_api.create_key( - "suppress_http_instrumentation" -) - # pylint: disable=unused-argument def _patched_endpoint_prepare_request(wrapped, instance, args, kwargs): diff --git a/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py b/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py index c7249c9afb..9a5d8429b5 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py @@ -27,7 +27,12 @@ ) from opentelemetry import trace as trace_api -from opentelemetry.context import attach, detach, set_value +from opentelemetry.context import ( + _SUPPRESS_HTTP_INSTRUMENTATION_KEY, + attach, + detach, + set_value, +) from opentelemetry.instrumentation.botocore import BotocoreInstrumentor from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY from opentelemetry.propagate import get_global_textmap, set_global_textmap @@ -326,6 +331,17 @@ def test_suppress_instrumentation_xray_client(self): detach(token) self.assertEqual(0, len(self.get_finished_spans())) + @mock_xray + def test_suppress_http_instrumentation_xray_client(self): + xray_client = self._make_client("xray") + token = attach(set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True)) + try: + xray_client.put_trace_segments(TraceSegmentDocuments=["str1"]) + xray_client.put_trace_segments(TraceSegmentDocuments=["str2"]) + finally: + detach(token) + self.assertEqual(2, len(self.get_finished_spans())) + @mock_s3 def test_request_hook(self): request_hook_service_attribute_name = "request_hook.service_name" diff --git a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py index bd14c504e6..1f66ddeac3 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py @@ -57,6 +57,9 @@ from requests.structures import CaseInsensitiveDict from opentelemetry import context + +# FIXME: fix the importing of this private attribute when the location of the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is defined. +from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.requests.package import _instruments from opentelemetry.instrumentation.requests.version import __version__ @@ -75,12 +78,6 @@ ) from opentelemetry.util.http.httplib import set_ip_on_next_http_connection -# A key to a context variable to avoid creating duplicate spans when instrumenting -# both, Session.request and Session.send, since Session.request calls into Session.send -_SUPPRESS_HTTP_INSTRUMENTATION_KEY = context.create_key( - "suppress_http_instrumentation" -) - _excluded_urls_from_env = get_excluded_urls("REQUESTS") diff --git a/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py b/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py index 1375333b67..626337b67c 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py +++ b/instrumentation/opentelemetry-instrumentation-requests/tests/test_requests_integration.py @@ -22,6 +22,9 @@ import opentelemetry.instrumentation.requests from opentelemetry import context, trace + +# FIXME: fix the importing of this private attribute when the location of the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is defined. +from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY from opentelemetry.instrumentation.requests import RequestsInstrumentor from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY from opentelemetry.propagate import get_global_textmap, set_global_textmap @@ -246,6 +249,18 @@ def test_suppress_instrumentation(self): self.assert_span(num_spans=0) + def test_suppress_http_instrumentation(self): + token = context.attach( + context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True) + ) + try: + result = self.perform_request(self.URL) + self.assertEqual(result.text, "Hello!") + finally: + context.detach(token) + + self.assert_span(num_spans=0) + def test_not_recording(self): with mock.patch("opentelemetry.trace.INVALID_SPAN") as mock_span: RequestsInstrumentor().uninstrument() diff --git a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py index 3e38999ace..04244989f3 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py @@ -75,6 +75,9 @@ def response_hook(span, request_obj, response) ) from opentelemetry import context + +# FIXME: fix the importing of this private attribute when the location of the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is defined. +from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.urllib.package import _instruments from opentelemetry.instrumentation.urllib.version import __version__ @@ -88,12 +91,6 @@ def response_hook(span, request_obj, response) from opentelemetry.trace.status import Status from opentelemetry.util.http import remove_url_credentials -# A key to a context variable to avoid creating duplicate spans when instrumenting -# both, Session.request and Session.send, since Session.request calls into Session.send -_SUPPRESS_HTTP_INSTRUMENTATION_KEY = context.create_key( - "suppress_http_instrumentation" -) - _RequestHookT = typing.Optional[typing.Callable[[Span, Request], None]] _ResponseHookT = typing.Optional[ typing.Callable[[Span, Request, client.HTTPResponse], None] diff --git a/instrumentation/opentelemetry-instrumentation-urllib/tests/test_urllib_integration.py b/instrumentation/opentelemetry-instrumentation-urllib/tests/test_urllib_integration.py index 405ff43c1e..d819d481cc 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib/tests/test_urllib_integration.py +++ b/instrumentation/opentelemetry-instrumentation-urllib/tests/test_urllib_integration.py @@ -24,6 +24,9 @@ import opentelemetry.instrumentation.urllib # pylint: disable=no-name-in-module,import-error from opentelemetry import context, trace + +# FIXME: fix the importing of this private attribute when the location of the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is defined. +from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY from opentelemetry.instrumentation.urllib import ( # pylint: disable=no-name-in-module,import-error URLLibInstrumentor, ) @@ -188,6 +191,18 @@ def test_suppress_instrumentation(self): self.assert_span(num_spans=0) + def test_suppress_http_instrumentation(self): + token = context.attach( + context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True) + ) + try: + result = self.perform_request(self.URL) + self.assertEqual(result.read(), b"Hello!") + finally: + context.detach(token) + + self.assert_span(num_spans=0) + def test_not_recording(self): with mock.patch("opentelemetry.trace.INVALID_SPAN") as mock_span: URLLibInstrumentor().uninstrument() diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py index ef04b7d0c2..e4973613d1 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/src/opentelemetry/instrumentation/urllib3/__init__.py @@ -72,6 +72,9 @@ def response_hook(span, request, response): import wrapt from opentelemetry import context + +# FIXME: fix the importing of this private attribute when the location of the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is defined. +from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.urllib3.package import _instruments from opentelemetry.instrumentation.urllib3.version import __version__ @@ -86,12 +89,6 @@ def response_hook(span, request, response): from opentelemetry.trace.status import Status from opentelemetry.util.http.httplib import set_ip_on_next_http_connection -# A key to a context variable to avoid creating duplicate spans when instrumenting -# both, Session.request and Session.send, since Session.request calls into Session.send -_SUPPRESS_HTTP_INSTRUMENTATION_KEY = context.create_key( - "suppress_http_instrumentation" -) - _UrlFilterT = typing.Optional[typing.Callable[[str], str]] _RequestHookT = typing.Optional[ typing.Callable[ diff --git a/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_integration.py b/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_integration.py index a79ee8f941..2e70a9d2ab 100644 --- a/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_integration.py +++ b/instrumentation/opentelemetry-instrumentation-urllib3/tests/test_urllib3_integration.py @@ -20,10 +20,10 @@ import urllib3.exceptions from opentelemetry import context, trace -from opentelemetry.instrumentation.urllib3 import ( - _SUPPRESS_HTTP_INSTRUMENTATION_KEY, - URLLib3Instrumentor, -) + +# FIXME: fix the importing of this private attribute when the location of the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is defined. +from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY +from opentelemetry.instrumentation.urllib3 import URLLib3Instrumentor from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY from opentelemetry.propagate import get_global_textmap, set_global_textmap from opentelemetry.semconv.trace import SpanAttributes