Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix HTTP instrumentation not being suppressed #1116

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
- 'release/*'
pull_request:
env:
CORE_REPO_SHA: cad776a2031c84fb3c3a1af90ee2a939f3394b9a
CORE_REPO_SHA: c82829283d3e99aa2e089d1774ee509619650617

jobs:
build:
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([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))


### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def response_hook(span, service_name, operation_name, result):
from wrapt import wrap_function_wrapper

from opentelemetry import context as context_api
from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a FIXME to remind us to fix the importing of a private attribute when the location of the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added, thanks for the feedback!

from opentelemetry.instrumentation.botocore.extensions import _find_extension
from opentelemetry.instrumentation.botocore.extensions.types import (
_AwsSdkCallContext,
Expand All @@ -105,14 +106,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):
request = args[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from opentelemetry.context import attach, detach, set_value
from opentelemetry.instrumentation.botocore import BotocoreInstrumentor
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY
from opentelemetry.propagate import get_global_textmap, set_global_textmap
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.test.mock_textmap import MockTextMapPropagator
Expand Down Expand Up @@ -325,6 +326,17 @@ def test_suppress_instrumentation_xray_client(self):
finally:
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):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
from requests.structures import CaseInsensitiveDict

from opentelemetry import context
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__
Expand All @@ -75,12 +76,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")


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from opentelemetry import context, trace
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY
from opentelemetry.propagate import get_global_textmap, set_global_textmap
from opentelemetry.sdk import resources
from opentelemetry.semconv.trace import SpanAttributes
Expand Down Expand Up @@ -245,6 +246,18 @@ def test_suppress_instrumentation(self):
context.detach(token)

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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def response_hook(span, request_obj, response)
)

from opentelemetry import context
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__
Expand All @@ -88,12 +89,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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
URLLibInstrumentor,
)
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY
from opentelemetry.propagate import get_global_textmap, set_global_textmap
from opentelemetry.sdk import resources
from opentelemetry.semconv.trace import SpanAttributes
Expand Down Expand Up @@ -188,6 +189,18 @@ def test_suppress_instrumentation(self):

self.assert_span(num_spans=0)

def test_suppress_http_instrumentation(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test that tests the scenario of being instrumented with multiple http instrumentations?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing a scenario with multiple http instrumentations would require testing across multiple packages at the same time (for example, requests and urllib3 to replicate the problem raised in issue #930) in the form of integration tests and not unit tests, which I think would be out of scope in this PR.

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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def response_hook(span, request, response):
import wrapt

from opentelemetry import context
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__
Expand All @@ -86,12 +87,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[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@
import urllib3.exceptions

from opentelemetry import context, trace
from opentelemetry.instrumentation.urllib3 import (
_SUPPRESS_HTTP_INSTRUMENTATION_KEY,
URLLib3Instrumentor,
)
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
Expand Down