From 39b037b27dae63659b7166059afc2e513d7e9654 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Fri, 15 May 2026 16:21:09 -0700 Subject: [PATCH 1/5] Use APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE env var in _is_attach_enabled Update _is_attach_enabled() to check the new APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE environment variable set by the RP integration agent (sitecustomize.py). When the env var is present, attach is only considered enabled if it is set to IntegratedAuto AND the existing per-RP logic (Functions, App Service, AKS) is satisfied. When the env var is absent, the function falls back to legacy detection (path-based for App Service, env-var-based for Functions/AKS). This resolves false positives where the agent path exists but auto-instrumentation backed off or failed to attach. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CHANGELOG.md | 4 + .../opentelemetry/exporter/_constants.py | 1 + .../monitor/opentelemetry/exporter/_utils.py | 15 ++ .../tests/test_utils.py | 142 ++++++++++++++++++ 4 files changed, 162 insertions(+) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md index 9cd28551f352..0d41becc71a7 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md @@ -3,8 +3,12 @@ ## 1.0.0b53 (Unreleased) ### Features Added + - Read for global feature sdkstats bitmap and add a 15 second delay timer ([#47031](https://github.com/Azure/azure-sdk-for-python/pull/47031)) +- Use `APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE` environment variable in `_is_attach_enabled` to + reliably detect successful auto-instrumentation attach, with fallback to legacy path-based detection + ([#46955](https://github.com/Azure/azure-sdk-for-python/pull/46955)) ### Breaking Changes diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_constants.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_constants.py index 218340e3a13d..074dae72b141 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_constants.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_constants.py @@ -38,6 +38,7 @@ _PYTHON_APPLICATIONINSIGHTS_ENABLE_TELEMETRY = "PYTHON_APPLICATIONINSIGHTS_ENABLE_TELEMETRY" _AKS_ARM_NAMESPACE_ID = "AKS_ARM_NAMESPACE_ID" _KUBERNETES_SERVICE_HOST = "KUBERNETES_SERVICE_HOST" +_APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE = "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE" # Network diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py index db99edde2c7c..91fd756de074 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py @@ -23,6 +23,7 @@ from azure.monitor.opentelemetry.exporter._connection_string_parser import ConnectionStringParser from azure.monitor.opentelemetry.exporter._constants import ( _AKS_ARM_NAMESPACE_ID, + _APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE, _AZURE_MONITOR_DISTRO_VERSION, _DEFAULT_AAD_SCOPE, _FUNCTIONS_WORKER_RUNTIME, @@ -68,6 +69,20 @@ def _is_on_aks(): def _is_attach_enabled(): + attach_type = environ.get(_APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE) + if attach_type is not None: + # If the env var is set, attach is only enabled if the value is + # "IntegratedAuto" AND the existing per-RP logic is satisfied. + if attach_type != "IntegratedAuto": + return False + if _is_on_functions(): + return environ.get(_PYTHON_APPLICATIONINSIGHTS_ENABLE_TELEMETRY) == "true" + if _is_on_app_service(): + return True + if _is_on_aks(): + return _AKS_ARM_NAMESPACE_ID in environ + return False + # Fallback to legacy logic when the env var is not set if _is_on_functions(): return environ.get(_PYTHON_APPLICATIONINSIGHTS_ENABLE_TELEMETRY) == "true" if _is_on_app_service(): diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py index d471e8bca8b5..752a2a335a42 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py @@ -778,6 +778,148 @@ def test_aks_no_attach(self): # This is not an expected scenario and just tests the default self.assertFalse(_utils._is_attach_enabled()) + # Attach with APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE env var + + @patch( + "azure.monitor.opentelemetry.exporter._utils.isdir", + return_value=True, + ) + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", + }, + ) + def test_attach_type_integrated_auto_app_service(self, mock_isdir): + self.assertTrue(_utils._is_attach_enabled()) + + @patch( + "azure.monitor.opentelemetry.exporter._utils.isdir", + return_value=True, + ) + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "Manual", + }, + ) + def test_attach_type_manual_app_service(self, mock_isdir): + self.assertFalse(_utils._is_attach_enabled()) + + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "FUNCTIONS_WORKER_RUNTIME": "python", + "PYTHON_APPLICATIONINSIGHTS_ENABLE_TELEMETRY": "true", + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", + }, + clear=True, + ) + def test_attach_type_integrated_auto_functions(self): + self.assertTrue(_utils._is_attach_enabled()) + + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "FUNCTIONS_WORKER_RUNTIME": "python", + "PYTHON_APPLICATIONINSIGHTS_ENABLE_TELEMETRY": "true", + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "Manual", + }, + clear=True, + ) + def test_attach_type_manual_functions(self): + self.assertFalse(_utils._is_attach_enabled()) + + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "KUBERNETES_SERVICE_HOST": TEST_KUBERNETES_SERVICE_HOST, + "AKS_ARM_NAMESPACE_ID": TEST_AKS_ARM_NAMESPACE_ID, + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", + }, + clear=True, + ) + def test_attach_type_integrated_auto_aks(self): + self.assertTrue(_utils._is_attach_enabled()) + + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "KUBERNETES_SERVICE_HOST": TEST_KUBERNETES_SERVICE_HOST, + "AKS_ARM_NAMESPACE_ID": TEST_AKS_ARM_NAMESPACE_ID, + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "Manual", + }, + clear=True, + ) + def test_attach_type_manual_aks(self): + self.assertFalse(_utils._is_attach_enabled()) + + @patch( + "azure.monitor.opentelemetry.exporter._utils.isdir", + return_value=False, + ) + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", + }, + ) + def test_attach_type_integrated_auto_app_service_no_isdir_check(self, mock_isdir): + # With the env var set, isdir is not checked - attach type is authoritative + self.assertTrue(_utils._is_attach_enabled()) + + @patch( + "azure.monitor.opentelemetry.exporter._utils.isdir", + return_value=True, + ) + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + {"WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME}, + ) + def test_attach_fallback_no_env_var_app_service(self, mock_isdir): + # Without the env var, falls back to legacy isdir check + self.assertTrue(_utils._is_attach_enabled()) + + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "FUNCTIONS_WORKER_RUNTIME": "python", + "PYTHON_APPLICATIONINSIGHTS_ENABLE_TELEMETRY": "true", + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", + }, + clear=True, + ) + def test_attach_type_integrated_auto_functions_still_checks_enable_telemetry(self): + # IntegratedAuto still requires the per-RP enable telemetry check + self.assertTrue(_utils._is_attach_enabled()) + + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "FUNCTIONS_WORKER_RUNTIME": "python", + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", + }, + clear=True, + ) + def test_attach_type_integrated_auto_functions_no_enable_telemetry(self): + # IntegratedAuto but ENABLE_TELEMETRY not set - should be false + self.assertFalse(_utils._is_attach_enabled()) + + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "KUBERNETES_SERVICE_HOST": TEST_KUBERNETES_SERVICE_HOST, + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", + }, + clear=True, + ) + def test_attach_type_integrated_auto_aks_no_arm_namespace(self): + # IntegratedAuto but AKS_ARM_NAMESPACE_ID not set - should be false + self.assertFalse(_utils._is_attach_enabled()) + # Synthetic def test_is_synthetic_source_bot(self): From 3ab2795d7bce3cf4b8f25fd4f3fb54a0df814105 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Mon, 18 May 2026 10:53:22 -0700 Subject: [PATCH 2/5] Update edge case logic --- .../azure/monitor/opentelemetry/exporter/_utils.py | 8 +------- .../tests/test_utils.py | 8 ++++---- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py index 91fd756de074..5b0b41d7eb1b 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py @@ -73,14 +73,8 @@ def _is_attach_enabled(): if attach_type is not None: # If the env var is set, attach is only enabled if the value is # "IntegratedAuto" AND the existing per-RP logic is satisfied. - if attach_type != "IntegratedAuto": - return False - if _is_on_functions(): - return environ.get(_PYTHON_APPLICATIONINSIGHTS_ENABLE_TELEMETRY) == "true" - if _is_on_app_service(): + if attach_type == "IntegratedAuto": return True - if _is_on_aks(): - return _AKS_ARM_NAMESPACE_ID in environ return False # Fallback to legacy logic when the env var is not set if _is_on_functions(): diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py index 752a2a335a42..c652f1e14262 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py @@ -905,8 +905,8 @@ def test_attach_type_integrated_auto_functions_still_checks_enable_telemetry(sel clear=True, ) def test_attach_type_integrated_auto_functions_no_enable_telemetry(self): - # IntegratedAuto but ENABLE_TELEMETRY not set - should be false - self.assertFalse(_utils._is_attach_enabled()) + # IntegratedAuto but ENABLE_TELEMETRY not set. Should be true. Env var overwrites other factors. + self.assertTrue(_utils._is_attach_enabled()) @patch.dict( "azure.monitor.opentelemetry.exporter._utils.environ", @@ -917,8 +917,8 @@ def test_attach_type_integrated_auto_functions_no_enable_telemetry(self): clear=True, ) def test_attach_type_integrated_auto_aks_no_arm_namespace(self): - # IntegratedAuto but AKS_ARM_NAMESPACE_ID not set - should be false - self.assertFalse(_utils._is_attach_enabled()) + # IntegratedAuto but AKS_ARM_NAMESPACE_ID not set. Should be true. Env var overwrites other factors. + self.assertTrue(_utils._is_attach_enabled()) # Synthetic From 26ccb1c9bcaaaeb6e898b7ba4151a4fadfb99968 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Thu, 28 May 2026 14:50:20 -0700 Subject: [PATCH 3/5] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../tests/test_utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py index c652f1e14262..965ca0729c82 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py @@ -867,9 +867,10 @@ def test_attach_type_manual_aks(self): "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", }, ) - def test_attach_type_integrated_auto_app_service_no_isdir_check(self, mock_isdir): - # With the env var set, isdir is not checked - attach type is authoritative - self.assertTrue(_utils._is_attach_enabled()) + def test_attach_type_integrated_auto_app_service_requires_isdir_check(self, mock_isdir): + # Even with IntegratedAuto, App Service attach still follows the legacy isdir gate. + self.assertFalse(_utils._is_attach_enabled()) + mock_isdir.assert_called() @patch( "azure.monitor.opentelemetry.exporter._utils.isdir", From 4775f417aa82a7b2b0988fdd056916df6ed3c6c4 Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Thu, 28 May 2026 14:56:02 -0700 Subject: [PATCH 4/5] feedback --- .../monitor/opentelemetry/exporter/_utils.py | 2 +- .../tests/test_utils.py | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py index 5b0b41d7eb1b..87e07705be8f 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_utils.py @@ -73,7 +73,7 @@ def _is_attach_enabled(): if attach_type is not None: # If the env var is set, attach is only enabled if the value is # "IntegratedAuto" AND the existing per-RP logic is satisfied. - if attach_type == "IntegratedAuto": + if attach_type.lower() == "integratedauto": return True return False # Fallback to legacy logic when the env var is not set diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py index 965ca0729c82..d11133524bc5 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py @@ -731,6 +731,7 @@ def test_get_sdk_version_prefix_aks_windows_attach(self, mock_system): @patch.dict( "azure.monitor.opentelemetry.exporter._utils.environ", {"WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME}, + clear=True, ) def test_attach_enabled(self, mock_isdir): self.assertEqual(_utils._is_attach_enabled(), True) @@ -742,6 +743,7 @@ def test_attach_enabled(self, mock_isdir): @patch.dict( "azure.monitor.opentelemetry.exporter._utils.environ", {"WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME}, + clear=True, ) def test_attach_app_service_disabled(self, mock_isdir): self.assertEqual(_utils._is_attach_enabled(), False) @@ -794,6 +796,34 @@ def test_aks_no_attach(self): def test_attach_type_integrated_auto_app_service(self, mock_isdir): self.assertTrue(_utils._is_attach_enabled()) + @patch( + "azure.monitor.opentelemetry.exporter._utils.isdir", + return_value=True, + ) + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "integratedauto", + }, + ) + def test_attach_type_integrated_auto_app_service_lower(self, mock_isdir): + self.assertTrue(_utils._is_attach_enabled()) + + @patch( + "azure.monitor.opentelemetry.exporter._utils.isdir", + return_value=True, + ) + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "INTEGRATEDAUTO", + }, + ) + def test_attach_type_integrated_auto_app_service_upper(self, mock_isdir): + self.assertTrue(_utils._is_attach_enabled()) + @patch( "azure.monitor.opentelemetry.exporter._utils.isdir", return_value=True, @@ -879,6 +909,7 @@ def test_attach_type_integrated_auto_app_service_requires_isdir_check(self, mock @patch.dict( "azure.monitor.opentelemetry.exporter._utils.environ", {"WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME}, + clear=True, ) def test_attach_fallback_no_env_var_app_service(self, mock_isdir): # Without the env var, falls back to legacy isdir check From a9c1a5cb200ce748cc15c3730f2b421b368db8ca Mon Sep 17 00:00:00 2001 From: Jeremy Voss Date: Thu, 28 May 2026 15:07:18 -0700 Subject: [PATCH 5/5] refactor tests --- .../tests/test_utils.py | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py index d11133524bc5..93ee5b91c273 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/test_utils.py @@ -782,6 +782,16 @@ def test_aks_no_attach(self): # Attach with APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE env var + @patch.dict( + "azure.monitor.opentelemetry.exporter._utils.environ", + { + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", + }, + clear=True, + ) + def test_attach_type_integrated_auto_app_service(self): + self.assertTrue(_utils._is_attach_enabled()) + @patch( "azure.monitor.opentelemetry.exporter._utils.isdir", return_value=True, @@ -792,9 +802,11 @@ def test_aks_no_attach(self): "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", }, + clear=True, ) def test_attach_type_integrated_auto_app_service(self, mock_isdir): self.assertTrue(_utils._is_attach_enabled()) + mock_isdir.assert_not_called() @patch( "azure.monitor.opentelemetry.exporter._utils.isdir", @@ -806,9 +818,11 @@ def test_attach_type_integrated_auto_app_service(self, mock_isdir): "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "integratedauto", }, + clear=True, ) def test_attach_type_integrated_auto_app_service_lower(self, mock_isdir): self.assertTrue(_utils._is_attach_enabled()) + mock_isdir.assert_not_called() @patch( "azure.monitor.opentelemetry.exporter._utils.isdir", @@ -820,9 +834,11 @@ def test_attach_type_integrated_auto_app_service_lower(self, mock_isdir): "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "INTEGRATEDAUTO", }, + clear=True, ) def test_attach_type_integrated_auto_app_service_upper(self, mock_isdir): self.assertTrue(_utils._is_attach_enabled()) + mock_isdir.assert_not_called() @patch( "azure.monitor.opentelemetry.exporter._utils.isdir", @@ -834,6 +850,7 @@ def test_attach_type_integrated_auto_app_service_upper(self, mock_isdir): "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "Manual", }, + clear=True, ) def test_attach_type_manual_app_service(self, mock_isdir): self.assertFalse(_utils._is_attach_enabled()) @@ -897,35 +914,38 @@ def test_attach_type_manual_aks(self): "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", }, ) - def test_attach_type_integrated_auto_app_service_requires_isdir_check(self, mock_isdir): - # Even with IntegratedAuto, App Service attach still follows the legacy isdir gate. - self.assertFalse(_utils._is_attach_enabled()) - mock_isdir.assert_called() + def test_attach_type_integrated_auto_app_service_no_isdir_check(self, mock_isdir): + # APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE overrides the legacy isdir gate. + self.assertTrue(_utils._is_attach_enabled()) + mock_isdir.assert_not_called() @patch( "azure.monitor.opentelemetry.exporter._utils.isdir", - return_value=True, + return_value=False, ) @patch.dict( "azure.monitor.opentelemetry.exporter._utils.environ", - {"WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME}, - clear=True, + { + "WEBSITE_SITE_NAME": TEST_WEBSITE_SITE_NAME, + "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "manual", + }, ) - def test_attach_fallback_no_env_var_app_service(self, mock_isdir): - # Without the env var, falls back to legacy isdir check - self.assertTrue(_utils._is_attach_enabled()) + def test_attach_type_manual_app_service_no_isdir_check(self, mock_isdir): + # APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE overrides the legacy isdir gate. + self.assertFalse(_utils._is_attach_enabled()) + mock_isdir.assert_not_called() @patch.dict( "azure.monitor.opentelemetry.exporter._utils.environ", { "FUNCTIONS_WORKER_RUNTIME": "python", - "PYTHON_APPLICATIONINSIGHTS_ENABLE_TELEMETRY": "true", + "PYTHON_APPLICATIONINSIGHTS_ENABLE_TELEMETRY": "false", "APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE": "IntegratedAuto", }, clear=True, ) - def test_attach_type_integrated_auto_functions_still_checks_enable_telemetry(self): - # IntegratedAuto still requires the per-RP enable telemetry check + def test_attach_type_integrated_auto_functions_enable_telemetry_false(self): + # APPLICATIONINSIGHTS_PYTHON_ATTACHTYPE overrides the legacy PYTHON_APPLICATIONINSIGHTS_ENABLE_TELEMETRY check. self.assertTrue(_utils._is_attach_enabled()) @patch.dict(