Clean up use of suppress_instrumentation in context and fix httpx bug (#2061)

* Clean up use of suppress_instrumentation in context and fix httpx bug

* Clean up use of suppress_instrumentation in context and fix httpx bug

* changelog

* fix tests

* fix import

* fmt

* update dep

* lint

* remove unused imports

* apply lint

* Fix version for pika

* Fix lint

---------
This commit is contained in:
Adrian Garcia Badaracco
2023-12-22 23:43:12 +01:00
committed by GitHub
parent e5aa74ff7f
commit 9563ee73ac
25 changed files with 175 additions and 301 deletions

View File

@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#2002](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2002))
- `opentelemetry-instrument-grpc` Fix arity of context.abort for AIO RPCs
([#2066](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2066))
- Consolidate instrumentation suppression mechanisms and fix bug in httpx instrumentation
([#2061](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2061))
### Fixed

View File

@ -26,6 +26,7 @@ classifiers = [
]
dependencies = [
"opentelemetry-api ~= 1.5",
"opentelemetry-instrumentation == 0.44b0.dev",
"wrapt >= 1.0.0, < 2.0.0",
]

View File

@ -18,9 +18,7 @@ from aio_pika.abc import AbstractIncomingMessage
from opentelemetry import context, propagate, trace
from opentelemetry.instrumentation.aio_pika.span_builder import SpanBuilder
from opentelemetry.instrumentation.aio_pika.utils import (
is_instrumentation_enabled,
)
from opentelemetry.instrumentation.utils import is_instrumentation_enabled
from opentelemetry.semconv.trace import MessagingOperationValues
from opentelemetry.trace import Span, Tracer

View File

@ -15,9 +15,7 @@ from typing import Optional
from aio_pika.abc import AbstractChannel, AbstractMessage
from opentelemetry.instrumentation.aio_pika.utils import (
is_instrumentation_enabled,
)
from opentelemetry.instrumentation.utils import is_instrumentation_enabled
from opentelemetry.semconv.trace import (
MessagingOperationValues,
SpanAttributes,

View File

@ -1,9 +0,0 @@
from opentelemetry import context
def is_instrumentation_enabled() -> bool:
if context.get_value("suppress_instrumentation") or context.get_value(
context._SUPPRESS_INSTRUMENTATION_KEY
):
return False
return True

View File

@ -94,8 +94,8 @@ from opentelemetry.instrumentation.aiohttp_client.package import _instruments
from opentelemetry.instrumentation.aiohttp_client.version import __version__
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.utils import (
_SUPPRESS_INSTRUMENTATION_KEY,
http_status_to_status_code,
is_instrumentation_enabled,
unwrap,
)
from opentelemetry.propagate import inject
@ -179,7 +179,7 @@ def create_trace_config(
trace_config_ctx: types.SimpleNamespace,
params: aiohttp.TraceRequestStartParams,
):
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
if not is_instrumentation_enabled():
trace_config_ctx.span = None
return
@ -282,7 +282,7 @@ def _instrument(
# pylint:disable=unused-argument
def instrumented_init(wrapped, instance, args, kwargs):
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
if not is_instrumentation_enabled():
return wrapped(*args, **kwargs)
client_trace_configs = list(kwargs.get("trace_configs") or [])

View File

@ -27,13 +27,12 @@ import yarl
from http_server_mock import HttpServerMock
from pkg_resources import iter_entry_points
from opentelemetry import context
from opentelemetry import trace as trace_api
from opentelemetry.instrumentation import aiohttp_client
from opentelemetry.instrumentation.aiohttp_client import (
AioHttpClientInstrumentor,
)
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import suppress_instrumentation
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.test.test_base import TestBase
from opentelemetry.trace import Span, StatusCode
@ -512,25 +511,17 @@ class TestAioHttpClientInstrumentor(TestBase):
self.assert_spans(1)
def test_suppress_instrumentation(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
run_with_test_server(
self.get_default_request(), self.URL, self.default_handler
)
finally:
context.detach(token)
self.assert_spans(0)
@staticmethod
async def suppressed_request(server: aiohttp.test_utils.TestServer):
async with aiohttp.test_utils.TestClient(server) as client:
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
await client.get(TestAioHttpClientInstrumentor.URL)
context.detach(token)
with suppress_instrumentation():
await client.get(TestAioHttpClientInstrumentor.URL)
def test_suppress_instrumentation_after_creation(self):
run_with_test_server(

View File

@ -38,7 +38,7 @@ from wrapt import wrap_function_wrapper
from opentelemetry import context, propagate, trace
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.utils import (
_SUPPRESS_INSTRUMENTATION_KEY,
is_instrumentation_enabled,
unwrap,
)
from opentelemetry.propagators.textmap import CarrierT, Getter, Setter
@ -218,7 +218,7 @@ class Boto3SQSInstrumentor(BaseInstrumentor):
def _wrap_send_message(self, sqs_class: type) -> None:
def send_wrapper(wrapped, instance, args, kwargs):
if context.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
if not is_instrumentation_enabled():
return wrapped(*args, **kwargs)
queue_url = kwargs.get("QueueUrl")
# The method expect QueueUrl and Entries params, so if they are None, we call wrapped to receive the
@ -252,7 +252,7 @@ class Boto3SQSInstrumentor(BaseInstrumentor):
# The method expect QueueUrl and Entries params, so if they are None, we call wrapped to receive the
# original exception
if (
context.get_value(_SUPPRESS_INSTRUMENTATION_KEY)
not is_instrumentation_enabled()
or not queue_url
or not entries
):

View File

@ -86,10 +86,6 @@ from botocore.endpoint import Endpoint
from botocore.exceptions import ClientError
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,
@ -98,7 +94,8 @@ from opentelemetry.instrumentation.botocore.package import _instruments
from opentelemetry.instrumentation.botocore.version import __version__
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.utils import (
_SUPPRESS_INSTRUMENTATION_KEY,
is_instrumentation_enabled,
suppress_http_instrumentation,
unwrap,
)
from opentelemetry.propagators.aws.aws_xray_propagator import AwsXRayPropagator
@ -171,7 +168,7 @@ class BotocoreInstrumentor(BaseInstrumentor):
# pylint: disable=too-many-branches
def _patched_api_call(self, original_func, instance, args, kwargs):
if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
if not is_instrumentation_enabled():
return original_func(*args, **kwargs)
call_context = _determine_call_context(instance, args)
@ -200,25 +197,20 @@ class BotocoreInstrumentor(BaseInstrumentor):
_safe_invoke(extension.before_service_call, span)
self._call_request_hook(span, call_context)
token = context_api.attach(
context_api.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True)
)
result = None
try:
result = original_func(*args, **kwargs)
except ClientError as error:
result = getattr(error, "response", None)
_apply_response_attributes(span, result)
_safe_invoke(extension.on_error, span, error)
raise
else:
_apply_response_attributes(span, result)
_safe_invoke(extension.on_success, span, result)
with suppress_http_instrumentation():
result = None
try:
result = original_func(*args, **kwargs)
except ClientError as error:
result = getattr(error, "response", None)
_apply_response_attributes(span, result)
_safe_invoke(extension.on_error, span, error)
raise
_apply_response_attributes(span, result)
_safe_invoke(extension.on_success, span, result)
finally:
context_api.detach(token)
_safe_invoke(extension.after_service_call)
self._call_response_hook(span, call_context, result)
return result

View File

@ -27,14 +27,11 @@ from moto import ( # pylint: disable=import-error
)
from opentelemetry import trace as trace_api
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.instrumentation.utils import (
suppress_http_instrumentation,
suppress_instrumentation,
)
from opentelemetry.propagate import get_global_textmap, set_global_textmap
from opentelemetry.propagators.aws.aws_xray_propagator import TRACE_HEADER_KEY
from opentelemetry.semconv.trace import SpanAttributes
@ -341,23 +338,17 @@ class TestBotocoreInstrumentor(TestBase):
@mock_xray
def test_suppress_instrumentation_xray_client(self):
xray_client = self._make_client("xray")
token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True))
try:
with suppress_instrumentation():
xray_client.put_trace_segments(TraceSegmentDocuments=["str1"])
xray_client.put_trace_segments(TraceSegmentDocuments=["str2"])
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:
with suppress_http_instrumentation():
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

View File

@ -19,12 +19,11 @@ from collections import OrderedDict
import grpc
from grpc.aio import ClientCallDetails
from opentelemetry import context
from opentelemetry.instrumentation.grpc._client import (
OpenTelemetryClientInterceptor,
_carrier_setter,
)
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import is_instrumentation_enabled
from opentelemetry.propagate import inject
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.trace.status import Status, StatusCode
@ -139,9 +138,10 @@ class _BaseAioClientInterceptor(OpenTelemetryClientInterceptor):
span.end()
def tracing_skipped(self, client_call_details):
return context.get_value(
_SUPPRESS_INSTRUMENTATION_KEY
) or not self.rpc_matches_filters(client_call_details)
return (
not is_instrumentation_enabled()
or not self.rpc_matches_filters(client_call_details)
)
def rpc_matches_filters(self, client_call_details):
return self._filter is None or self._filter(client_call_details)

View File

@ -25,10 +25,10 @@ from typing import Callable, MutableMapping
import grpc
from opentelemetry import context, trace
from opentelemetry import trace
from opentelemetry.instrumentation.grpc import grpcext
from opentelemetry.instrumentation.grpc._utilities import RpcInfo
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import is_instrumentation_enabled
from opentelemetry.propagate import inject
from opentelemetry.propagators.textmap import Setter
from opentelemetry.semconv.trace import SpanAttributes
@ -123,7 +123,7 @@ class OpenTelemetryClientInterceptor(
return result
def _intercept(self, request, metadata, client_info, invoker):
if context.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
if not is_instrumentation_enabled():
return invoker(request, metadata)
if not metadata:
@ -219,7 +219,7 @@ class OpenTelemetryClientInterceptor(
def intercept_stream(
self, request_or_iterator, metadata, client_info, invoker
):
if context.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
if not is_instrumentation_enabled():
return invoker(request_or_iterator, metadata)
if self._filter is not None and not self._filter(client_info):

View File

@ -31,7 +31,7 @@ import grpc
import pytest
import opentelemetry.instrumentation.grpc
from opentelemetry import context, trace
from opentelemetry import trace
from opentelemetry.instrumentation.grpc import (
GrpcAioInstrumentorClient,
aio_client_interceptors,
@ -39,7 +39,7 @@ from opentelemetry.instrumentation.grpc import (
from opentelemetry.instrumentation.grpc._aio_client import (
UnaryUnaryAioClientInterceptor,
)
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import suppress_instrumentation
from opentelemetry.propagate import get_global_textmap, set_global_textmap
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.test.mock_textmap import MockTextMapPropagator
@ -314,53 +314,33 @@ class TestAioClientInterceptor(TestBase, IsolatedAsyncioTestCase):
set_global_textmap(previous_propagator)
async def test_unary_unary_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
response = await simple_method(self._stub)
assert response.response_data == "data"
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 0)
finally:
context.detach(token)
async def test_unary_stream_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
async for response in server_streaming_method(self._stub):
self.assertEqual(response.response_data, "data")
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 0)
finally:
context.detach(token)
async def test_stream_unary_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
response = await client_streaming_method(self._stub)
assert response.response_data == "data"
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 0)
finally:
context.detach(token)
async def test_stream_stream_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
async for response in bidirectional_streaming_method(self._stub):
self.assertEqual(response.response_data, "data")
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 0)
finally:
context.detach(token)

View File

@ -19,7 +19,7 @@ from tests.protobuf import ( # pylint: disable=no-name-in-module
)
import opentelemetry.instrumentation.grpc
from opentelemetry import context, trace
from opentelemetry import trace
from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient
from opentelemetry.instrumentation.grpc._client import (
OpenTelemetryClientInterceptor,
@ -27,7 +27,7 @@ from opentelemetry.instrumentation.grpc._client import (
from opentelemetry.instrumentation.grpc.grpcext._interceptor import (
_UnaryClientInfo,
)
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import suppress_instrumentation
from opentelemetry.propagate import get_global_textmap, set_global_textmap
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.test.mock_textmap import MockTextMapPropagator
@ -307,45 +307,25 @@ class TestClientProto(TestBase):
set_global_textmap(previous_propagator)
def test_unary_unary_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
simple_method(self._stub)
spans = self.memory_exporter.get_finished_spans()
finally:
context.detach(token)
self.assertEqual(len(spans), 0)
def test_unary_stream_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
server_streaming_method(self._stub)
spans = self.memory_exporter.get_finished_spans()
finally:
context.detach(token)
self.assertEqual(len(spans), 0)
def test_stream_unary_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
client_streaming_method(self._stub)
spans = self.memory_exporter.get_finished_spans()
finally:
context.detach(token)
self.assertEqual(len(spans), 0)
def test_stream_stream_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
bidirectional_streaming_method(self._stub)
spans = self.memory_exporter.get_finished_spans()
finally:
context.detach(token)
self.assertEqual(len(spans), 0)

View File

@ -22,7 +22,7 @@ from tests.protobuf import ( # pylint: disable=no-name-in-module
)
import opentelemetry.instrumentation.grpc
from opentelemetry import context, trace
from opentelemetry import trace
from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient, filters
from opentelemetry.instrumentation.grpc._client import (
OpenTelemetryClientInterceptor,
@ -30,7 +30,7 @@ from opentelemetry.instrumentation.grpc._client import (
from opentelemetry.instrumentation.grpc.grpcext._interceptor import (
_UnaryClientInfo,
)
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import suppress_instrumentation
from opentelemetry.propagate import get_global_textmap, set_global_textmap
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.test.mock_textmap import MockTextMapPropagator
@ -639,45 +639,25 @@ class TestClientProtoFilterByEnvAndOption(TestBase):
set_global_textmap(previous_propagator)
def test_unary_unary_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
simple_method(self._stub)
spans = self.memory_exporter.get_finished_spans()
finally:
context.detach(token)
self.assertEqual(len(spans), 0)
def test_unary_stream_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
server_streaming_method(self._stub)
spans = self.memory_exporter.get_finished_spans()
finally:
context.detach(token)
self.assertEqual(len(spans), 0)
def test_stream_unary_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
client_streaming_method(self._stub)
spans = self.memory_exporter.get_finished_spans()
finally:
context.detach(token)
self.assertEqual(len(spans), 0)
def test_stream_stream_with_suppress_key(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
bidirectional_streaming_method(self._stub)
spans = self.memory_exporter.get_finished_spans()
finally:
context.detach(token)
self.assertEqual(len(spans), 0)

View File

@ -5,7 +5,7 @@ from pika.channel import Channel
from pika.spec import Basic, BasicProperties
from opentelemetry import context, propagate, trace
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import is_instrumentation_enabled
from opentelemetry.propagators.textmap import CarrierT, Getter
from opentelemetry.semconv.trace import (
MessagingOperationValues,
@ -135,9 +135,7 @@ def _get_span(
span_kind: SpanKind,
operation: Optional[MessagingOperationValues] = None,
) -> Optional[Span]:
if context.get_value("suppress_instrumentation") or context.get_value(
_SUPPRESS_INSTRUMENTATION_KEY
):
if not is_instrumentation_enabled():
return None
task_name = properties.type if properties.type else task_name
span = tracer.start_span(

View File

@ -79,14 +79,13 @@ from typing import Callable, Collection
from pymongo import monitoring
from opentelemetry import context
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.pymongo.package import _instruments
from opentelemetry.instrumentation.pymongo.utils import (
COMMAND_TO_ATTRIBUTE_MAPPING,
)
from opentelemetry.instrumentation.pymongo.version import __version__
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import is_instrumentation_enabled
from opentelemetry.semconv.trace import DbSystemValues, SpanAttributes
from opentelemetry.trace import SpanKind, get_tracer
from opentelemetry.trace.span import Span
@ -122,9 +121,7 @@ class CommandTracer(monitoring.CommandListener):
def started(self, event: monitoring.CommandStartedEvent):
"""Method to handle a pymongo CommandStartedEvent"""
if not self.is_enabled or context.get_value(
_SUPPRESS_INSTRUMENTATION_KEY
):
if not self.is_enabled or not is_instrumentation_enabled():
return
command_name = event.command_name
span_name = f"{event.database_name}.{command_name}"
@ -167,9 +164,7 @@ class CommandTracer(monitoring.CommandListener):
def succeeded(self, event: monitoring.CommandSucceededEvent):
"""Method to handle a pymongo CommandSucceededEvent"""
if not self.is_enabled or context.get_value(
_SUPPRESS_INSTRUMENTATION_KEY
):
if not self.is_enabled or not is_instrumentation_enabled():
return
span = self._pop_span(event)
if span is None:
@ -185,9 +180,7 @@ class CommandTracer(monitoring.CommandListener):
def failed(self, event: monitoring.CommandFailedEvent):
"""Method to handle a pymongo CommandFailedEvent"""
if not self.is_enabled or context.get_value(
_SUPPRESS_INSTRUMENTATION_KEY
):
if not (self.is_enabled and is_instrumentation_enabled()):
return
span = self._pop_span(event)
if span is None:

View File

@ -14,13 +14,12 @@
from unittest import mock
from opentelemetry import context
from opentelemetry import trace as trace_api
from opentelemetry.instrumentation.pymongo import (
CommandTracer,
PymongoInstrumentor,
)
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import suppress_instrumentation
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.test.test_base import TestBase
@ -112,16 +111,10 @@ class TestPymongo(TestBase):
mock_event.command.get = mock.Mock()
mock_event.command.get.return_value = "dummy"
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
command_tracer = CommandTracer(mock_tracer)
command_tracer.started(event=mock_event)
command_tracer.succeeded(event=mock_event)
finally:
context.detach(token)
# if suppression key is set, CommandTracer methods return immediately, so command.get is not invoked.
self.assertFalse(

View File

@ -58,10 +58,6 @@ from requests.models import PreparedRequest, Response
from requests.sessions import Session
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._semconv import (
_METRIC_ATTRIBUTES_CLIENT_DURATION_NAME,
_SPAN_ATTRIBUTES_ERROR_TYPE,
@ -87,8 +83,9 @@ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.requests.package import _instruments
from opentelemetry.instrumentation.requests.version import __version__
from opentelemetry.instrumentation.utils import (
_SUPPRESS_INSTRUMENTATION_KEY,
http_status_to_status_code,
is_http_instrumentation_enabled,
suppress_http_instrumentation,
)
from opentelemetry.metrics import Histogram, get_meter
from opentelemetry.propagate import inject
@ -149,9 +146,7 @@ def _instrument(
)
return request.headers
if context.get_value(
_SUPPRESS_INSTRUMENTATION_KEY
) or context.get_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY):
if not is_http_instrumentation_enabled():
return wrapped_send(self, request, **kwargs)
# See
@ -220,20 +215,19 @@ def _instrument(
headers = get_or_create_headers()
inject(headers)
token = context.attach(
context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True)
)
start_time = default_timer()
try:
result = wrapped_send(self, request, **kwargs) # *** PROCEED
except Exception as exc: # pylint: disable=W0703
exception = exc
result = getattr(exc, "response", None)
finally:
elapsed_time = max(default_timer() - start_time, 0)
context.detach(token)
with suppress_http_instrumentation():
start_time = default_timer()
try:
result = wrapped_send(
self, request, **kwargs
) # *** PROCEED
except Exception as exc: # pylint: disable=W0703
exception = exc
result = getattr(exc, "response", None)
finally:
elapsed_time = max(
round((default_timer() - start_time) * 1000), 0
)
if isinstance(result, Response):
span_attributes = {}

View File

@ -21,10 +21,7 @@ from requests.adapters import BaseAdapter
from requests.models import Response
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 import trace
from opentelemetry.instrumentation._semconv import (
_OTEL_SEMCONV_STABILITY_OPT_IN_KEY,
_SPAN_ATTRIBUTES_ERROR_TYPE,
@ -33,7 +30,10 @@ from opentelemetry.instrumentation._semconv import (
_OpenTelemetrySemanticConventionStability,
)
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import (
suppress_http_instrumentation,
suppress_instrumentation,
)
from opentelemetry.propagate import get_global_textmap, set_global_textmap
from opentelemetry.sdk import resources
from opentelemetry.semconv.trace import SpanAttributes
@ -397,26 +397,16 @@ class RequestsIntegrationTestBase(abc.ABC):
self.assert_span()
def test_suppress_instrumentation(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
result = self.perform_request(self.URL)
self.assertEqual(result.text, "Hello!")
finally:
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:
with suppress_http_instrumentation():
result = self.perform_request(self.URL)
self.assertEqual(result.text, "Hello!")
finally:
context.detach(token)
self.assert_span(num_spans=0)

View File

@ -85,16 +85,13 @@ from urllib.request import ( # pylint: disable=no-name-in-module,import-error
Request,
)
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__
from opentelemetry.instrumentation.utils import (
_SUPPRESS_INSTRUMENTATION_KEY,
http_status_to_status_code,
is_http_instrumentation_enabled,
suppress_http_instrumentation,
)
from opentelemetry.metrics import Histogram, get_meter
from opentelemetry.propagate import inject
@ -206,9 +203,7 @@ def _instrument(
def _instrumented_open_call(
_, request, call_wrapped, get_or_create_headers
): # pylint: disable=too-many-locals
if context.get_value(
_SUPPRESS_INSTRUMENTATION_KEY
) or context.get_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY):
if not is_http_instrumentation_enabled():
return call_wrapped()
url = request.full_url
@ -236,18 +231,15 @@ def _instrument(
headers = get_or_create_headers()
inject(headers)
token = context.attach(
context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True)
)
start_time = default_timer()
try:
result = call_wrapped() # *** PROCEED
except Exception as exc: # pylint: disable=W0703
exception = exc
result = getattr(exc, "file", None)
finally:
elapsed_time = round((default_timer() - start_time) * 1000)
context.detach(token)
with suppress_http_instrumentation():
start_time = default_timer()
try:
result = call_wrapped() # *** PROCEED
except Exception as exc: # pylint: disable=W0703
exception = exc
result = getattr(exc, "file", None)
finally:
elapsed_time = round((default_timer() - start_time) * 1000)
if result is not None:
code_ = result.getcode()

View File

@ -24,14 +24,14 @@ from urllib.request import OpenerDirector
import httpretty
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 import trace
from opentelemetry.instrumentation.urllib import ( # pylint: disable=no-name-in-module,import-error
URLLibInstrumentor,
)
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import (
suppress_http_instrumentation,
suppress_instrumentation,
)
from opentelemetry.propagate import get_global_textmap, set_global_textmap
from opentelemetry.sdk import resources
from opentelemetry.semconv.trace import SpanAttributes
@ -255,26 +255,16 @@ class RequestsIntegrationTestBase(abc.ABC):
self.assert_span()
def test_suppress_instrumentation(self):
token = context.attach(
context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
)
try:
with suppress_instrumentation():
result = self.perform_request(self.URL)
self.assertEqual(result.read(), b"Hello!")
finally:
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:
with suppress_http_instrumentation():
result = self.perform_request(self.URL)
self.assertEqual(result.read(), b"Hello!")
finally:
context.detach(token)
self.assert_span(num_spans=0)

View File

@ -79,7 +79,6 @@ API
"""
import collections.abc
import contextlib
import io
import typing
from timeit import default_timer
@ -88,16 +87,13 @@ from typing import Collection
import urllib3.connectionpool
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__
from opentelemetry.instrumentation.utils import (
_SUPPRESS_INSTRUMENTATION_KEY,
http_status_to_status_code,
is_http_instrumentation_enabled,
suppress_http_instrumentation,
unwrap,
)
from opentelemetry.metrics import Histogram, get_meter
@ -224,7 +220,7 @@ def _instrument(
excluded_urls: ExcludeList = None,
):
def instrumented_urlopen(wrapped, instance, args, kwargs):
if _is_instrumentation_suppressed():
if not is_http_instrumentation_enabled():
return wrapped(*args, **kwargs)
url = _get_url(instance, args, kwargs, url_filter)
@ -248,7 +244,7 @@ def _instrument(
request_hook(span, instance, headers, body)
inject(headers)
with _suppress_further_instrumentation():
with suppress_http_instrumentation():
start_time = default_timer()
response = wrapped(*args, **kwargs)
elapsed_time = round((default_timer() - start_time) * 1000)
@ -352,13 +348,6 @@ def _apply_response(span: Span, response: urllib3.response.HTTPResponse):
span.set_status(Status(http_status_to_status_code(response.status)))
def _is_instrumentation_suppressed() -> bool:
return bool(
context.get_value(_SUPPRESS_INSTRUMENTATION_KEY)
or context.get_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY)
)
def _create_metric_attributes(
instance: urllib3.connectionpool.HTTPConnectionPool,
response: urllib3.response.HTTPResponse,
@ -382,16 +371,5 @@ def _create_metric_attributes(
return metric_attributes
@contextlib.contextmanager
def _suppress_further_instrumentation():
token = context.attach(
context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True)
)
try:
yield
finally:
context.detach(token)
def _uninstrument():
unwrap(urllib3.connectionpool.HTTPConnectionPool, "urlopen")

View File

@ -19,12 +19,12 @@ import httpretty
import urllib3
import urllib3.exceptions
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 import trace
from opentelemetry.instrumentation.urllib3 import URLLib3Instrumentor
from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.instrumentation.utils import (
suppress_http_instrumentation,
suppress_instrumentation,
)
from opentelemetry.propagate import get_global_textmap, set_global_textmap
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.test.mock_textmap import MockTextMapPropagator
@ -225,20 +225,17 @@ class TestURLLib3Instrumentor(TestBase):
URLLib3Instrumentor().instrument()
def test_suppress_instrumentation(self):
suppression_keys = (
_SUPPRESS_HTTP_INSTRUMENTATION_KEY,
_SUPPRESS_INSTRUMENTATION_KEY,
suppression_cms = (
suppress_instrumentation,
suppress_http_instrumentation,
)
for key in suppression_keys:
for cm in suppression_cms:
self.memory_exporter.clear()
with self.subTest(key=key):
token = context.attach(context.set_value(key, True))
try:
with self.subTest(cm=cm):
with cm():
response = self.perform_request(self.HTTP_URL)
self.assertEqual(b"Hello!", response.data)
finally:
context.detach(token)
self.assert_span(num_spans=0)

View File

@ -13,16 +13,22 @@
# limitations under the License.
import urllib.parse
from contextlib import contextmanager
from re import escape, sub
from typing import Dict, Sequence
from typing import Dict, Iterable, Sequence
from wrapt import ObjectProxy
from opentelemetry import context, trace
# pylint: disable=unused-import
# pylint: disable=E0611
from opentelemetry.context import _SUPPRESS_INSTRUMENTATION_KEY # noqa: F401
# FIXME: fix the importing of these private attributes when the location of the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is defined.=
from opentelemetry.context import (
_SUPPRESS_HTTP_INSTRUMENTATION_KEY,
_SUPPRESS_INSTRUMENTATION_KEY,
)
# pylint: disable=E0611
from opentelemetry.propagate import extract
from opentelemetry.trace import StatusCode
from opentelemetry.trace.propagation.tracecontext import (
@ -152,3 +158,42 @@ def _python_path_without_directory(python_path, directory, path_separator):
"",
python_path,
)
def is_instrumentation_enabled() -> bool:
if context.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
return False
return True
def is_http_instrumentation_enabled() -> bool:
return is_instrumentation_enabled() and not context.get_value(
_SUPPRESS_HTTP_INSTRUMENTATION_KEY
)
@contextmanager
def _suppress_instrumentation(*keys: str) -> Iterable[None]:
"""Suppress instrumentation within the context."""
ctx = context.get_current()
for key in keys:
ctx = context.set_value(key, True, ctx)
token = context.attach(ctx)
try:
yield
finally:
context.detach(token)
@contextmanager
def suppress_instrumentation() -> Iterable[None]:
"""Suppress instrumentation within the context."""
with _suppress_instrumentation(_SUPPRESS_INSTRUMENTATION_KEY):
yield
@contextmanager
def suppress_http_instrumentation() -> Iterable[None]:
"""Suppress instrumentation within the context."""
with _suppress_instrumentation(_SUPPRESS_HTTP_INSTRUMENTATION_KEY):
yield