From 58f77f5d7e286eeb576593959d45e8ba52e9f293 Mon Sep 17 00:00:00 2001 From: Nathaniel Ruiz Nowell Date: Thu, 12 Nov 2020 14:03:37 -0800 Subject: [PATCH 1/2] Add propagator injection for botocore --- .../instrumentation/botocore/__init__.py | 13 +++++ .../tests/test_botocore_instrumentation.py | 55 +++++++++++++++++++ 2 files changed, 68 insertions(+) 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 b574b86cf..8c57ee866 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py @@ -59,6 +59,7 @@ from wrapt import ObjectProxy, wrap_function_wrapper from opentelemetry.instrumentation.botocore.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.sdk.trace import Resource +from opentelemetry import propagators from opentelemetry.trace import SpanKind, get_tracer logger = logging.getLogger(__name__) @@ -85,6 +86,12 @@ class BotocoreInstrumentor(BaseInstrumentor): self._patched_api_call, ) + wrap_function_wrapper( + "botocore.endpoint", + "Endpoint.prepare_request", + self._patched_prepare_request, + ) + def _uninstrument(self, **kwargs): unwrap(BaseClient, "_make_api_call") @@ -144,6 +151,12 @@ class BotocoreInstrumentor(BaseInstrumentor): return result + def _patched_prepare_request(self, wrapped, instance, args, kwargs): + request = args[0] + headers = request.headers + propagators.inject(type(headers).__setitem__, headers) + return wrapped(*args, **kwargs) + def unwrap(obj, attr): function = getattr(obj, attr, None) diff --git a/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py b/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py index fba0182ee..643d16a94 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py @@ -26,7 +26,9 @@ from moto import ( # pylint: disable=import-error ) from opentelemetry.instrumentation.botocore import BotocoreInstrumentor +from opentelemetry import propagators from opentelemetry.sdk.resources import Resource +from opentelemetry.test.mock_textmap import MockTextMapPropagator from opentelemetry.test.test_base import TestBase @@ -275,3 +277,56 @@ class TestBotocoreInstrumentor(TestBase): # checking for protection on sts against security leak self.assertTrue("params" not in span.attributes.keys()) + + @mock_ec2 + def test_propagator_injects_into_request(self): + headers = {} + previous_propagator = propagators.get_global_textmap() + + def check_headers(**kwargs): + nonlocal headers + headers = kwargs["request"].headers + + try: + propagators.set_global_textmap(MockTextMapPropagator()) + + ec2 = self.session.create_client("ec2", region_name="us-west-2") + ec2.meta.events.register_first( + "before-send.ec2.DescribeInstances", check_headers + ) + ec2.describe_instances() + + spans = self.memory_exporter.get_finished_spans() + assert spans + span = spans[0] + self.assertEqual(len(spans), 1) + self.assertEqual(span.attributes["aws.agent"], "botocore") + self.assertEqual(span.attributes["aws.region"], "us-west-2") + self.assertEqual( + span.attributes["aws.operation"], "DescribeInstances" + ) + assert_span_http_status_code(span, 200) + self.assertEqual( + span.resource, + Resource( + attributes={ + "endpoint": "ec2", + "operation": "describeinstances", + } + ), + ) + self.assertEqual(span.name, "ec2.command") + + self.assertIn(MockTextMapPropagator.TRACE_ID_KEY, headers) + self.assertEqual( + str(span.get_span_context().trace_id), + headers[MockTextMapPropagator.TRACE_ID_KEY], + ) + self.assertIn(MockTextMapPropagator.SPAN_ID_KEY, headers) + self.assertEqual( + str(span.get_span_context().span_id), + headers[MockTextMapPropagator.SPAN_ID_KEY], + ) + + finally: + propagators.set_global_textmap(previous_propagator) From 8ee114b6f5e0eab78bbe8441b1b4346c56d7caab Mon Sep 17 00:00:00 2001 From: Nathaniel Ruiz Nowell Date: Thu, 12 Nov 2020 14:27:16 -0800 Subject: [PATCH 2/2] Update changelogs + fix lint --- .../CHANGELOG.md | 2 ++ .../instrumentation/botocore/__init__.py | 18 ++++++++++-------- .../tests/test_botocore_instrumentation.py | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-botocore/CHANGELOG.md b/instrumentation/opentelemetry-instrumentation-botocore/CHANGELOG.md index 9a01165b8..4894f1b20 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/CHANGELOG.md +++ b/instrumentation/opentelemetry-instrumentation-botocore/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## Unreleased +- Add propagator injection for botocore calls + ([#181](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/181)) ## Version 0.13b0 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 8c57ee866..a29e56a77 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py @@ -56,15 +56,23 @@ import logging from botocore.client import BaseClient from wrapt import ObjectProxy, wrap_function_wrapper +from opentelemetry import propagators from opentelemetry.instrumentation.botocore.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.sdk.trace import Resource -from opentelemetry import propagators from opentelemetry.trace import SpanKind, get_tracer logger = logging.getLogger(__name__) +# pylint: disable=unused-argument +def _patched_endpoint_prepare_request(wrapped, instance, args, kwargs): + request = args[0] + headers = request.headers + propagators.inject(type(headers).__setitem__, headers) + return wrapped(*args, **kwargs) + + class BotocoreInstrumentor(BaseInstrumentor): """A instrumentor for Botocore @@ -89,7 +97,7 @@ class BotocoreInstrumentor(BaseInstrumentor): wrap_function_wrapper( "botocore.endpoint", "Endpoint.prepare_request", - self._patched_prepare_request, + _patched_endpoint_prepare_request, ) def _uninstrument(self, **kwargs): @@ -151,12 +159,6 @@ class BotocoreInstrumentor(BaseInstrumentor): return result - def _patched_prepare_request(self, wrapped, instance, args, kwargs): - request = args[0] - headers = request.headers - propagators.inject(type(headers).__setitem__, headers) - return wrapped(*args, **kwargs) - def unwrap(obj, attr): function = getattr(obj, attr, None) diff --git a/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py b/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py index 643d16a94..3d5eb4db9 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py @@ -25,8 +25,8 @@ from moto import ( # pylint: disable=import-error mock_sqs, ) -from opentelemetry.instrumentation.botocore import BotocoreInstrumentor from opentelemetry import propagators +from opentelemetry.instrumentation.botocore import BotocoreInstrumentor from opentelemetry.sdk.resources import Resource from opentelemetry.test.mock_textmap import MockTextMapPropagator from opentelemetry.test.test_base import TestBase