diff --git a/CHANGELOG.md b/CHANGELOG.md index f4a7b64505..9ca0a01d59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `opentelemetry-instrumentation-botocore`: Handle dict input in _decode_tool_use for Bedrock streaming ([#3875](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3875)) +- `opentelemetry-instrumentation-aws-lambda`: Fix ImportError with slash-delimited handler paths + ([#3894](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3894)) ## Version 1.38.0/0.59b0 (2025-10-16) diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py b/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py index ed40d4c1c9..9b450cdf21 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/src/opentelemetry/instrumentation/aws_lambda/__init__.py @@ -460,6 +460,8 @@ def _instrument(self, **kwargs): ) return # pylint: disable=attribute-defined-outside-init + # Convert slash-delimited paths to dot-delimited for valid Python imports + lambda_handler = lambda_handler.replace("/", ".") ( self._wrapped_module_name, self._wrapped_function_name, diff --git a/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py b/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py index 8fbff76675..a468cb986a 100644 --- a/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py +++ b/instrumentation/opentelemetry-instrumentation-aws-lambda/tests/test_aws_lambda_instrumentation_manual.py @@ -727,6 +727,53 @@ def test_sqs_event_sets_attributes(self): MOCK_LAMBDA_CONTEXT_ATTRIBUTES, ) + def test_slash_delimited_handler_path(self): + """Test that slash-delimited handler paths work correctly. + + AWS Lambda accepts both slash-delimited (python/functions/api.handler) + and dot-delimited (python.functions.api.handler) handler paths. + This test ensures the instrumentation handles both formats. + """ + # Test slash-delimited format + slash_env_patch = mock.patch.dict( + "os.environ", + {_HANDLER: "tests/mocks/lambda_function.handler"}, + ) + slash_env_patch.start() + AwsLambdaInstrumentor().instrument() + + mock_execute_lambda() + + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + self.assertSpanHasAttributes( + spans[0], + MOCK_LAMBDA_CONTEXT_ATTRIBUTES, + ) + + slash_env_patch.stop() + AwsLambdaInstrumentor().uninstrument() + self.memory_exporter.clear() + + # Test dot-delimited format (should still work) + dot_env_patch = mock.patch.dict( + "os.environ", + {_HANDLER: "tests.mocks.lambda_function.handler"}, + ) + dot_env_patch.start() + AwsLambdaInstrumentor().instrument() + + mock_execute_lambda() + + spans = self.memory_exporter.get_finished_spans() + self.assertEqual(len(spans), 1) + self.assertSpanHasAttributes( + spans[0], + MOCK_LAMBDA_CONTEXT_ATTRIBUTES, + ) + + dot_env_patch.stop() + def test_lambda_handles_handler_exception_with_api_gateway_proxy_event( self, ):