Skip to content

Commit dd60b99

Browse files
authored
Merge branch 'main' into zhaez/changelog
2 parents aff8fa2 + 8fd3f21 commit dd60b99

File tree

3 files changed

+80
-26
lines changed

3 files changed

+80
-26
lines changed

aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_instrumentation_patch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def apply_instrumentation_patches() -> None:
6767
from amazon.opentelemetry.distro.patches._starlette_patches import _apply_starlette_instrumentation_patches
6868

6969
# Starlette auto-instrumentation v0.54b includes a strict dependency version check
70-
# This restriction was removed in v1.34.0/0.55b0. Applying temporary patch for Genesis launch
70+
# This restriction was removed in v1.34.0/0.55b0. Applying temporary patch for Bedrock AgentCore launch
7171
# TODO: Remove patch after syncing with upstream v1.34.0 or later
7272
_apply_starlette_instrumentation_patches()
7373

aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_starlette_patches.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from logging import Logger, getLogger
55
from typing import Collection
66

7+
from amazon.opentelemetry.distro._utils import is_agent_observability_enabled
8+
79
_logger: Logger = getLogger(__name__)
810

911

@@ -18,6 +20,7 @@ def _apply_starlette_instrumentation_patches() -> None:
1820
"""
1921
try:
2022
# pylint: disable=import-outside-toplevel
23+
from opentelemetry.instrumentation.asgi import OpenTelemetryMiddleware
2124
from opentelemetry.instrumentation.starlette import StarletteInstrumentor
2225

2326
# Patch starlette dependencies version check
@@ -28,6 +31,25 @@ def patched_instrumentation_dependencies(self) -> Collection[str]:
2831
# Apply the patch
2932
StarletteInstrumentor.instrumentation_dependencies = patched_instrumentation_dependencies
3033

34+
# pylint: disable=line-too-long
35+
# Patch to exclude http receive/send ASGI event spans from Bedrock AgentCore,
36+
# this Middleware instrumentation is injected internally by Starlette Instrumentor, see:
37+
# https://github.com/open-telemetry/opentelemetry-python-contrib/blob/51da0a766e5d3cbc746189e10c9573163198cfcd/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py#L573
38+
#
39+
# Issue for tracking a feature to customize this setting within Starlette:
40+
# https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3725
41+
if is_agent_observability_enabled():
42+
original_init = OpenTelemetryMiddleware.__init__
43+
44+
def patched_init(self, app, **kwargs):
45+
original_init(self, app, **kwargs)
46+
if hasattr(self, "exclude_receive_span"):
47+
self.exclude_receive_span = True
48+
if hasattr(self, "exclude_send_span"):
49+
self.exclude_send_span = True
50+
51+
OpenTelemetryMiddleware.__init__ = patched_init
52+
3153
_logger.debug("Successfully patched Starlette instrumentation_dependencies method")
3254
except Exception as exc: # pylint: disable=broad-except
3355
_logger.warning("Failed to apply Starlette instrumentation patches: %s", exc)

aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_starlette_patches.py

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,63 @@ class TestStarlettePatch(TestCase):
1212
@patch("amazon.opentelemetry.distro.patches._starlette_patches._logger")
1313
def test_starlette_patch_applied_successfully(self, mock_logger):
1414
"""Test that the Starlette instrumentation patch is applied successfully."""
15-
# Create a mock StarletteInstrumentor class
16-
mock_instrumentor_class = MagicMock()
17-
mock_instrumentor_class.__name__ = "StarletteInstrumentor"
18-
19-
# Create a mock module
20-
mock_starlette_module = MagicMock()
21-
mock_starlette_module.StarletteInstrumentor = mock_instrumentor_class
22-
23-
# Mock the import
24-
with patch.dict("sys.modules", {"opentelemetry.instrumentation.starlette": mock_starlette_module}):
25-
# Apply the patch
26-
_apply_starlette_instrumentation_patches()
27-
28-
# Verify the instrumentation_dependencies method was replaced
29-
self.assertTrue(hasattr(mock_instrumentor_class, "instrumentation_dependencies"))
30-
31-
# Test the patched method returns the expected value
32-
mock_instance = MagicMock()
33-
result = mock_instrumentor_class.instrumentation_dependencies(mock_instance)
34-
self.assertEqual(result, ("starlette >= 0.13",))
35-
36-
# Verify logging
37-
mock_logger.debug.assert_called_once_with(
38-
"Successfully patched Starlette instrumentation_dependencies method"
39-
)
15+
for agent_enabled in [True, False]:
16+
with self.subTest(agent_enabled=agent_enabled):
17+
with patch.dict("os.environ", {"AGENT_OBSERVABILITY_ENABLED": "true" if agent_enabled else "false"}):
18+
# Create a mock StarletteInstrumentor class
19+
mock_instrumentor_class = MagicMock()
20+
mock_instrumentor_class.__name__ = "StarletteInstrumentor"
21+
22+
def create_middleware_class():
23+
class MockMiddleware:
24+
def __init__(self, app, **kwargs):
25+
pass
26+
27+
return MockMiddleware
28+
29+
mock_middleware_class = create_middleware_class()
30+
31+
mock_starlette_module = MagicMock()
32+
mock_starlette_module.StarletteInstrumentor = mock_instrumentor_class
33+
34+
mock_asgi_module = MagicMock()
35+
mock_asgi_module.OpenTelemetryMiddleware = mock_middleware_class
36+
37+
with patch.dict(
38+
"sys.modules",
39+
{
40+
"opentelemetry.instrumentation.starlette": mock_starlette_module,
41+
"opentelemetry.instrumentation.asgi": mock_asgi_module,
42+
},
43+
):
44+
# Apply the patch
45+
_apply_starlette_instrumentation_patches()
46+
47+
# Verify the instrumentation_dependencies method was replaced
48+
self.assertTrue(hasattr(mock_instrumentor_class, "instrumentation_dependencies"))
49+
50+
# Test the patched method returns the expected value
51+
mock_instance = MagicMock()
52+
result = mock_instrumentor_class.instrumentation_dependencies(mock_instance)
53+
self.assertEqual(result, ("starlette >= 0.13",))
54+
55+
mock_middleware_instance = MagicMock()
56+
mock_middleware_instance.exclude_receive_span = False
57+
mock_middleware_instance.exclude_send_span = False
58+
mock_middleware_class.__init__(mock_middleware_instance, "app")
59+
60+
# Test middleware patching sets exclude flags
61+
if agent_enabled:
62+
self.assertTrue(mock_middleware_instance.exclude_receive_span)
63+
self.assertTrue(mock_middleware_instance.exclude_send_span)
64+
else:
65+
self.assertFalse(mock_middleware_instance.exclude_receive_span)
66+
self.assertFalse(mock_middleware_instance.exclude_send_span)
67+
68+
# Verify logging
69+
mock_logger.debug.assert_called_with(
70+
"Successfully patched Starlette instrumentation_dependencies method"
71+
)
4072

4173
@patch("amazon.opentelemetry.distro.patches._starlette_patches._logger")
4274
def test_starlette_patch_handles_import_error(self, mock_logger):

0 commit comments

Comments
 (0)