Skip to content

Commit b33e262

Browse files
authored
disable django instrumentation if DJANGO_SETTINGS_MODULE is not set (#549)
*Issue #, if available:* When using the OpenTelemetry Django instrumentation, users must set the DJANGO_SETTINGS_MODULE environment variable before Python starts. Otherwise, Django will fail to launch because it cannot locate the required settings module. *Description of changes:* In the ADOT distribution, we can add logic so that if Django is installed, the Django instrumentation is enabled only when the DJANGO_SETTINGS_MODULE environment variable is present. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
1 parent 972dec9 commit b33e262

File tree

3 files changed

+140
-2
lines changed

3 files changed

+140
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ For any change that affects end users of this package, please add an entry under
1111
If your change does not need a CHANGELOG entry, add the "skip changelog" label to your PR.
1212

1313
## Unreleased
14+
- Disable django instrumentation if DJANGO_SETTINGS_MODULE is not set
15+
([#549](https://github.com/aws-observability/aws-otel-python-instrumentation/pull/549))
1416
- [PATCH] Add safety check for bedrock ConverseStream responses
1517
([#547](https://github.com/aws-observability/aws-otel-python-instrumentation/pull/547))
1618
- Add Service and Environment dimensions to EMF metrics when Application Signals EMF export is enabled

aws-opentelemetry-distro/src/amazon/opentelemetry/distro/aws_opentelemetry_distro.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import sys
1717
from logging import ERROR, Logger, getLogger
1818

19-
from amazon.opentelemetry.distro._utils import get_aws_region, is_agent_observability_enabled
19+
from amazon.opentelemetry.distro._utils import get_aws_region, is_agent_observability_enabled, is_installed
2020
from amazon.opentelemetry.distro.aws_opentelemetry_configurator import (
2121
APPLICATION_SIGNALS_ENABLED_CONFIG,
2222
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
@@ -86,6 +86,21 @@ def _configure(self, **kwargs):
8686
if cwd_path not in sys.path:
8787
sys.path.insert(0, cwd_path)
8888

89+
# Check if Django is installed and determine if Django instrumentation should be enabled
90+
if is_installed("django"):
91+
# Django instrumentation is allowed when DJANGO_SETTINGS_MODULE is set
92+
if not os.getenv("DJANGO_SETTINGS_MODULE"):
93+
# DJANGO_SETTINGS_MODULE is not set, disable Django instrumentation
94+
disabled_instrumentations = os.getenv("OTEL_PYTHON_DISABLED_INSTRUMENTATIONS", "")
95+
os.environ["OTEL_PYTHON_DISABLED_INSTRUMENTATIONS"] = disabled_instrumentations + ",django"
96+
_logger.warning(
97+
"Django is installed but DJANGO_SETTINGS_MODULE is not set. Disabling django instrumentation."
98+
)
99+
else:
100+
_logger.debug(
101+
"Django instrumentation enabled: DJANGO_SETTINGS_MODULE=%s", os.getenv("DJANGO_SETTINGS_MODULE")
102+
)
103+
89104
os.environ.setdefault(OTEL_EXPORTER_OTLP_PROTOCOL, "http/protobuf")
90105

91106
if os.environ.get(OTEL_PROPAGATORS, None) is None:

aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/test_aws_opentelemetry_distro.py

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def setUp(self):
3232
"OTEL_PYTHON_DISABLED_INSTRUMENTATIONS",
3333
"OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED",
3434
"OTEL_AWS_APPLICATION_SIGNALS_ENABLED",
35+
"DJANGO_SETTINGS_MODULE",
3536
]
3637

3738
# First, save all current values
@@ -100,14 +101,21 @@ def test_configure_without_patches(self, mock_super_configure, mock_apply_patche
100101

101102
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.get_aws_region")
102103
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.is_agent_observability_enabled")
104+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.is_installed")
103105
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.apply_instrumentation_patches")
104106
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.OpenTelemetryDistro._configure")
105107
def test_configure_with_agent_observability_enabled(
106-
self, mock_super_configure, mock_apply_patches, mock_is_agent_observability, mock_get_aws_region
108+
self,
109+
mock_super_configure,
110+
mock_apply_patches,
111+
mock_is_installed,
112+
mock_is_agent_observability,
113+
mock_get_aws_region,
107114
):
108115
"""Test that _configure sets agent observability defaults when enabled"""
109116
mock_is_agent_observability.return_value = True
110117
mock_get_aws_region.return_value = "us-west-2"
118+
mock_is_installed.return_value = False # Mock Django as not installed to avoid interference
111119

112120
distro = AwsOpenTelemetryDistro()
113121
distro._configure()
@@ -277,3 +285,116 @@ def test_otel_propagators_added_when_not_user_defined(self, mock_super_configure
277285
for prop in individual_propagators:
278286
actual_propagators.append(type(prop).__name__)
279287
self.assertEqual(expected_propagators, actual_propagators)
288+
289+
# Django Instrumentation Tests
290+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.is_installed")
291+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.apply_instrumentation_patches")
292+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.OpenTelemetryDistro._configure")
293+
def test_django_instrumentation_enabled_with_settings_module(
294+
self, mock_super_configure, mock_apply_patches, mock_is_installed
295+
):
296+
"""Test that Django instrumentation is enabled when DJANGO_SETTINGS_MODULE is set"""
297+
mock_is_installed.return_value = True
298+
os.environ["DJANGO_SETTINGS_MODULE"] = "myproject.settings"
299+
300+
distro = AwsOpenTelemetryDistro()
301+
distro._configure()
302+
303+
# Verify that django is NOT in disabled instrumentations
304+
disabled_instrumentations = os.environ.get("OTEL_PYTHON_DISABLED_INSTRUMENTATIONS", "")
305+
self.assertNotIn("django", disabled_instrumentations)
306+
307+
mock_is_installed.assert_called_once_with("django")
308+
309+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.is_installed")
310+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.apply_instrumentation_patches")
311+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.OpenTelemetryDistro._configure")
312+
def test_django_instrumentation_disabled_without_settings_module(
313+
self, mock_super_configure, mock_apply_patches, mock_is_installed
314+
):
315+
"""Test that Django instrumentation is disabled when DJANGO_SETTINGS_MODULE is not set"""
316+
mock_is_installed.return_value = True
317+
318+
distro = AwsOpenTelemetryDistro()
319+
distro._configure()
320+
321+
# Verify that django is in disabled instrumentations
322+
disabled_instrumentations = os.environ.get("OTEL_PYTHON_DISABLED_INSTRUMENTATIONS", "")
323+
self.assertIn("django", disabled_instrumentations)
324+
325+
mock_is_installed.assert_called_once_with("django")
326+
327+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.is_installed")
328+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.apply_instrumentation_patches")
329+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.OpenTelemetryDistro._configure")
330+
def test_django_instrumentation_disabled_with_existing_disabled_instrumentations(
331+
self, mock_super_configure, mock_apply_patches, mock_is_installed
332+
):
333+
"""Test that Django is appended to existing disabled instrumentations"""
334+
mock_is_installed.return_value = True
335+
os.environ["OTEL_PYTHON_DISABLED_INSTRUMENTATIONS"] = "flask,fastapi"
336+
337+
distro = AwsOpenTelemetryDistro()
338+
distro._configure()
339+
340+
# Verify that django is appended to existing disabled instrumentations
341+
disabled_instrumentations = os.environ.get("OTEL_PYTHON_DISABLED_INSTRUMENTATIONS", "")
342+
self.assertEqual("flask,fastapi,django", disabled_instrumentations)
343+
344+
mock_is_installed.assert_called_once_with("django")
345+
346+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.is_installed")
347+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.apply_instrumentation_patches")
348+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.OpenTelemetryDistro._configure")
349+
def test_django_not_installed_no_effect(self, mock_super_configure, mock_apply_patches, mock_is_installed):
350+
"""Test that when Django is not installed, no changes are made to disabled instrumentations"""
351+
mock_is_installed.return_value = False
352+
353+
distro = AwsOpenTelemetryDistro()
354+
distro._configure()
355+
356+
# Verify that OTEL_PYTHON_DISABLED_INSTRUMENTATIONS is not affected
357+
disabled_instrumentations = os.environ.get("OTEL_PYTHON_DISABLED_INSTRUMENTATIONS", "")
358+
self.assertEqual("", disabled_instrumentations)
359+
360+
mock_is_installed.assert_called_once_with("django")
361+
362+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.is_installed")
363+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.apply_instrumentation_patches")
364+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.OpenTelemetryDistro._configure")
365+
def test_django_instrumentation_enabled_with_settings_module_and_existing_disabled(
366+
self, mock_super_configure, mock_apply_patches, mock_is_installed
367+
):
368+
"""Test that Django instrumentation is enabled even with existing disabled instrumentations"""
369+
mock_is_installed.return_value = True
370+
os.environ["DJANGO_SETTINGS_MODULE"] = "myproject.settings"
371+
os.environ["OTEL_PYTHON_DISABLED_INSTRUMENTATIONS"] = "flask,fastapi"
372+
373+
distro = AwsOpenTelemetryDistro()
374+
distro._configure()
375+
376+
# Verify that django is NOT added to disabled instrumentations
377+
disabled_instrumentations = os.environ.get("OTEL_PYTHON_DISABLED_INSTRUMENTATIONS", "")
378+
self.assertEqual("flask,fastapi", disabled_instrumentations)
379+
self.assertNotIn("django", disabled_instrumentations)
380+
381+
mock_is_installed.assert_called_once_with("django")
382+
383+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.is_installed")
384+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.apply_instrumentation_patches")
385+
@patch("amazon.opentelemetry.distro.aws_opentelemetry_distro.OpenTelemetryDistro._configure")
386+
def test_django_instrumentation_disabled_empty_settings_module(
387+
self, mock_super_configure, mock_apply_patches, mock_is_installed
388+
):
389+
"""Test that Django instrumentation is disabled when DJANGO_SETTINGS_MODULE is empty"""
390+
mock_is_installed.return_value = True
391+
os.environ["DJANGO_SETTINGS_MODULE"] = ""
392+
393+
distro = AwsOpenTelemetryDistro()
394+
distro._configure()
395+
396+
# Verify that django is in disabled instrumentations
397+
disabled_instrumentations = os.environ.get("OTEL_PYTHON_DISABLED_INSTRUMENTATIONS", "")
398+
self.assertIn("django", disabled_instrumentations)
399+
400+
mock_is_installed.assert_called_once_with("django")

0 commit comments

Comments
 (0)