Repository: elastic/apm-agent-python

Issue:
ELASTIC_APM_SERVICE_NAME env var for Python Lambda not working
We have a test Python lambda function using the elastic-apm-extension-ver-0-0-4-arm64 layer and have set 'ELASTIC_APM_SERVICE_NAME' environment variable to 'python-apm-enabled'. 

However, within Elastic under APM we are seeing the original function name (as it is within AWS - we want change the service name in Elastic to remove the environment prefix by setting ELASTIC_APM_SERVICE_NAME), so we would expect the name of the service and service.name within the metadata of the transaction in APM to reflect the value set by the environment variable.

It is showing under APM as 'test1-python-apm-enabled' for the Service Name and for service.name in the transaction metadata.
So it still includes the environment prefix. As we have added 'ELASTIC_APM_SERVICE_NAME' to the environment variables to change the service name, I would expect the name and service.name metadata to be updated to the new value.

Could you please advise how we would go about changing the service name to achieve our desired outcome?

Thanks


Discussion:
This is an oversight on my part, I'm not allowing for environment overrides on that config value.

I'll get this fixed, but as a workaround, if you do `@capture_serverless(service_name="foo")` it should work in the meantime.
Thank you for such a quick response. I'll try this tomorrow morning 👍🏻
@basepi your suggestion appears to not work, unfortunately. I've added 'service_name' to the wrapper as you have suggested above but it is still showing in APM as the original name. Do you have any further suggestions?
Hmmm, that's a bit mysterious. This is the offending bit of code: https://github.com/elastic/apm-agent-python/blob/ca6f21e3d193edf727398fbb7ee18a15e9d8f0fd/elasticapm/contrib/serverless/aws.py#L80-L81

Adding `service_name` to the decorator call should skip that nicely.

The only thing I can think of is perhaps the `Client` object is being created before the decorator is initialized... It's designed to be a singleton so I re-use the existing Client if it exists. Do you have any references to `elasticapm` besides the decorator? Are there multiple functions decorated with that decorator?
@basepi Apologies for the late reply. Here is our code - I have made the changes you have suggested, but in Elastic I still see the service name as the original function name rather than the test value to override it.
[python-apm.zip](https://github.com/elastic/apm-agent-python/files/8314655/python-apm.zip)
 
Just realized that I've been inadvertently reproducing this, but I just didn't notice it in my testing. Appears to still be a problem, I'm going to track it down.

Resolving patch:
diff --git a/elasticapm/contrib/serverless/aws.py b/elasticapm/contrib/serverless/aws.py
--- a/elasticapm/contrib/serverless/aws.py
+++ b/elasticapm/contrib/serverless/aws.py
@@ -317,7 +317,7 @@ def set_metadata_and_context(self, coldstart: bool) -> None:
             cloud_context["origin"]["provider"] = "aws"
 
         metadata["service"] = {}
-        metadata["service"]["name"] = os.environ.get("AWS_LAMBDA_FUNCTION_NAME")
+        metadata["service"]["name"] = self.client.config.service_name
         metadata["service"]["framework"] = {"name": "AWS Lambda"}
         metadata["service"]["runtime"] = {
             "name": os.environ.get("AWS_EXECUTION_ENV"),


Test patch:
diff --git a/tests/contrib/serverless/aws_tests.py b/tests/contrib/serverless/aws_tests.py
--- a/tests/contrib/serverless/aws_tests.py
+++ b/tests/contrib/serverless/aws_tests.py
@@ -259,3 +259,19 @@ def test_func(event, context):
 
     assert transaction["name"] == "test_func"
     assert transaction["span_count"]["started"] == 1
+
+
+@pytest.mark.parametrize("elasticapm_client", [{"service_name": "override"}], indirect=True)
+def test_service_name_override(event_api, context, elasticapm_client):
+
+    os.environ["AWS_LAMBDA_FUNCTION_NAME"] = "test_func"
+
+    @capture_serverless(elasticapm_client=elasticapm_client)
+    def test_func(event, context):
+        with capture_span("test_span"):
+            time.sleep(0.01)
+        return {"statusCode": 200, "headers": {"foo": "bar"}}
+
+    test_func(event_api, context)
+
+    assert elasticapm_client._transport._metadata["service"]["name"] == "override"