Repository: elastic/apm-agent-python

Issue:
unexpected keyword argument 'flushed' in lambda extension
**Describe the bug**: 
Call self.send(data,flushed=true) in https://github.com/elastic/apm-agent-python/blob/main/elasticapm/transport/base.py#L183 uses not declared argument.

**To Reproduce**

1. we use elastic-apm-extension-ver-1-0-0-x86_64 as lambda layer 
2. use a newer version of elastic-apm=">6.8.1"
3. Result : TypeError: send() got an unexpected keyword argument 'flushed'

**Environment (please complete the following information)**
- OS: N/A - use lambda
- Python version: any
- Framework and version [e.g. Django 2.1]: None
- APM Server version: 1.0.0
- Agent version: >6.8.1




Discussion:
Some clarification might be needed.

The `flushed=True` behavior was introduced in 6.9.0, so that might be your issue if you're using 6.8.1. It's also not designed to be called directly, we call it via [this line](https://github.com/elastic/apm-agent-python/blob/45abe9734dd25acdc21633cdc58ab80304506d8a/elasticapm/contrib/serverless/aws.py#L224).

Are you using our [official lambda integration](https://www.elastic.co/guide/en/apm/agent/python/current/lambda-support.html) and extension?
We upgrade quite recently ( last week) - our team which takes care of APM did some upgrades on the server side as well and after that change, we experienced a heavy raise in this issue in our logs. I don't know why but I don't experience any issue since I downgrade elastic-apm to 6.8.1. All my point is that signature is required  "forced_flush" but call "flushed" argument on that specific line -  https://github.com/elastic/apm-agent-python/blob/main/elasticapm/transport/base.py#L183

Huh. You're totally right. I'm actually not sure how my manual testing didn't catch this. I'll have a fix shortly, thanks for the report.

Resolving patch:
diff --git a/elasticapm/transport/base.py b/elasticapm/transport/base.py
--- a/elasticapm/transport/base.py
+++ b/elasticapm/transport/base.py
@@ -176,11 +176,11 @@ def _process_queue(self):
             if flush:
                 if buffer_written:
                     self._flush(buffer, forced_flush=forced_flush)
-                elif forced_flush and "/localhost:" in self.client.config.server_url:
+                elif forced_flush and any(x in self.client.config.server_url for x in ("/localhost:", "/127.0.0.1:")):
                     # No data on buffer, but due to manual flush we should send
                     # an empty payload with flushed=true query param, but only
                     # to a local APM server (or lambda extension)
-                    self.send(None, flushed=True)
+                    self.send("", forced_flush=True)
                 self._last_flush = timeit.default_timer()
                 buffer = self._init_buffer()
                 buffer_written = False


Test patch:
diff --git a/tests/transports/test_base.py b/tests/transports/test_base.py
--- a/tests/transports/test_base.py
+++ b/tests/transports/test_base.py
@@ -264,3 +264,13 @@ def test_flushed_arg(sending_elasticapm_client):
     sending_elasticapm_client._transport.flush()
 
     assert sending_elasticapm_client.httpserver.requests[0].args["flushed"] == "true"
+
+
+@pytest.mark.parametrize("sending_elasticapm_client", [{"api_request_time": "100ms"}], indirect=True)
+def test_flushed_arg_with_wait(sending_elasticapm_client):
+    sending_elasticapm_client.begin_transaction("test_type")
+    sending_elasticapm_client.end_transaction("test")
+    time.sleep(0.2)
+    sending_elasticapm_client._transport.flush()
+
+    assert sending_elasticapm_client.httpserver.requests[1].args["flushed"] == "true"