diff --git a/aws-opentelemetry-distro/pyproject.toml b/aws-opentelemetry-distro/pyproject.toml index 3735545db..eaebe2ecd 100644 --- a/aws-opentelemetry-distro/pyproject.toml +++ b/aws-opentelemetry-distro/pyproject.toml @@ -26,63 +26,63 @@ classifiers = [ ] dependencies = [ - "opentelemetry-api == 1.37.0", - "opentelemetry-sdk == 1.37.0", - "opentelemetry-exporter-otlp-proto-grpc == 1.37.0", - "opentelemetry-exporter-otlp-proto-http == 1.37.0", - "opentelemetry-propagator-b3 == 1.37.0", - "opentelemetry-propagator-jaeger == 1.37.0", - "opentelemetry-exporter-otlp-proto-common == 1.37.0", - "opentelemetry-sdk-extension-aws == 2.0.2", - "opentelemetry-propagator-aws-xray == 1.0.1", - "opentelemetry-distro == 0.58b0", - "opentelemetry-processor-baggage == 0.58b0", - "opentelemetry-propagator-ot-trace == 0.58b0", - "opentelemetry-instrumentation == 0.58b0", - "opentelemetry-instrumentation-aws-lambda == 0.58b0", - "opentelemetry-instrumentation-aio-pika == 0.58b0", - "opentelemetry-instrumentation-aiohttp-client == 0.58b0", - "opentelemetry-instrumentation-aiokafka == 0.58b0", - "opentelemetry-instrumentation-aiopg == 0.58b0", - "opentelemetry-instrumentation-asgi == 0.58b0", - "opentelemetry-instrumentation-asyncpg == 0.58b0", - "opentelemetry-instrumentation-boto == 0.58b0", - "opentelemetry-instrumentation-boto3sqs == 0.58b0", - "opentelemetry-instrumentation-botocore == 0.58b0", - "opentelemetry-instrumentation-celery == 0.58b0", - "opentelemetry-instrumentation-confluent-kafka == 0.58b0", - "opentelemetry-instrumentation-dbapi == 0.58b0", - "opentelemetry-instrumentation-django == 0.58b0", - "opentelemetry-instrumentation-elasticsearch == 0.58b0", - "opentelemetry-instrumentation-falcon == 0.58b0", - "opentelemetry-instrumentation-fastapi == 0.58b0", - "opentelemetry-instrumentation-flask == 0.58b0", - "opentelemetry-instrumentation-grpc == 0.58b0", - "opentelemetry-instrumentation-httpx == 0.58b0", - "opentelemetry-instrumentation-jinja2 == 0.58b0", - "opentelemetry-instrumentation-kafka-python == 0.58b0", - "opentelemetry-instrumentation-logging == 0.58b0", - "opentelemetry-instrumentation-mysql == 0.58b0", - "opentelemetry-instrumentation-mysqlclient == 0.58b0", - "opentelemetry-instrumentation-pika == 0.58b0", - "opentelemetry-instrumentation-psycopg2 == 0.58b0", - "opentelemetry-instrumentation-pymemcache == 0.58b0", - "opentelemetry-instrumentation-pymongo == 0.58b0", - "opentelemetry-instrumentation-pymysql == 0.58b0", - "opentelemetry-instrumentation-pyramid == 0.58b0", - "opentelemetry-instrumentation-redis == 0.58b0", - "opentelemetry-instrumentation-remoulade == 0.58b0", - "opentelemetry-instrumentation-requests == 0.58b0", - "opentelemetry-instrumentation-sqlalchemy == 0.58b0", - "opentelemetry-instrumentation-sqlite3 == 0.58b0", - "opentelemetry-instrumentation-starlette == 0.58b0", - "opentelemetry-instrumentation-system-metrics == 0.58b0", - "opentelemetry-instrumentation-tornado == 0.58b0", - "opentelemetry-instrumentation-tortoiseorm == 0.58b0", - "opentelemetry-instrumentation-urllib == 0.58b0", - "opentelemetry-instrumentation-urllib3 == 0.58b0", - "opentelemetry-instrumentation-wsgi == 0.58b0", - "opentelemetry-instrumentation-cassandra == 0.58b0", + "opentelemetry-api == 1.39.1", + "opentelemetry-sdk == 1.39.1", + "opentelemetry-exporter-otlp-proto-grpc == 1.39.1", + "opentelemetry-exporter-otlp-proto-http == 1.39.1", + "opentelemetry-propagator-b3 == 1.39.1", + "opentelemetry-propagator-jaeger == 1.39.1", + "opentelemetry-exporter-otlp-proto-common == 1.39.1", + "opentelemetry-sdk-extension-aws == 2.1.0", + "opentelemetry-propagator-aws-xray == 1.0.2", + "opentelemetry-distro == 0.60b1", + "opentelemetry-processor-baggage == 0.60b1", + "opentelemetry-propagator-ot-trace == 0.60b1", + "opentelemetry-instrumentation == 0.60b1", + "opentelemetry-instrumentation-aws-lambda == 0.60b1", + "opentelemetry-instrumentation-aio-pika == 0.60b1", + "opentelemetry-instrumentation-aiohttp-client == 0.60b1", + "opentelemetry-instrumentation-aiokafka == 0.60b1", + "opentelemetry-instrumentation-aiopg == 0.60b1", + "opentelemetry-instrumentation-asgi == 0.60b1", + "opentelemetry-instrumentation-asyncpg == 0.60b1", + "opentelemetry-instrumentation-boto == 0.60b1", + "opentelemetry-instrumentation-boto3sqs == 0.60b1", + "opentelemetry-instrumentation-botocore == 0.60b1", + "opentelemetry-instrumentation-celery == 0.60b1", + "opentelemetry-instrumentation-confluent-kafka == 0.60b1", + "opentelemetry-instrumentation-dbapi == 0.60b1", + "opentelemetry-instrumentation-django == 0.60b1", + "opentelemetry-instrumentation-elasticsearch == 0.60b1", + "opentelemetry-instrumentation-falcon == 0.60b1", + "opentelemetry-instrumentation-fastapi == 0.60b1", + "opentelemetry-instrumentation-flask == 0.60b1", + "opentelemetry-instrumentation-grpc == 0.60b1", + "opentelemetry-instrumentation-httpx == 0.60b1", + "opentelemetry-instrumentation-jinja2 == 0.60b1", + "opentelemetry-instrumentation-kafka-python == 0.60b1", + "opentelemetry-instrumentation-logging == 0.60b1", + "opentelemetry-instrumentation-mysql == 0.60b1", + "opentelemetry-instrumentation-mysqlclient == 0.60b1", + "opentelemetry-instrumentation-pika == 0.60b1", + "opentelemetry-instrumentation-psycopg2 == 0.60b1", + "opentelemetry-instrumentation-pymemcache == 0.60b1", + "opentelemetry-instrumentation-pymongo == 0.60b1", + "opentelemetry-instrumentation-pymysql == 0.60b1", + "opentelemetry-instrumentation-pyramid == 0.60b1", + "opentelemetry-instrumentation-redis == 0.60b1", + "opentelemetry-instrumentation-remoulade == 0.60b1", + "opentelemetry-instrumentation-requests == 0.60b1", + "opentelemetry-instrumentation-sqlalchemy == 0.60b1", + "opentelemetry-instrumentation-sqlite3 == 0.60b1", + "opentelemetry-instrumentation-starlette == 0.60b1", + "opentelemetry-instrumentation-system-metrics == 0.60b1", + "opentelemetry-instrumentation-tornado == 0.60b1", + "opentelemetry-instrumentation-tortoiseorm == 0.60b1", + "opentelemetry-instrumentation-urllib == 0.60b1", + "opentelemetry-instrumentation-urllib3 == 0.60b1", + "opentelemetry-instrumentation-wsgi == 0.60b1", + "opentelemetry-instrumentation-cassandra == 0.60b1", ] [project.optional-dependencies] diff --git a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/aws_opentelemetry_configurator.py b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/aws_opentelemetry_configurator.py index 41fa542db..286de5335 100644 --- a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/aws_opentelemetry_configurator.py +++ b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/aws_opentelemetry_configurator.py @@ -95,7 +95,7 @@ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT" OTEL_EXPORTER_OTLP_LOGS_HEADERS = "OTEL_EXPORTER_OTLP_LOGS_HEADERS" -CODE_CORRELATION_ENABLED_CONFIG = "OTEL_AWS_CODE_CORRELATION_ENABLED" +OTEL_AWS_ENHANCED_CODE_ATTRIBUTES = "OTEL_AWS_ENHANCED_CODE_ATTRIBUTES" XRAY_SERVICE = "xray" LOGS_SERIVCE = "logs" @@ -473,7 +473,7 @@ def _customize_logs_exporter(log_exporter: LogExporter) -> LogExporter: def _customize_span_processors(provider: TracerProvider, resource: Resource) -> None: - if get_code_correlation_enabled_status() is True: + if is_enhanced_code_attributes() is True: # pylint: disable=import-outside-toplevel from amazon.opentelemetry.distro.code_correlation import CodeAttributesSpanProcessor @@ -622,32 +622,21 @@ def _is_application_signals_runtime_enabled(): ) -def get_code_correlation_enabled_status() -> Optional[bool]: +def is_enhanced_code_attributes() -> bool: """ - Get the code correlation enabled status from environment variable. + Get the enhanced code attributes enabled status from environment variable. Returns: - True if OTEL_AWS_CODE_CORRELATION_ENABLED is set to 'true' - False if OTEL_AWS_CODE_CORRELATION_ENABLED is set to 'false' - None if OTEL_AWS_CODE_CORRELATION_ENABLED is not set (default state) + True if OTEL_AWS_ENHANCED_CODE_ATTRIBUTES is set to 'true' + else False """ - env_value = os.environ.get(CODE_CORRELATION_ENABLED_CONFIG) - - if env_value is None: - return None # Default state - environment variable not set + env_value = os.environ.get(OTEL_AWS_ENHANCED_CODE_ATTRIBUTES, "false") env_value_lower = env_value.strip().lower() if env_value_lower == "true": return True - if env_value_lower == "false": - return False - # Invalid value, treat as default and log warning - _logger.warning( - "Invalid value for %s: %s. Expected 'true' or 'false'. Using default.", - CODE_CORRELATION_ENABLED_CONFIG, - env_value, - ) - return None + + return False def _is_lambda_environment(): diff --git a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/code_correlation/config.py b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/code_correlation/config.py index 5271a0fe6..627aeb4f8 100644 --- a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/code_correlation/config.py +++ b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/code_correlation/config.py @@ -15,12 +15,12 @@ from typing import Any, Dict, List, Optional # Environment variable constants -_ENV_CONFIG = "OTEL_AWS_CODE_CORRELATION_CONFIG" +_ENV_CONFIG = "OTEL_AWS_CODE_ATTRIBUTES_CONFIG" _logger = logging.getLogger(__name__) -class AwsCodeCorrelationConfig: +class AwsCodeAttributesConfig: """ Configuration manager for AWS OpenTelemetry code correlation features. @@ -29,10 +29,10 @@ class AwsCodeCorrelationConfig: and stack trace depth configuration. Environment Variables: - OTEL_AWS_CODE_CORRELATION_CONFIG: JSON configuration with detailed settings + OTEL_AWS_CODE_ATTRIBUTES_CONFIG: JSON configuration with detailed settings Example Configuration: - export OTEL_AWS_CODE_CORRELATION_CONFIG='{ + export OTEL_AWS_CODE_ATTRIBUTES_CONFIG='{ "include": ["myapp", "mylib"], "exclude": ["third-party", "vendor"], "stack_depth": 5 @@ -55,12 +55,12 @@ def __init__( self.stack_depth = stack_depth @classmethod - def from_env(cls) -> "AwsCodeCorrelationConfig": + def from_env(cls) -> "AwsCodeAttributesConfig": """ Create configuration instance from environment variables. Returns: - AwsCodeCorrelationConfig: Configured instance + AwsCodeAttributesConfig: Configured instance """ config_data = cls._parse_config_data() include_value = cls._validate_string_list(config_data, "include") @@ -168,7 +168,7 @@ def to_json(self, indent: Optional[int] = 2) -> str: def __repr__(self) -> str: """Return string representation of the configuration.""" return ( - f"AwsCodeCorrelationConfig(" + f"AwsCodeAttributesConfig(" f"include={self.include}, " f"exclude={self.exclude}, " f"stack_depth={self.stack_depth})" diff --git a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/code_correlation/internal/packages_resolver.py b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/code_correlation/internal/packages_resolver.py index 209dfa485..b2ad5c261 100644 --- a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/code_correlation/internal/packages_resolver.py +++ b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/code_correlation/internal/packages_resolver.py @@ -20,13 +20,13 @@ from pathlib import Path from typing import Any, Callable, Dict, List, NamedTuple, Optional, Set, Union -from ..config import AwsCodeCorrelationConfig +from ..config import AwsCodeAttributesConfig # Module-level constants _logger = logging.getLogger(__name__) # Configuration -_code_attributes_config = AwsCodeCorrelationConfig.from_env() +_code_attributes_config = AwsCodeAttributesConfig.from_env() # Global caching variables _sys_path_hash: Optional[int] = None diff --git a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_aio_pika_patches.py b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_aio_pika_patches.py index e7a209fd5..2d6cdd75b 100644 --- a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_aio_pika_patches.py +++ b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_aio_pika_patches.py @@ -9,7 +9,6 @@ import functools import logging -from amazon.opentelemetry.distro.aws_opentelemetry_configurator import get_code_correlation_enabled_status from amazon.opentelemetry.distro.code_correlation.utils import record_code_attributes logger = logging.getLogger(__name__) @@ -32,9 +31,6 @@ def patched_decorate(self, callback): def _apply_aio_pika_instrumentation_patches(): """Apply aio-pika patches if code correlation is enabled.""" try: - if get_code_correlation_enabled_status() is not True: - return - # Import CallbackDecorator inside function to allow proper testing try: # pylint: disable=import-outside-toplevel diff --git a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_celery_patches.py b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_celery_patches.py index f3fdbe047..c8494143f 100644 --- a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_celery_patches.py +++ b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_celery_patches.py @@ -12,7 +12,6 @@ import logging from typing import Any, Callable, Optional -from amazon.opentelemetry.distro.aws_opentelemetry_configurator import get_code_correlation_enabled_status from amazon.opentelemetry.distro.code_correlation.utils import add_code_attributes_to_span logger = logging.getLogger(__name__) @@ -125,9 +124,6 @@ def _apply_celery_instrumentation_patches(): Apply code correlation patches to the Celery instrumentation. """ try: - if get_code_correlation_enabled_status() is not True: - return - if CeleryInstrumentor is None: logger.warning("Failed to apply Celery patches: CeleryInstrumentor not available") return diff --git a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_django_patches.py b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_django_patches.py index 0b1c40494..cd294c5aa 100644 --- a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_django_patches.py +++ b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_django_patches.py @@ -4,8 +4,6 @@ from logging import getLogger -from amazon.opentelemetry.distro.aws_opentelemetry_configurator import get_code_correlation_enabled_status - _logger = getLogger(__name__) @@ -17,8 +15,7 @@ def _apply_django_instrumentation_patches() -> None: to spans by modifying the process_view method of the Django middleware. Also patches Django's path/re_path functions for URL pattern instrumentation. """ - if get_code_correlation_enabled_status() is True: - _apply_django_code_attributes_patch() + _apply_django_code_attributes_patch() def _apply_django_code_attributes_patch() -> None: # pylint: disable=too-many-statements diff --git a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_fastapi_patches.py b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_fastapi_patches.py index 1f98fc58d..d6cdc1041 100644 --- a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_fastapi_patches.py +++ b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_fastapi_patches.py @@ -4,8 +4,6 @@ from logging import getLogger -from amazon.opentelemetry.distro.aws_opentelemetry_configurator import get_code_correlation_enabled_status - _logger = getLogger(__name__) @@ -16,8 +14,7 @@ def _apply_fastapi_instrumentation_patches() -> None: This patches the FastAPI instrumentation to automatically add code attributes to spans by decorating view functions with record_code_attributes. """ - if get_code_correlation_enabled_status() is True: - _apply_fastapi_code_attributes_patch() + _apply_fastapi_code_attributes_patch() def _apply_fastapi_code_attributes_patch() -> None: diff --git a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_flask_patches.py b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_flask_patches.py index c975b8af1..26d9be44d 100644 --- a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_flask_patches.py +++ b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_flask_patches.py @@ -4,8 +4,6 @@ from logging import getLogger -from amazon.opentelemetry.distro.aws_opentelemetry_configurator import get_code_correlation_enabled_status - _logger = getLogger(__name__) @@ -16,8 +14,7 @@ def _apply_flask_instrumentation_patches() -> None: This patches the Flask instrumentation to automatically add code attributes to spans by decorating view functions with record_code_attributes. """ - if get_code_correlation_enabled_status() is True: - _apply_flask_code_attributes_patch() + _apply_flask_code_attributes_patch() def _apply_flask_code_attributes_patch() -> None: # pylint: disable=too-many-statements diff --git a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_pika_patches.py b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_pika_patches.py index bc4824d5d..cf666f071 100644 --- a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_pika_patches.py +++ b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_pika_patches.py @@ -9,7 +9,6 @@ import functools import logging -from amazon.opentelemetry.distro.aws_opentelemetry_configurator import get_code_correlation_enabled_status from amazon.opentelemetry.distro.code_correlation.utils import add_code_attributes_to_span logger = logging.getLogger(__name__) @@ -43,9 +42,6 @@ def enhanced_consume_hook(span, body, properties): def _apply_pika_instrumentation_patches(): """Apply pika patches if code correlation is enabled.""" try: - if get_code_correlation_enabled_status() is not True: - return - # Import pika_utils inside function to allow proper testing try: # pylint: disable=import-outside-toplevel diff --git a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_starlette_patches.py b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_starlette_patches.py index 91f633bd1..eef53d210 100644 --- a/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_starlette_patches.py +++ b/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/patches/_starlette_patches.py @@ -5,7 +5,6 @@ from typing import Collection from amazon.opentelemetry.distro._utils import is_agent_observability_enabled -from amazon.opentelemetry.distro.aws_opentelemetry_configurator import get_code_correlation_enabled_status _logger: Logger = getLogger(__name__) @@ -16,8 +15,7 @@ def _apply_starlette_instrumentation_patches() -> None: This applies both version compatibility patches and code attributes support. """ _apply_starlette_version_patches() - if get_code_correlation_enabled_status() is True: - _apply_starlette_code_attributes_patch() + _apply_starlette_code_attributes_patch() # Upstream fix available in OpenTelemetry 1.34.0/0.55b0 (2025-06-04) diff --git a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/code_correlation/test_config.py b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/code_correlation/test_config.py index c28e68606..655bab8fe 100644 --- a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/code_correlation/test_config.py +++ b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/code_correlation/test_config.py @@ -6,15 +6,15 @@ from unittest import TestCase from unittest.mock import patch -from amazon.opentelemetry.distro.code_correlation.config import _ENV_CONFIG, AwsCodeCorrelationConfig +from amazon.opentelemetry.distro.code_correlation.config import _ENV_CONFIG, AwsCodeAttributesConfig -class TestAwsCodeCorrelationConfig(TestCase): - """Test the AwsCodeCorrelationConfig class.""" +class TestAwsCodeAttributesConfig(TestCase): + """Test the AwsCodeAttributesConfig class.""" def test_init_with_defaults(self): """Test initialization with default parameters.""" - config = AwsCodeCorrelationConfig() + config = AwsCodeAttributesConfig() self.assertEqual(config.include, []) self.assertEqual(config.exclude, []) @@ -22,7 +22,7 @@ def test_init_with_defaults(self): def test_init_with_none_parameters(self): """Test initialization with None parameters.""" - config = AwsCodeCorrelationConfig(include=None, exclude=None, stack_depth=0) + config = AwsCodeAttributesConfig(include=None, exclude=None, stack_depth=0) self.assertEqual(config.include, []) self.assertEqual(config.exclude, []) @@ -34,7 +34,7 @@ def test_init_with_custom_parameters(self): exclude = ["third-party", "vendor"] stack_depth = 10 - config = AwsCodeCorrelationConfig(include=include, exclude=exclude, stack_depth=stack_depth) + config = AwsCodeAttributesConfig(include=include, exclude=exclude, stack_depth=stack_depth) self.assertEqual(config.include, include) self.assertEqual(config.exclude, exclude) @@ -42,7 +42,7 @@ def test_init_with_custom_parameters(self): def test_init_with_empty_lists(self): """Test initialization with empty lists.""" - config = AwsCodeCorrelationConfig(include=[], exclude=[], stack_depth=5) + config = AwsCodeAttributesConfig(include=[], exclude=[], stack_depth=5) self.assertEqual(config.include, []) self.assertEqual(config.exclude, []) @@ -50,7 +50,7 @@ def test_init_with_empty_lists(self): def test_to_dict(self): """Test conversion to dictionary.""" - config = AwsCodeCorrelationConfig(include=["app1", "app2"], exclude=["lib1", "lib2"], stack_depth=15) + config = AwsCodeAttributesConfig(include=["app1", "app2"], exclude=["lib1", "lib2"], stack_depth=15) result = config.to_dict() @@ -59,7 +59,7 @@ def test_to_dict(self): def test_to_dict_with_defaults(self): """Test conversion to dictionary with default values.""" - config = AwsCodeCorrelationConfig() + config = AwsCodeAttributesConfig() result = config.to_dict() @@ -68,7 +68,7 @@ def test_to_dict_with_defaults(self): def test_to_json_with_indent(self): """Test conversion to JSON with indentation.""" - config = AwsCodeCorrelationConfig(include=["myapp"], exclude=["vendor"], stack_depth=5) + config = AwsCodeAttributesConfig(include=["myapp"], exclude=["vendor"], stack_depth=5) result = config.to_json(indent=2) @@ -78,7 +78,7 @@ def test_to_json_with_indent(self): def test_to_json_without_indent(self): """Test conversion to JSON without indentation.""" - config = AwsCodeCorrelationConfig(include=["myapp"], exclude=["vendor"], stack_depth=5) + config = AwsCodeAttributesConfig(include=["myapp"], exclude=["vendor"], stack_depth=5) result = config.to_json(indent=None) @@ -88,7 +88,7 @@ def test_to_json_without_indent(self): def test_to_json_default_indent(self): """Test conversion to JSON with default indentation.""" - config = AwsCodeCorrelationConfig(include=["myapp"], exclude=["vendor"], stack_depth=5) + config = AwsCodeAttributesConfig(include=["myapp"], exclude=["vendor"], stack_depth=5) result = config.to_json() @@ -98,24 +98,24 @@ def test_to_json_default_indent(self): def test_repr(self): """Test string representation.""" - config = AwsCodeCorrelationConfig(include=["app1", "app2"], exclude=["lib1"], stack_depth=10) + config = AwsCodeAttributesConfig(include=["app1", "app2"], exclude=["lib1"], stack_depth=10) result = repr(config) - expected = "AwsCodeCorrelationConfig(include=['app1', 'app2'], exclude=['lib1'], stack_depth=10)" + expected = "AwsCodeAttributesConfig(include=['app1', 'app2'], exclude=['lib1'], stack_depth=10)" self.assertEqual(result, expected) def test_repr_with_defaults(self): """Test string representation with default values.""" - config = AwsCodeCorrelationConfig() + config = AwsCodeAttributesConfig() result = repr(config) - expected = "AwsCodeCorrelationConfig(include=[], exclude=[], stack_depth=0)" + expected = "AwsCodeAttributesConfig(include=[], exclude=[], stack_depth=0)" self.assertEqual(result, expected) -class TestAwsCodeCorrelationConfigFromEnv(TestCase): # pylint: disable=too-many-public-methods +class TestAwsCodeAttributesConfigFromEnv(TestCase): # pylint: disable=too-many-public-methods """Test the from_env class method.""" def setUp(self): @@ -131,7 +131,7 @@ def tearDown(self): def test_from_env_no_environment_variable(self): """Test from_env when environment variable is not set.""" - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, []) self.assertEqual(config.exclude, []) @@ -141,7 +141,7 @@ def test_from_env_empty_environment_variable(self): """Test from_env when environment variable is empty.""" os.environ[_ENV_CONFIG] = "" - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, []) self.assertEqual(config.exclude, []) @@ -151,7 +151,7 @@ def test_from_env_whitespace_only_environment_variable(self): """Test from_env when environment variable contains only whitespace.""" os.environ[_ENV_CONFIG] = " \t\n " - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, []) self.assertEqual(config.exclude, []) @@ -161,7 +161,7 @@ def test_from_env_empty_json_object(self): """Test from_env with empty JSON object.""" os.environ[_ENV_CONFIG] = "{}" - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, []) self.assertEqual(config.exclude, []) @@ -172,7 +172,7 @@ def test_from_env_complete_configuration(self): config_data = {"include": ["myapp", "mylib"], "exclude": ["third-party", "vendor"], "stack_depth": 15} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, ["myapp", "mylib"]) self.assertEqual(config.exclude, ["third-party", "vendor"]) @@ -183,7 +183,7 @@ def test_from_env_partial_configuration(self): config_data = {"include": ["myapp"]} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, ["myapp"]) self.assertEqual(config.exclude, []) # Default value @@ -194,7 +194,7 @@ def test_from_env_only_exclude(self): config_data = {"exclude": ["vendor", "third-party"]} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, []) # Default value self.assertEqual(config.exclude, ["vendor", "third-party"]) @@ -205,7 +205,7 @@ def test_from_env_only_stack_depth(self): config_data = {"stack_depth": 25} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, []) # Default value self.assertEqual(config.exclude, []) # Default value @@ -216,7 +216,7 @@ def test_from_env_zero_stack_depth(self): config_data = {"stack_depth": 0} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.stack_depth, 0) @@ -226,7 +226,7 @@ def test_from_env_negative_stack_depth(self, mock_logger): config_data = {"stack_depth": -5} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() # Negative stack_depth should be corrected to 0 self.assertEqual(config.stack_depth, 0) @@ -244,7 +244,7 @@ def test_from_env_empty_include_list(self): config_data = {"include": [], "exclude": ["vendor"], "stack_depth": 5} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, []) self.assertEqual(config.exclude, ["vendor"]) @@ -255,7 +255,7 @@ def test_from_env_empty_exclude_list(self): config_data = {"include": ["myapp"], "exclude": [], "stack_depth": 5} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, ["myapp"]) self.assertEqual(config.exclude, []) @@ -266,7 +266,7 @@ def test_from_env_single_item_lists(self): config_data = {"include": ["single_app"], "exclude": ["single_vendor"]} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, ["single_app"]) self.assertEqual(config.exclude, ["single_vendor"]) @@ -276,7 +276,7 @@ def test_from_env_invalid_json(self, mock_logger): """Test from_env with invalid JSON.""" os.environ[_ENV_CONFIG] = "invalid json {" - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() # Should use default values when JSON is invalid self.assertEqual(config.include, []) @@ -294,7 +294,7 @@ def test_from_env_malformed_json_syntax_error(self, mock_logger): """Test from_env with malformed JSON that causes syntax error.""" os.environ[_ENV_CONFIG] = '{"include": ["app1", "app2"' # Missing closing bracket and brace - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() # Should use default values self.assertEqual(config.include, []) @@ -309,7 +309,7 @@ def test_from_env_non_object_json(self, mock_logger): """Test from_env with valid JSON that's not an object.""" os.environ[_ENV_CONFIG] = '["not", "an", "object"]' - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() # Should handle gracefully and use defaults self.assertEqual(config.include, []) @@ -335,7 +335,7 @@ def test_from_env_extra_fields_ignored(self): } os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.include, ["myapp"]) self.assertEqual(config.exclude, ["vendor"]) @@ -352,7 +352,7 @@ def test_from_env_wrong_type_values(self, mock_logger): } os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() # Should validate and use defaults for invalid types self.assertEqual(config.include, []) # Corrected to empty list @@ -391,7 +391,7 @@ def test_from_env_null_values(self, mock_logger): config_data = {"include": None, "exclude": None, "stack_depth": None} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() # get() should return None for null values, and validation should handle it self.assertEqual(config.include, []) # Constructor converts None to [] @@ -432,7 +432,7 @@ def test_from_env_complex_package_names(self): } os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual( config.include, ["my.app.module", "com.company.service", "app_with_underscores", "app-with-dashes"] @@ -444,13 +444,13 @@ def test_from_env_large_stack_depth(self): config_data = {"stack_depth": 999999} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() self.assertEqual(config.stack_depth, 999999) def test_env_constant_value(self): """Test that the environment variable constant has the expected value.""" - self.assertEqual(_ENV_CONFIG, "OTEL_AWS_CODE_CORRELATION_CONFIG") + self.assertEqual(_ENV_CONFIG, "OTEL_AWS_CODE_ATTRIBUTES_CONFIG") @patch("amazon.opentelemetry.distro.code_correlation.config._logger") def test_from_env_mixed_type_include_list(self, mock_logger): @@ -462,7 +462,7 @@ def test_from_env_mixed_type_include_list(self, mock_logger): } os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() # Should only keep string items self.assertEqual(config.include, ["valid_string", "another_valid_string"]) @@ -497,7 +497,7 @@ def test_from_env_mixed_type_exclude_list(self, mock_logger): } os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() # Should only keep string items self.assertEqual(config.include, []) @@ -532,7 +532,7 @@ def test_from_env_all_non_string_list_items(self, mock_logger): } os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() # Should result in empty lists since no valid strings self.assertEqual(config.include, []) @@ -582,7 +582,7 @@ def test_from_env_float_stack_depth(self, mock_logger): config_data = {"include": ["myapp"], "exclude": ["vendor"], "stack_depth": 5.7} os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() # Float should be treated as invalid and corrected to 0 self.assertEqual(config.include, ["myapp"]) @@ -607,7 +607,7 @@ def test_from_env_empty_string_in_lists(self, mock_logger): } os.environ[_ENV_CONFIG] = json.dumps(config_data) - config = AwsCodeCorrelationConfig.from_env() + config = AwsCodeAttributesConfig.from_env() # Empty strings are still strings, so they should be preserved self.assertEqual(config.include, ["valid", "", "also_valid", ""]) @@ -618,8 +618,8 @@ def test_from_env_empty_string_in_lists(self, mock_logger): mock_logger.warning.assert_not_called() -class TestAwsCodeCorrelationConfigIntegration(TestCase): - """Integration tests for AwsCodeCorrelationConfig.""" +class TestAwsCodeAttributesConfigIntegration(TestCase): + """Integration tests for AwsCodeAttributesConfig.""" def setUp(self): """Set up test fixtures.""" @@ -634,7 +634,7 @@ def tearDown(self): def test_roundtrip_to_dict_from_env(self): """Test roundtrip: config -> to_dict -> env -> from_env -> config.""" - original_config = AwsCodeCorrelationConfig( + original_config = AwsCodeAttributesConfig( include=["app1", "app2"], exclude=["vendor1", "vendor2"], stack_depth=20 ) @@ -643,7 +643,7 @@ def test_roundtrip_to_dict_from_env(self): os.environ[_ENV_CONFIG] = json.dumps(config_dict) # Create new config from environment - new_config = AwsCodeCorrelationConfig.from_env() + new_config = AwsCodeAttributesConfig.from_env() # Should be equivalent self.assertEqual(new_config.include, original_config.include) @@ -653,14 +653,14 @@ def test_roundtrip_to_dict_from_env(self): def test_roundtrip_to_json_from_env(self): """Test roundtrip: config -> to_json -> env -> from_env -> config.""" - original_config = AwsCodeCorrelationConfig(include=["myapp"], exclude=["third-party"], stack_depth=5) + original_config = AwsCodeAttributesConfig(include=["myapp"], exclude=["third-party"], stack_depth=5) # Convert to JSON for environment config_json = original_config.to_json(indent=None) # Compact JSON os.environ[_ENV_CONFIG] = config_json # Create new config from environment - new_config = AwsCodeCorrelationConfig.from_env() + new_config = AwsCodeAttributesConfig.from_env() # Should be equivalent self.assertEqual(new_config.include, original_config.include) @@ -670,9 +670,9 @@ def test_roundtrip_to_json_from_env(self): def test_config_equality_comparison(self): """Test that configs with same values produce same representations.""" - config1 = AwsCodeCorrelationConfig(include=["app"], exclude=["vendor"], stack_depth=10) + config1 = AwsCodeAttributesConfig(include=["app"], exclude=["vendor"], stack_depth=10) - config2 = AwsCodeCorrelationConfig(include=["app"], exclude=["vendor"], stack_depth=10) + config2 = AwsCodeAttributesConfig(include=["app"], exclude=["vendor"], stack_depth=10) # They should have the same string representation self.assertEqual(repr(config1), repr(config2)) diff --git a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_aio_pika_patches.py b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_aio_pika_patches.py index d9fe030cf..e0d907fd0 100644 --- a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_aio_pika_patches.py +++ b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_aio_pika_patches.py @@ -46,28 +46,13 @@ def test_patch_callback_decorator_decorate(self): # Verify we got a function back (the enhanced decorated callback) self.assertTrue(callable(result)) - @patch("amazon.opentelemetry.distro.patches._aio_pika_patches.get_code_correlation_enabled_status") - def test_apply_aio_pika_instrumentation_patches_disabled(self, mock_get_status): - """Test patches are not applied when code correlation is disabled.""" - mock_get_status.return_value = False - - with patch.dict( - "sys.modules", - { - "opentelemetry.instrumentation.aio_pika": None, - "opentelemetry.instrumentation.aio_pika.callback_decorator": None, - }, - ): - # Should not raise exception when code correlation is disabled - _apply_aio_pika_instrumentation_patches() - - @patch("amazon.opentelemetry.distro.patches._aio_pika_patches.get_code_correlation_enabled_status") - def test_apply_aio_pika_instrumentation_patches_enabled(self, mock_get_status): - """Test patches are applied when code correlation is enabled.""" - mock_get_status.return_value = True - + @patch("amazon.opentelemetry.distro.patches._aio_pika_patches.logger") + def test_apply_aio_pika_instrumentation_patches_success(self, mock_logger): + """Test patches are applied successfully.""" # Mock CallbackDecorator mock_callback_decorator = Mock() + original_decorate = Mock() + mock_callback_decorator.decorate = original_decorate with patch.dict( "sys.modules", @@ -80,14 +65,12 @@ def test_apply_aio_pika_instrumentation_patches_enabled(self, mock_get_status): ): _apply_aio_pika_instrumentation_patches() - # Verify the decorate method was patched - self.assertTrue(hasattr(mock_callback_decorator, "decorate")) + # Verify the decorate method was patched (should be different from original) + self.assertNotEqual(mock_callback_decorator.decorate, original_decorate) - @patch("amazon.opentelemetry.distro.patches._aio_pika_patches.get_code_correlation_enabled_status") - def test_apply_aio_pika_instrumentation_patches_import_error(self, mock_get_status): + @patch("amazon.opentelemetry.distro.patches._aio_pika_patches.logger") + def test_apply_aio_pika_instrumentation_patches_import_error(self, mock_logger): """Test patches handle import errors gracefully.""" - mock_get_status.return_value = True - with patch.dict( "sys.modules", { @@ -98,14 +81,26 @@ def test_apply_aio_pika_instrumentation_patches_import_error(self, mock_get_stat # Should not raise exception when import fails _apply_aio_pika_instrumentation_patches() + # Verify warning was logged + mock_logger.warning.assert_called_once() + args = mock_logger.warning.call_args[0] + self.assertIn("Failed to apply Aio-Pika patches", args[0]) + @patch("amazon.opentelemetry.distro.patches._aio_pika_patches.logger") - @patch("amazon.opentelemetry.distro.patches._aio_pika_patches.get_code_correlation_enabled_status") - def test_apply_aio_pika_instrumentation_patches_exception_handling(self, mock_get_status, mock_logger): + def test_apply_aio_pika_instrumentation_patches_exception_handling(self, mock_logger): """Test patches handle general exceptions gracefully.""" - mock_get_status.side_effect = Exception("Test exception") - # Should handle exceptions gracefully - _apply_aio_pika_instrumentation_patches() + # Mock import that raises an exception + def failing_import(*args, **kwargs): + if "callback_decorator" in str(args): + raise Exception("Test exception") + return Mock() + + with patch("builtins.__import__", side_effect=failing_import): + # Should handle exceptions gracefully + _apply_aio_pika_instrumentation_patches() - # Verify warning was logged - mock_logger.warning.assert_called_once() + # Verify warning was logged + mock_logger.warning.assert_called_once() + args = mock_logger.warning.call_args[0] + self.assertIn("Failed to apply Aio-Pika patches", args[0]) diff --git a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_celery_patches.py b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_celery_patches.py index 81abf0068..061d9c515 100644 --- a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_celery_patches.py +++ b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_celery_patches.py @@ -22,72 +22,46 @@ def tearDown(self): """Clean up after tests.""" super().tearDown() - @patch("amazon.opentelemetry.distro.patches._celery_patches.get_code_correlation_enabled_status") @patch("amazon.opentelemetry.distro.patches._celery_patches.CeleryInstrumentor") - def test_apply_celery_instrumentation_patches_enabled(self, mock_instrumentor, mock_get_status): - """Test Celery instrumentation patches when code correlation is enabled.""" - mock_get_status.return_value = True - + def test_apply_celery_instrumentation_patches_enabled(self, mock_instrumentor): + """Test Celery instrumentation patches when CeleryInstrumentor is available.""" # Mock CeleryInstrumentor mock_original_trace_prerun = Mock() mock_instrumentor._trace_prerun = mock_original_trace_prerun _apply_celery_instrumentation_patches() - mock_get_status.assert_called_once() # Verify that the _trace_prerun method was replaced self.assertNotEqual(mock_instrumentor._trace_prerun, mock_original_trace_prerun) - @patch("amazon.opentelemetry.distro.patches._celery_patches.get_code_correlation_enabled_status") - def test_apply_celery_instrumentation_patches_disabled(self, mock_get_status): - """Test Celery instrumentation patches when code correlation is disabled.""" - mock_get_status.return_value = False - - with patch("amazon.opentelemetry.distro.patches._celery_patches.logger") as mock_logger: - _apply_celery_instrumentation_patches() - - mock_get_status.assert_called_once() - # No warning should be logged since it returns early - mock_logger.warning.assert_not_called() - - @patch("amazon.opentelemetry.distro.patches._celery_patches.get_code_correlation_enabled_status") - def test_apply_celery_instrumentation_patches_none_status(self, mock_get_status): - """Test Celery instrumentation patches when status is None.""" - mock_get_status.return_value = None - - with patch("amazon.opentelemetry.distro.patches._celery_patches.logger") as mock_logger: - _apply_celery_instrumentation_patches() - - mock_get_status.assert_called_once() - # No warning should be logged since it returns early - mock_logger.warning.assert_not_called() - - @patch("amazon.opentelemetry.distro.patches._celery_patches.get_code_correlation_enabled_status") @patch("amazon.opentelemetry.distro.patches._celery_patches.logger") - def test_apply_celery_instrumentation_patches_import_error(self, mock_logger, mock_get_status): + def test_apply_celery_instrumentation_patches_import_error(self, mock_logger): """Test Celery instrumentation patches with import error.""" - mock_get_status.return_value = True - # Patch CeleryInstrumentor to None to simulate import failure with patch("amazon.opentelemetry.distro.patches._celery_patches.CeleryInstrumentor", None): _apply_celery_instrumentation_patches() - mock_get_status.assert_called_once() mock_logger.warning.assert_called_once() args = mock_logger.warning.call_args[0] self.assertIn("Failed to apply Celery patches: CeleryInstrumentor not available", args[0]) - @patch("amazon.opentelemetry.distro.patches._celery_patches.get_code_correlation_enabled_status") @patch("amazon.opentelemetry.distro.patches._celery_patches.logger") - def test_apply_celery_instrumentation_patches_exception(self, mock_logger, mock_get_status): + def test_apply_celery_instrumentation_patches_exception(self, mock_logger): """Test Celery instrumentation patches with general exception.""" - mock_get_status.side_effect = Exception("Unexpected error") + # Mock CeleryInstrumentor to raise an exception when accessing _trace_prerun + mock_instrumentor = Mock() - _apply_celery_instrumentation_patches() + def raise_exception(): + raise Exception("Unexpected error") - mock_logger.warning.assert_called_once() - args = mock_logger.warning.call_args[0] - self.assertIn("Failed to apply Celery instrumentation patches", args[0]) + type(mock_instrumentor).__getattr__ = Mock(side_effect=raise_exception) + + with patch("amazon.opentelemetry.distro.patches._celery_patches.CeleryInstrumentor", mock_instrumentor): + _apply_celery_instrumentation_patches() + + mock_logger.warning.assert_called_once() + args = mock_logger.warning.call_args[0] + self.assertIn("Failed to apply Celery instrumentation patches", args[0]) class TestExtractTaskFunction(TestBase): @@ -398,12 +372,9 @@ def setUp(self): """Set up test fixtures.""" super().setUp() - @patch("amazon.opentelemetry.distro.patches._celery_patches.get_code_correlation_enabled_status") @patch("amazon.opentelemetry.distro.patches._celery_patches.CeleryInstrumentor") - def test_full_patch_application_flow(self, mock_instrumentor, mock_get_status): + def test_full_patch_application_flow(self, mock_instrumentor): """Test the complete flow of applying Celery patches.""" - mock_get_status.return_value = True - # Create a realistic mock setup original_trace_prerun = Mock(__name__="original_trace_prerun") mock_instrumentor._trace_prerun = original_trace_prerun diff --git a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_django_patches.py b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_django_patches.py index 4cbbe1a6b..93ea24134 100644 --- a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_django_patches.py +++ b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_django_patches.py @@ -34,42 +34,14 @@ def tearDown(self): """Clean up after tests.""" super().tearDown() - @patch("amazon.opentelemetry.distro.patches._django_patches.get_code_correlation_enabled_status") - def test_apply_django_instrumentation_patches_enabled(self, mock_get_status): + def test_apply_django_instrumentation_patches_enabled(self): """Test Django instrumentation patches when code correlation is enabled.""" - mock_get_status.return_value = True - with patch( "amazon.opentelemetry.distro.patches._django_patches._apply_django_code_attributes_patch" ) as mock_patch: _apply_django_instrumentation_patches() - mock_get_status.assert_called_once() mock_patch.assert_called_once() - @patch("amazon.opentelemetry.distro.patches._django_patches.get_code_correlation_enabled_status") - def test_apply_django_instrumentation_patches_disabled(self, mock_get_status): - """Test Django instrumentation patches when code correlation is disabled.""" - mock_get_status.return_value = False - - with patch( - "amazon.opentelemetry.distro.patches._django_patches._apply_django_code_attributes_patch" - ) as mock_patch: - _apply_django_instrumentation_patches() - mock_get_status.assert_called_once() - mock_patch.assert_not_called() - - @patch("amazon.opentelemetry.distro.patches._django_patches.get_code_correlation_enabled_status") - def test_apply_django_instrumentation_patches_none_status(self, mock_get_status): - """Test Django instrumentation patches when status is None.""" - mock_get_status.return_value = None - - with patch( - "amazon.opentelemetry.distro.patches._django_patches._apply_django_code_attributes_patch" - ) as mock_patch: - _apply_django_instrumentation_patches() - mock_get_status.assert_called_once() - mock_patch.assert_not_called() - class TestDjangoCodeAttributesPatches(TestBase): """Test Django code attributes patches functionality.""" @@ -130,7 +102,6 @@ def test_apply_django_code_attributes_patch_exception_handling(self): # If we get here, no exception was raised -@patch("amazon.opentelemetry.distro.patches._django_patches.get_code_correlation_enabled_status", return_value=True) class TestDjangoRealIntegration(TestBase): """Test Django patches with real Django integration.""" @@ -171,7 +142,7 @@ def tearDown(self): pass super().tearDown() - def test_django_view_function_patch_process_view(self, mock_get_status): + def test_django_view_function_patch_process_view(self): """Test Django patch with real view function triggering process_view method.""" # Define a simple Django view function @@ -221,7 +192,7 @@ def test_view(request): # Clean up instrumentation instrumentor.uninstrument() - def test_django_class_based_view_patch_process_view(self, mock_get_status): + def test_django_class_based_view_patch_process_view(self): """Test Django patch with class-based view to test handler targeting logic.""" # Define a class-based Django view diff --git a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_fastapi_patches.py b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_fastapi_patches.py index bf5afcb98..a9503b8e6 100644 --- a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_fastapi_patches.py +++ b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_fastapi_patches.py @@ -1,7 +1,6 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 import sys -from unittest.mock import patch from fastapi import APIRouter, FastAPI @@ -58,15 +57,12 @@ def tearDown(self): except Exception: pass - @patch("amazon.opentelemetry.distro.patches._fastapi_patches.get_code_correlation_enabled_status") - def test_fastapi_patches_with_real_app(self, mock_get_status): + def test_fastapi_patches_with_real_app(self): """Test FastAPI patches core functionality.""" - mock_get_status.return_value = True original_add_api_route = _ORIGINAL_APIROUTER_ADD_API_ROUTE # Apply patches _apply_fastapi_instrumentation_patches() - mock_get_status.assert_called_once() # Test method wrapping instrumentor = FastAPIInstrumentor() @@ -84,25 +80,8 @@ def test_fastapi_patches_with_real_app(self, mock_get_status): restored_add_api_route = APIRouter.add_api_route self.assertEqual(restored_add_api_route, original_add_api_route) - @patch("amazon.opentelemetry.distro.patches._fastapi_patches.get_code_correlation_enabled_status") - def test_fastapi_patches_disabled(self, mock_get_status): - """Test FastAPI patches when disabled.""" - mock_get_status.return_value = False - - _apply_fastapi_instrumentation_patches() - instrumentor = FastAPIInstrumentor() - instrumentor.instrument_app(self.app) - - mock_get_status.assert_called_once() - self.assertIsNotNone(self.app) - - spans = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans), 0) - - @patch("amazon.opentelemetry.distro.patches._fastapi_patches.get_code_correlation_enabled_status") - def test_fastapi_patches_import_error_handling(self, mock_get_status): + def test_fastapi_patches_import_error_handling(self): """Test FastAPI patches with import errors.""" - mock_get_status.return_value = True original_modules = sys.modules.copy() try: @@ -117,17 +96,13 @@ def test_fastapi_patches_import_error_handling(self, mock_get_status): del sys.modules[module] _apply_fastapi_instrumentation_patches() - mock_get_status.assert_called_once() finally: sys.modules.clear() sys.modules.update(original_modules) - @patch("amazon.opentelemetry.distro.patches._fastapi_patches.get_code_correlation_enabled_status") - def test_fastapi_patches_endpoint_decoration(self, mock_get_status): + def test_fastapi_patches_endpoint_decoration(self): """Test endpoint decoration functionality.""" - mock_get_status.return_value = True - instrumentor = FastAPIInstrumentor() instrumentor.instrument_app(self.app) _apply_fastapi_instrumentation_patches() @@ -143,11 +118,8 @@ async def async_endpoint(): self.assertTrue(len(self.app.routes) > 0) - @patch("amazon.opentelemetry.distro.patches._fastapi_patches.get_code_correlation_enabled_status") - def test_fastapi_patches_uninstrument_error_handling(self, mock_get_status): + def test_fastapi_patches_uninstrument_error_handling(self): """Test uninstrument error handling.""" - mock_get_status.return_value = True - instrumentor = FastAPIInstrumentor() _apply_fastapi_instrumentation_patches() instrumentor._instrument() @@ -161,10 +133,8 @@ def test_fastapi_patches_uninstrument_error_handling(self, mock_get_status): except Exception: pass # Expected to handle gracefully - @patch("amazon.opentelemetry.distro.patches._fastapi_patches.get_code_correlation_enabled_status") - def test_fastapi_patches_code_correlation_import_error(self, mock_get_status): + def test_fastapi_patches_code_correlation_import_error(self): """Test code correlation import error handling.""" - mock_get_status.return_value = True original_modules = sys.modules.copy() try: @@ -185,11 +155,8 @@ def test_fastapi_patches_code_correlation_import_error(self, mock_get_status): sys.modules.clear() sys.modules.update(original_modules) - @patch("amazon.opentelemetry.distro.patches._fastapi_patches.get_code_correlation_enabled_status") - def test_fastapi_patches_double_decoration_prevention(self, mock_get_status): + def test_fastapi_patches_double_decoration_prevention(self): """Test prevention of double decoration.""" - mock_get_status.return_value = True - _apply_fastapi_instrumentation_patches() instrumentor = FastAPIInstrumentor() instrumentor._instrument() @@ -206,11 +173,8 @@ async def test_endpoint(): self.assertTrue(len(self.app.routes) > 0) - @patch("amazon.opentelemetry.distro.patches._fastapi_patches.get_code_correlation_enabled_status") - def test_fastapi_patches_none_endpoint_handling(self, mock_get_status): + def test_fastapi_patches_none_endpoint_handling(self): """Test handling of None endpoints.""" - mock_get_status.return_value = True - _apply_fastapi_instrumentation_patches() instrumentor = FastAPIInstrumentor() instrumentor._instrument() diff --git a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_flask_patches.py b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_flask_patches.py index effc1475b..2bb64f9a8 100644 --- a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_flask_patches.py +++ b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_flask_patches.py @@ -1,13 +1,10 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -from unittest.mock import patch - import flask from werkzeug.test import Client from werkzeug.wrappers import Response from amazon.opentelemetry.distro.patches._flask_patches import _apply_flask_instrumentation_patches -from opentelemetry import trace from opentelemetry.instrumentation.flask import FlaskInstrumentor from opentelemetry.test.test_base import TestBase @@ -89,11 +86,8 @@ def tearDown(self): except Exception: # pylint: disable=broad-exception-caught pass - @patch("amazon.opentelemetry.distro.patches._flask_patches.get_code_correlation_enabled_status") - def test_flask_patches_with_real_app(self, mock_get_status): + def test_flask_patches_with_real_app(self): """Test Flask patches with real Flask app covering various scenarios.""" - mock_get_status.return_value = True - # Store original Flask methods - use the module level constants original_add_url_rule = _ORIGINAL_FLASK_ADD_URL_RULE original_dispatch_request = _ORIGINAL_FLASK_DISPATCH_REQUEST @@ -101,9 +95,6 @@ def test_flask_patches_with_real_app(self, mock_get_status): # Apply patches FIRST _apply_flask_instrumentation_patches() - # Verify that get_status was called - mock_get_status.assert_called_once() - # Create instrumentor and manually call _instrument to trigger Flask method wrapping instrumentor = FlaskInstrumentor() instrumentor._instrument() @@ -136,45 +127,8 @@ def test_flask_patches_with_real_app(self, mock_get_status): restored_dispatch_request, original_dispatch_request, "Flask.dispatch_request should be restored" ) - @patch("amazon.opentelemetry.distro.patches._flask_patches.get_code_correlation_enabled_status") - def test_flask_patches_disabled(self, mock_get_status): - """Test Flask patches when code correlation is disabled.""" - mock_get_status.return_value = False - - # Apply patches (should not modify anything) - _apply_flask_instrumentation_patches() - - # Instrument the app normally - instrumentor = FlaskInstrumentor() - instrumentor.instrument_app(self.app) - - # Verify that get_status was called - mock_get_status.assert_called_once() - - # Make a request - resp = self.client.get("/hello") - self.assertEqual(200, resp.status_code) - self.assertEqual([b"Hello!"], list(resp.response)) - - # Check spans were still generated (normal instrumentation) - spans = self.memory_exporter.get_finished_spans() - self.assertEqual(len(spans), 1) - - span = spans[0] - self.assertEqual(span.name, "GET /hello") - self.assertEqual(span.kind, trace.SpanKind.SERVER) - - # Clean up - avoid Flask instrumentation issues - try: - instrumentor.uninstrument_app(self.app) - except Exception: - pass # Flask instrumentation cleanup may fail, that's ok - - @patch("amazon.opentelemetry.distro.patches._flask_patches.get_code_correlation_enabled_status") - def test_flask_patches_import_error_handling(self, mock_get_status): + def test_flask_patches_import_error_handling(self): """Test Flask patches with import errors.""" - mock_get_status.return_value = True - # Test that patches handle import errors gracefully by mocking sys.modules import sys @@ -188,19 +142,13 @@ def test_flask_patches_import_error_handling(self, mock_get_status): # Should not raise exception even with missing flask _apply_flask_instrumentation_patches() - # Verify status was checked - mock_get_status.assert_called_once() - finally: # Restore original modules sys.modules.clear() sys.modules.update(original_modules) - @patch("amazon.opentelemetry.distro.patches._flask_patches.get_code_correlation_enabled_status") - def test_flask_patches_view_function_decoration(self, mock_get_status): + def test_flask_patches_view_function_decoration(self): """Test Flask patches view function decoration edge cases.""" - mock_get_status.return_value = True - # Create instrumentor and apply patches instrumentor = FlaskInstrumentor() instrumentor.instrument_app(self.app) @@ -227,11 +175,8 @@ def lambda_func(): # Clean up - don't call uninstrument_app to avoid Flask instrumentation issues - @patch("amazon.opentelemetry.distro.patches._flask_patches.get_code_correlation_enabled_status") - def test_flask_patches_dispatch_request_coverage(self, mock_get_status): + def test_flask_patches_dispatch_request_coverage(self): """Test Flask patches dispatch_request method coverage.""" - mock_get_status.return_value = True - # Create a special app with deferred view function binding test_app = flask.Flask(__name__) @@ -251,11 +196,8 @@ def deferred_view(): resp = client.get("/deferred") self.assertEqual(200, resp.status_code) - @patch("amazon.opentelemetry.distro.patches._flask_patches.get_code_correlation_enabled_status") - def test_flask_patches_uninstrument_error_handling(self, mock_get_status): + def test_flask_patches_uninstrument_error_handling(self): """Test Flask patches uninstrument error handling.""" - mock_get_status.return_value = True - # Create instrumentor and apply patches instrumentor = FlaskInstrumentor() _apply_flask_instrumentation_patches() @@ -273,11 +215,8 @@ def test_flask_patches_uninstrument_error_handling(self, mock_get_status): except Exception: pass # Expected to handle gracefully - @patch("amazon.opentelemetry.distro.patches._flask_patches.get_code_correlation_enabled_status") - def test_flask_patches_code_correlation_import_error(self, mock_get_status): + def test_flask_patches_code_correlation_import_error(self): """Test Flask patches when code_correlation import fails.""" - mock_get_status.return_value = True - # Mock import error for code_correlation module import sys diff --git a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_pika_patches.py b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_pika_patches.py index dab5e42d7..1a106c11d 100644 --- a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_pika_patches.py +++ b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_pika_patches.py @@ -12,11 +12,8 @@ class TestPikaPatches(TestBase): """Test Pika patches functionality.""" - @patch("amazon.opentelemetry.distro.patches._pika_patches.get_code_correlation_enabled_status") - def test_apply_pika_instrumentation_patches_enabled(self, mock_get_status): - """Test Pika instrumentation patches when code correlation is enabled.""" - mock_get_status.return_value = True - + def test_apply_pika_instrumentation_patches_success(self): + """Test Pika instrumentation patches when import is successful.""" # Mock pika utils mock_utils = Mock() mock_original_decorate_callback = Mock() @@ -31,40 +28,12 @@ def test_apply_pika_instrumentation_patches_enabled(self, mock_get_status): ): _apply_pika_instrumentation_patches() - mock_get_status.assert_called_once() # Verify that the _decorate_callback method was replaced self.assertNotEqual(mock_utils._decorate_callback, mock_original_decorate_callback) - @patch("amazon.opentelemetry.distro.patches._pika_patches.get_code_correlation_enabled_status") - def test_apply_pika_instrumentation_patches_disabled(self, mock_get_status): - """Test Pika instrumentation patches when code correlation is disabled.""" - mock_get_status.return_value = False - - with patch("amazon.opentelemetry.distro.patches._pika_patches.logger") as mock_logger: - _apply_pika_instrumentation_patches() - - mock_get_status.assert_called_once() - # No warning should be logged since it returns early - mock_logger.warning.assert_not_called() - - @patch("amazon.opentelemetry.distro.patches._pika_patches.get_code_correlation_enabled_status") - def test_apply_pika_instrumentation_patches_none_status(self, mock_get_status): - """Test Pika instrumentation patches when status is None.""" - mock_get_status.return_value = None - - with patch("amazon.opentelemetry.distro.patches._pika_patches.logger") as mock_logger: - _apply_pika_instrumentation_patches() - - mock_get_status.assert_called_once() - # No warning should be logged since it returns early - mock_logger.warning.assert_not_called() - - @patch("amazon.opentelemetry.distro.patches._pika_patches.get_code_correlation_enabled_status") @patch("amazon.opentelemetry.distro.patches._pika_patches.logger") - def test_apply_pika_instrumentation_patches_import_error(self, mock_logger, mock_get_status): + def test_apply_pika_instrumentation_patches_import_error(self, mock_logger): """Test Pika instrumentation patches with import error.""" - mock_get_status.return_value = True - # Patch the specific import that would fail with patch.dict( "sys.modules", @@ -72,22 +41,26 @@ def test_apply_pika_instrumentation_patches_import_error(self, mock_logger, mock ): _apply_pika_instrumentation_patches() - mock_get_status.assert_called_once() mock_logger.warning.assert_called_once() args = mock_logger.warning.call_args[0] - self.assertIn("Failed to apply Pika patches", args[0]) + self.assertIn("Failed to apply Pika patches: pika utils not available", args[0]) - @patch("amazon.opentelemetry.distro.patches._pika_patches.get_code_correlation_enabled_status") @patch("amazon.opentelemetry.distro.patches._pika_patches.logger") - def test_apply_pika_instrumentation_patches_exception(self, mock_logger, mock_get_status): + def test_apply_pika_instrumentation_patches_exception(self, mock_logger): """Test Pika instrumentation patches with general exception.""" - mock_get_status.side_effect = Exception("Unexpected error") - _apply_pika_instrumentation_patches() + # Mock import that raises an exception + def failing_import(*args, **kwargs): + if "pika" in str(args): + raise Exception("Unexpected error") + return Mock() - mock_logger.warning.assert_called_once() - args = mock_logger.warning.call_args[0] - self.assertIn("Failed to apply Pika patches", args[0]) + with patch("builtins.__import__", side_effect=failing_import): + _apply_pika_instrumentation_patches() + + mock_logger.warning.assert_called_once() + args = mock_logger.warning.call_args[0] + self.assertIn("Failed to apply Pika patches", args[0]) class TestPatchDecorateCallback(TestBase): @@ -291,11 +264,8 @@ def test_enhanced_consume_hook_original_hook_exception(self): class TestPikaPatchesIntegration(TestBase): """Test Pika patches integration scenarios.""" - @patch("amazon.opentelemetry.distro.patches._pika_patches.get_code_correlation_enabled_status") - def test_full_patch_application_flow(self, mock_get_status): + def test_full_patch_application_flow(self): """Test the complete flow of applying Pika patches.""" - mock_get_status.return_value = True - # Create a realistic mock setup mock_utils = Mock() original_decorate_callback = Mock(__name__="original_decorate_callback") @@ -326,12 +296,9 @@ def test_full_patch_application_flow(self, mock_get_status): # Original function should be called original_decorate_callback.assert_called_once() - @patch("amazon.opentelemetry.distro.patches._pika_patches.get_code_correlation_enabled_status") @patch("amazon.opentelemetry.distro.patches._pika_patches.add_code_attributes_to_span") - def test_end_to_end_enhanced_consume_hook(self, mock_add_attributes, mock_get_status): + def test_end_to_end_enhanced_consume_hook(self, mock_add_attributes): """Test end-to-end flow with enhanced consume hook.""" - mock_get_status.return_value = True - # Create a realistic mock setup mock_utils = Mock() original_decorate_callback = Mock(return_value="decorated_result") diff --git a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_starlette_patches.py b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_starlette_patches.py index 16f0a72cd..fe21f53cb 100644 --- a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_starlette_patches.py +++ b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/patches/test_starlette_patches.py @@ -17,6 +17,9 @@ def test_starlette_patch_applied_successfully(self, mock_logger): """Test that the Starlette instrumentation patch is applied successfully.""" for agent_enabled in [True, False]: with self.subTest(agent_enabled=agent_enabled): + # Reset mock for each sub-test + mock_logger.reset_mock() + with patch.dict("os.environ", {"AGENT_OBSERVABILITY_ENABLED": "true" if agent_enabled else "false"}): # Create a mock StarletteInstrumentor class mock_instrumentor_class = MagicMock() @@ -68,9 +71,14 @@ def __init__(self, app, **kwargs): self.assertFalse(mock_middleware_instance.exclude_receive_span) self.assertFalse(mock_middleware_instance.exclude_send_span) - # Verify logging - mock_logger.debug.assert_called_with( - "Successfully patched Starlette instrumentation_dependencies method" + # Verify logging - expect two debug calls from both patch functions + self.assertEqual(mock_logger.debug.call_count, 2) + + # Check that both expected debug messages were logged + debug_calls = [call[0][0] for call in mock_logger.debug.call_args_list] + self.assertIn("Successfully patched Starlette instrumentation_dependencies method", debug_calls) + self.assertIn( + "Starlette instrumentation code attributes patch applied successfully", debug_calls ) @patch("amazon.opentelemetry.distro.patches._starlette_patches._logger") @@ -81,10 +89,13 @@ def test_starlette_patch_handles_import_error(self, mock_logger): # This should not raise an exception _apply_starlette_instrumentation_patches() - # Verify warning was logged - mock_logger.warning.assert_called_once() - args = mock_logger.warning.call_args[0] - self.assertIn("Failed to apply Starlette instrumentation patches", args[0]) + # Verify warning was logged - expect two warnings from both sub-functions + self.assertEqual(mock_logger.warning.call_count, 2) + + # Check that both expected warning messages were logged + warning_calls = [call[0][0] for call in mock_logger.warning.call_args_list] + self.assertIn("Failed to apply Starlette instrumentation patches", warning_calls[0]) + self.assertIn("Failed to apply Starlette code attributes patch", warning_calls[1]) class TestStarletteCodeAttributesPatch(TestCase): diff --git a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/test_aws_opentelementry_configurator.py b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/test_aws_opentelementry_configurator.py index 740733ad4..b360107e3 100644 --- a/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/test_aws_opentelementry_configurator.py +++ b/aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/test_aws_opentelementry_configurator.py @@ -17,8 +17,8 @@ from amazon.opentelemetry.distro.aws_lambda_span_processor import AwsLambdaSpanProcessor from amazon.opentelemetry.distro.aws_metric_attributes_span_exporter import AwsMetricAttributesSpanExporter from amazon.opentelemetry.distro.aws_opentelemetry_configurator import ( - CODE_CORRELATION_ENABLED_CONFIG, LAMBDA_SPAN_EXPORT_BATCH_SIZE, + OTEL_AWS_ENHANCED_CODE_ATTRIBUTES, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_HEADERS, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, @@ -45,7 +45,7 @@ _is_application_signals_runtime_enabled, _is_defer_to_workers_enabled, _is_wsgi_master_process, - get_code_correlation_enabled_status, + is_enhanced_code_attributes, ) from amazon.opentelemetry.distro.aws_opentelemetry_distro import AwsOpenTelemetryDistro from amazon.opentelemetry.distro.aws_span_metrics_processor import AwsSpanMetricsProcessor @@ -784,7 +784,7 @@ def test_customize_span_processors_with_code_correlation_enabled(self): # Clean up environment to ensure consistent test state os.environ.pop("AGENT_OBSERVABILITY_ENABLED", None) os.environ.pop("OTEL_AWS_APPLICATION_SIGNALS_ENABLED", None) - os.environ.pop(CODE_CORRELATION_ENABLED_CONFIG, None) + os.environ.pop(OTEL_AWS_ENHANCED_CODE_ATTRIBUTES, None) # Test without code correlation enabled - should not add CodeAttributesSpanProcessor _customize_span_processors(mock_tracer_provider, Resource.get_empty()) @@ -793,7 +793,7 @@ def test_customize_span_processors_with_code_correlation_enabled(self): mock_tracer_provider.reset_mock() # Test with code correlation enabled - should add CodeAttributesSpanProcessor - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = "true" + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = "true" with patch( "amazon.opentelemetry.distro.code_correlation.CodeAttributesSpanProcessor" @@ -810,7 +810,7 @@ def test_customize_span_processors_with_code_correlation_enabled(self): mock_tracer_provider.reset_mock() # Test with code correlation enabled along with application signals - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = "true" + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = "true" os.environ["OTEL_AWS_APPLICATION_SIGNALS_ENABLED"] = "True" os.environ["OTEL_AWS_APPLICATION_SIGNALS_RUNTIME_ENABLED"] = "False" @@ -839,7 +839,7 @@ def test_customize_span_processors_with_code_correlation_enabled(self): self.assertIsInstance(third_call_args, AwsSpanMetricsProcessor) # Clean up - os.environ.pop(CODE_CORRELATION_ENABLED_CONFIG, None) + os.environ.pop(OTEL_AWS_ENHANCED_CODE_ATTRIBUTES, None) os.environ.pop("OTEL_AWS_APPLICATION_SIGNALS_ENABLED", None) os.environ.pop("OTEL_AWS_APPLICATION_SIGNALS_RUNTIME_ENABLED", None) @@ -1500,65 +1500,65 @@ def test_create_emf_exporter_cloudwatch_exporter_import_error( self.assertIsNone(result) mock_logger.error.assert_called_once() - def test_get_code_correlation_enabled_status(self): - """Test get_code_correlation_enabled_status function with various environment variable values""" + def test_is_enhanced_code_attributes(self): + """Test is_enhanced_code_attributes function with various environment variable values""" # Test when environment variable is not set (default state) - os.environ.pop(CODE_CORRELATION_ENABLED_CONFIG, None) - result = get_code_correlation_enabled_status() - self.assertIsNone(result) + os.environ.pop(OTEL_AWS_ENHANCED_CODE_ATTRIBUTES, None) + result = is_enhanced_code_attributes() + self.assertFalse(result) # Test when environment variable is set to 'true' (case insensitive) - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = "true" - result = get_code_correlation_enabled_status() + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = "true" + result = is_enhanced_code_attributes() self.assertTrue(result) - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = "TRUE" - result = get_code_correlation_enabled_status() + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = "TRUE" + result = is_enhanced_code_attributes() self.assertTrue(result) - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = "True" - result = get_code_correlation_enabled_status() + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = "True" + result = is_enhanced_code_attributes() self.assertTrue(result) # Test when environment variable is set to 'false' (case insensitive) - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = "false" - result = get_code_correlation_enabled_status() + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = "false" + result = is_enhanced_code_attributes() self.assertFalse(result) - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = "FALSE" - result = get_code_correlation_enabled_status() + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = "FALSE" + result = is_enhanced_code_attributes() self.assertFalse(result) - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = "False" - result = get_code_correlation_enabled_status() + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = "False" + result = is_enhanced_code_attributes() self.assertFalse(result) # Test with leading/trailing whitespace - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = " true " - result = get_code_correlation_enabled_status() + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = " true " + result = is_enhanced_code_attributes() self.assertTrue(result) - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = " false " - result = get_code_correlation_enabled_status() + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = " false " + result = is_enhanced_code_attributes() self.assertFalse(result) - # Test invalid values (should return None and log warning) - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = "invalid" - result = get_code_correlation_enabled_status() - self.assertIsNone(result) + # Test invalid values (should return False) + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = "invalid" + result = is_enhanced_code_attributes() + self.assertFalse(result) # Test another invalid value - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = "yes" - result = get_code_correlation_enabled_status() - self.assertIsNone(result) + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = "yes" + result = is_enhanced_code_attributes() + self.assertFalse(result) # Test empty string (invalid) - os.environ[CODE_CORRELATION_ENABLED_CONFIG] = "" - result = get_code_correlation_enabled_status() - self.assertIsNone(result) + os.environ[OTEL_AWS_ENHANCED_CODE_ATTRIBUTES] = "" + result = is_enhanced_code_attributes() + self.assertFalse(result) # Clean up - os.environ.pop(CODE_CORRELATION_ENABLED_CONFIG, None) + os.environ.pop(OTEL_AWS_ENHANCED_CODE_ATTRIBUTES, None) def validate_distro_environ(): diff --git a/contract-tests/images/mock-collector/pyproject.toml b/contract-tests/images/mock-collector/pyproject.toml index cd7cb8416..3c6bd582b 100644 --- a/contract-tests/images/mock-collector/pyproject.toml +++ b/contract-tests/images/mock-collector/pyproject.toml @@ -11,8 +11,8 @@ requires-python = ">=3.9" dependencies = [ "grpcio ~= 1.76.0", - "opentelemetry-proto==1.37.0", - "opentelemetry-sdk==1.37.0", + "opentelemetry-proto == 1.39.1", + "opentelemetry-sdk == 1.39.1", "protobuf==6.33.0", "typing-extensions==4.15.0" ] diff --git a/contract-tests/images/mock-collector/requirements.txt b/contract-tests/images/mock-collector/requirements.txt index db89ab3fb..7bcaf2c4d 100644 --- a/contract-tests/images/mock-collector/requirements.txt +++ b/contract-tests/images/mock-collector/requirements.txt @@ -1,5 +1,5 @@ grpcio==1.76.0 -opentelemetry-proto==1.37.0 -opentelemetry-sdk==1.37.0 +opentelemetry-proto==1.39.1 +opentelemetry-sdk==1.39.1 protobuf==6.33.0 typing-extensions==4.15.0 diff --git a/contract-tests/tests/pyproject.toml b/contract-tests/tests/pyproject.toml index ff45cf496..35d82785b 100644 --- a/contract-tests/tests/pyproject.toml +++ b/contract-tests/tests/pyproject.toml @@ -10,8 +10,8 @@ license = "Apache-2.0" requires-python = ">=3.9" dependencies = [ - "opentelemetry-proto==1.37.0", - "opentelemetry-sdk==1.37.0", + "opentelemetry-proto == 1.39.1", + "opentelemetry-sdk == 1.39.1", "testcontainers==3.7.1", "grpcio==1.76.0", "docker==7.1.0", diff --git a/contract-tests/tests/test/amazon/misc/code_attributes_test.py b/contract-tests/tests/test/amazon/misc/code_attributes_test.py index 908289589..d0305bda2 100644 --- a/contract-tests/tests/test/amazon/misc/code_attributes_test.py +++ b/contract-tests/tests/test/amazon/misc/code_attributes_test.py @@ -34,7 +34,7 @@ def get_application_extra_environment_variables(self) -> Dict[str, str]: """ return { "OTEL_INSTRUMENTATION_COMMON_PEER_SERVICE_MAPPING": "backend=backend:8080", - "OTEL_AWS_CODE_CORRELATION_ENABLED": "true", + "OTEL_AWS_ENHANCED_CODE_ATTRIBUTES": "true", } def test_success(self) -> None: diff --git a/lambda-layer/src/opentelemetry/instrumentation/aws_lambda/__init__.py b/lambda-layer/src/opentelemetry/instrumentation/aws_lambda/__init__.py index b88e65438..cee9597df 100644 --- a/lambda-layer/src/opentelemetry/instrumentation/aws_lambda/__init__.py +++ b/lambda-layer/src/opentelemetry/instrumentation/aws_lambda/__init__.py @@ -93,15 +93,12 @@ def custom_event_context_extractor(lambda_event): # Import code correlation functionality try: - from amazon.opentelemetry.distro.aws_opentelemetry_configurator import get_code_correlation_enabled_status from amazon.opentelemetry.distro.code_correlation import add_code_attributes_to_span except ImportError: # If code correlation module is not available, define no-op functions def add_code_attributes_to_span(span, func): pass - def get_code_correlation_enabled_status(): - return None logger = logging.getLogger(__name__) @@ -315,16 +312,15 @@ def _instrumented_lambda_handler_call( # noqa pylint: disable=too-many-branches account_id, ) - # Add code-level information attributes to the span if enabled - if get_code_correlation_enabled_status() is True: - try: - add_code_attributes_to_span(span, call_wrapped) - except Exception as exc: - # Log but don't fail the instrumentation - logger.debug( - "Failed to add code attributes to lambda span: %s", - str(exc) - ) + # Add code-level information attributes to the span + try: + add_code_attributes_to_span(span, call_wrapped) + except Exception as exc: + # Log but don't fail the instrumentation + logger.debug( + "Failed to add code attributes to lambda span: %s", + str(exc) + ) exception = None result = None diff --git a/lambda-layer/src/tests/requirements.txt b/lambda-layer/src/tests/requirements.txt index 3bca3e0e4..75d7ace16 100644 --- a/lambda-layer/src/tests/requirements.txt +++ b/lambda-layer/src/tests/requirements.txt @@ -1,3 +1,3 @@ # Dependencies used in tests only -opentelemetry-test-utils==0.46b0 -opentelemetry-instrumentation-aws-lambda==0.46b0 +opentelemetry-test-utils==0.60b1 +opentelemetry-instrumentation-aws-lambda==0.60b1