internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: elastic/apm-agent-python

Issue:
assert scope["type"] == "http"`on websocket connection 
`
    ...lib/python3.9/site-packages/elasticapm/contrib/starlette/__init__.py", line 135, in __call__
    assert scope["type"] == "http"
AssertionError
`

**To Reproduce**

```py
import uvicorn
from elasticapm.contrib.starlette import make_apm_client, ElasticAPM
from fastapi import FastAPI, WebSocket

apm = make_apm_client({'SERVICE_NAME': 'test', 'SERVER_URL': 'http://0.0.0.0:8200'})
app = FastAPI()
app.add_middleware(ElasticAPM, client=apm)


@app.websocket('/ws/')
async def websocket_endpoint(
        websocket: WebSocket,
):
    await websocket.accept()


if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=18000)

```

run in Chrome console
```js
socket = new WebSocket('ws://127.0.0.1:18000/ws/');
```

**Environment (please complete the following information)**
- OS: MacOs
- Python version: 3.9
- Framework and version: FastAPI
- APM Server version: 3.6.1




Discussion:
Thank you for the report! I think instead of using an `assert` we need to just ignore non-http scopes. I'm going to work on this.

Resolving patch:
diff --git a/elasticapm/contrib/starlette/__init__.py b/elasticapm/contrib/starlette/__init__.py
--- a/elasticapm/contrib/starlette/__init__.py
+++ b/elasticapm/contrib/starlette/__init__.py
@@ -130,9 +130,10 @@ async def __call__(self, scope, receive, send):
             receive: receive awaitable callable
             send: send awaitable callable
         """
-        # we only handle the http scope, raise an exception for anything else
-        # see https://www.uvicorn.org/#the-asgi-interface
-        assert scope["type"] == "http"
+        # we only handle the http scope, skip anything else.
+        if scope["type"] != "http":
+            await self.app(scope, receive, send)
+            return
 
         @functools.wraps(send)
         async def wrapped_send(message):


Test patch:
diff --git a/tests/contrib/asyncio/starlette_tests.py b/tests/contrib/asyncio/starlette_tests.py
--- a/tests/contrib/asyncio/starlette_tests.py
+++ b/tests/contrib/asyncio/starlette_tests.py
@@ -104,6 +104,12 @@ async def hi_from_sub(request):
     async def hi_from_sub(request):
         return PlainTextResponse(request.path_params["name"])
 
+    @app.websocket_route("/ws")
+    async def ws(websocket):
+        await websocket.accept()
+        await websocket.send_text("Hello, world!")
+        await websocket.close()
+
     app.add_middleware(ElasticAPM, client=elasticapm_client)
 
     yield app
@@ -457,3 +463,12 @@ def test_make_client_without_config():
         c = make_apm_client(client_cls=TempStoreClient)
         c.close()
         assert c.config.service_name == "foo"
+
+
+def test_websocket(app, elasticapm_client):
+    client = TestClient(app)
+    with client.websocket_connect("/ws") as websocket:
+        data = websocket.receive_text()
+        assert data == "Hello, world!"
+
+    assert len(elasticapm_client.events[constants.TRANSACTION]) == 0
Repository: elastic/apm-agent-python

Issue:
Cookie value from request header is not getting sanitized
Hi, 

The APM python agent is silently throwing error when trying to sanitize the cookie value from request header. On debugging, I found that we are reading the cookie value incorrectly from context. 
 
Instead of  reading the cookie value using `event["context"]["request"]["headers"]["Cookie"]`, we read it as `event["context"]["request"]["headers"]["cookie"]`. 

https://github.com/elastic/apm-agent-python/blob/31c858595db709c766226e5cddb826d27e377d9d/elasticapm/processors.py#L116


Discussion:
Thanks for the report! Should be an easy fix.

Resolving patch:
diff --git a/elasticapm/processors.py b/elasticapm/processors.py
--- a/elasticapm/processors.py
+++ b/elasticapm/processors.py
@@ -118,7 +118,14 @@ def sanitize_http_request_cookies(client, event):
             cookie_string, "; ", "=", sanitize_field_names=client.config.sanitize_field_names
         )
     except (KeyError, TypeError):
-        pass
+        try:
+            # Sometimes it's Cookie, not cookie
+            cookie_string = force_text(event["context"]["request"]["headers"]["Cookie"], errors="replace")
+            event["context"]["request"]["headers"]["Cookie"] = _sanitize_string(
+                cookie_string, "; ", "=", sanitize_field_names=client.config.sanitize_field_names
+            )
+        except (KeyError, TypeError):
+            pass
     return event
 
 


Test patch:
diff --git a/tests/processors/tests.py b/tests/processors/tests.py
--- a/tests/processors/tests.py
+++ b/tests/processors/tests.py
@@ -222,6 +222,25 @@ def test_sanitize_http_request_cookies(elasticapm_client, custom_field, expected
 
     assert result["context"]["request"]["headers"]["cookie"] == expected_header_cookies
 
+    http_test_data["context"]["request"]["headers"].pop("cookie")
+    http_test_data["context"]["request"]["headers"][
+        "Cookie"
+    ] = "foo=bar; password=12345; secret=12345; csrftoken=abc; custom-sensitive-cookie=123"
+
+    result = processors.sanitize_http_request_cookies(elasticapm_client, http_test_data)
+    expected = {
+        "foo": "bar",
+        "password": processors.MASK,
+        "secret": processors.MASK,
+        "sessionid": processors.MASK,
+    }
+
+    expected.update(custom_field)
+
+    assert result["context"]["request"]["cookies"] == expected
+
+    assert result["context"]["request"]["headers"]["Cookie"] == expected_header_cookies
+
 
 @pytest.mark.parametrize(
     "elasticapm_client, expected_cookies",
Repository: elastic/apm-agent-python

Issue:
[META 527] User-agent header for transport
Implement [514](https://github.com/elastic/apm/pull/514) for all APM agents.


Discussion:

Resolving patch:
diff --git a/elasticapm/base.py b/elasticapm/base.py
--- a/elasticapm/base.py
+++ b/elasticapm/base.py
@@ -36,6 +36,7 @@
 import logging
 import os
 import platform
+import re
 import sys
 import threading
 import time
@@ -135,7 +136,7 @@ def __init__(self, config=None, **inline):
         headers = {
             "Content-Type": "application/x-ndjson",
             "Content-Encoding": "gzip",
-            "User-Agent": "elasticapm-python/%s" % elasticapm.VERSION,
+            "User-Agent": self.get_user_agent(),
         }
 
         transport_kwargs = {
@@ -419,6 +420,17 @@ def get_cloud_info(self):
             self.logger.warning("Unknown value for CLOUD_PROVIDER, skipping cloud metadata: {}".format(provider))
             return {}
 
+    def get_user_agent(self) -> str:
+        """
+        Compiles the user agent, which will be added as a header to all requests
+        to the APM Server
+        """
+        if self.config.service_version:
+            service_version = re.sub(r"[^\t _\x21-\x27\x2a-\x5b\x5d-\x7e\x80-\xff]", "_", self.config.service_version)
+            return "apm-agent-python/{} ({} {})".format(elasticapm.VERSION, self.config.service_name, service_version)
+        else:
+            return "apm-agent-python/{} ({})".format(elasticapm.VERSION, self.config.service_name)
+
     def build_metadata(self):
         data = {
             "service": self.get_service_info(),


Test patch:
diff --git a/tests/client/client_tests.py b/tests/client/client_tests.py
--- a/tests/client/client_tests.py
+++ b/tests/client/client_tests.py
@@ -297,7 +297,7 @@ def test_send(sending_elasticapm_client):
         "Content-Type": "application/x-ndjson",
         "Content-Encoding": "gzip",
         "Authorization": "Bearer %s" % sending_elasticapm_client.config.secret_token,
-        "User-Agent": "elasticapm-python/%s" % elasticapm.VERSION,
+        "User-Agent": "apm-agent-python/%s (myapp)" % elasticapm.VERSION,
     }
     seen_headers = dict(request.headers)
     for k, v in expected_headers.items():
@@ -867,3 +867,16 @@ def test_backdating_transaction(elasticapm_client):
     elasticapm_client.end_transaction()
     transaction = elasticapm_client.events[TRANSACTION][0]
     assert 1000 < transaction["duration"] < 2000
+
+
+@pytest.mark.parametrize(
+    "elasticapm_client,expected",
+    [
+        ({"service_version": "v2"}, " v2"),
+        ({"service_version": "v2 \x00"}, " v2 _"),
+        ({}, ""),
+    ],
+    indirect=["elasticapm_client"],
+)
+def test_user_agent(elasticapm_client, expected):
+    assert elasticapm_client.get_user_agent() == "apm-agent-python/unknown (myapp{})".format(expected)
Repository: elastic/apm-agent-python

Issue:
No module named 'elasticapm.metrics.sets.transactions'
fastapi: 0.70.0
elastic-apm: 6.6.2

Could not register elasticapm.metrics.sets.transactions.TransactionsMetricSet metricset: No module named 'elasticapm.metrics.sets.transactions'

```
  File "elasticapm/contrib/starlette/__init__.py", line 70, in make_apm_client
    return client_cls(config, **defaults)
  File "elasticapm/base.py", line 199, in __init__
    self._metrics.register(path)
  File "elasticapm/metrics/base_metrics.py", line 72, in register
    logger.warning("Could not register %s metricset: %s", class_path, compat.text_type(e))
  File "__init__.py", line 1480, in warning
    self._log(WARNING, msg, args, **kwargs)
  File "__init__.py", line 1615, in _log
    self.handle(record)
  File "__init__.py", line 1625, in handle
    self.callHandlers(record)
  File "__init__.py", line 967, in handle
    self.emit(record)
```


Discussion:

Resolving patch:
diff --git a/elasticapm/conf/__init__.py b/elasticapm/conf/__init__.py
--- a/elasticapm/conf/__init__.py
+++ b/elasticapm/conf/__init__.py
@@ -550,7 +550,6 @@ class Config(_ConfigBase):
         "METRICS_SETS",
         default=[
             "elasticapm.metrics.sets.cpu.CPUMetricSet",
-            "elasticapm.metrics.sets.transactions.TransactionsMetricSet",
         ],
     )
     metrics_interval = _ConfigValue(


Test patch:
Repository: elastic/apm-agent-python

Issue:
Breaking change in sync httpx refactor from #1403
elastic/apm-agent-python#1403 refactored a lot of the httpx code. However it seems that the sync version of the instrumentation still calls `self._set_disttracing_headers` which was removed in the same PR, causing any form of sync httpx instrumentation to crash.

**Environment (please complete the following information)**
- Agent version: 6.7.1


Discussion:

Resolving patch:
diff --git a/elasticapm/instrumentation/packages/httpx/sync/httpcore.py b/elasticapm/instrumentation/packages/httpx/sync/httpcore.py
--- a/elasticapm/instrumentation/packages/httpx/sync/httpcore.py
+++ b/elasticapm/instrumentation/packages/httpx/sync/httpcore.py
@@ -91,10 +91,6 @@ def mutate_unsampled_call_args(self, module, method, wrapped, instance, args, kw
         trace_parent = transaction.trace_parent.copy_from(
             span_id=transaction.id, trace_options=TracingOptions(recorded=False)
         )
-        if "headers" in kwargs:
-            headers = kwargs["headers"]
-            if headers is None:
-                headers = []
-                kwargs["headers"] = headers
-            self._set_disttracing_headers(headers, trace_parent, transaction)
+        headers = utils.get_request_data(args, kwargs)[2]
+        utils.set_disttracing_headers(headers, trace_parent, transaction)
         return args, kwargs


Test patch:
Repository: elastic/apm-agent-python

Issue:
[ci] tests.config.tests.test_config_all_upper_case failing
It appears that the `tests.config.tests.test_config_all_upper_case` test is failing [across a number of different platforms on the master branch](https://apm-ci.elastic.co/job/apm-agent-python/job/apm-agent-python-mbp/job/master/593/testReport/):
<img width="684" alt="Screen Shot 2021-12-16 at 9 04 34 AM" src="https://user-images.githubusercontent.com/111616/146331918-5ee9fa87-156b-42b1-8dc5-53ceea0d6df1.png">




Discussion:
@cachedout I'm aware, I just didn't get around to fix it yet. It's an easy fix, I'll open a PR 

Resolving patch:
diff --git a/elasticapm/conf/__init__.py b/elasticapm/conf/__init__.py
--- a/elasticapm/conf/__init__.py
+++ b/elasticapm/conf/__init__.py
@@ -594,7 +594,7 @@ class Config(_ConfigBase):
         type=int,
     )
     exit_span_min_duration = _ConfigValue(
-        "exit_span_min_duration",
+        "EXIT_SPAN_MIN_DURATION",
         default=1,
         validators=[duration_validator],
         type=float,


Test patch:
Repository: elastic/apm-agent-python

Issue:
[META 571] Align on default service name
[![issue details](https://img.shields.io/endpoint?label=meta-issue:&url=https%3A%2F%2Fgiss.app.elstc.co%2Fapi%2Fstatus%2Felastic%2Fapm%2F571)](https://github.com/elastic/apm/issues/571)

[![issue details](https://img.shields.io/endpoint?label=spec-issue:&url=https%3A%2F%2Fgiss.app.elstc.co%2Fapi%2Fstatus%2Felastic%2Fapm%2F572)](https://github.com/elastic/apm/issues/572)

As defined in https://github.com/elastic/apm/pull/499, agents don't require users to configure the `service_name`. Ideally, the a descriptive value can be inferred form the application. But in some cases that's not possible. In these cases, agents must now align on the naming scheme for the default service name. This enables the UI to show inline help for services that it identifies as unnamed services based on the naming scheme. 


Discussion:

Resolving patch:
diff --git a/elasticapm/conf/__init__.py b/elasticapm/conf/__init__.py
--- a/elasticapm/conf/__init__.py
+++ b/elasticapm/conf/__init__.py
@@ -509,7 +509,10 @@ def copy(self):
 
 class Config(_ConfigBase):
     service_name = _ConfigValue(
-        "SERVICE_NAME", validators=[RegexValidator("^[a-zA-Z0-9 _-]+$")], default="python_service", required=True
+        "SERVICE_NAME",
+        validators=[RegexValidator("^[a-zA-Z0-9 _-]+$")],
+        default="unknown-python-service",
+        required=True,
     )
     service_node_name = _ConfigValue("SERVICE_NODE_NAME")
     environment = _ConfigValue("ENVIRONMENT")


Test patch:
Repository: elastic/apm-agent-python

Issue:
Missing error message: Oops. That didn't work. The following error occured:
**Describe the bug**: No error message appear

```
>> python3 manage.py elasticapm test

Trying to send a test error to APM Server using these settings:

SERVICE_NAME:	DJANGO_DEVELOPMENT
SECRET_TOKEN:	xxx
SERVER:		http://localhost:8200

Oops. That didn't work. The following error occured: 

Fetched APM Server version 7.17.0
```

**To Reproduce**

Not sure how to reproduce this. 
Where can I find a detailed error message?



Discussion:

Resolving patch:
diff --git a/elasticapm/transport/http.py b/elasticapm/transport/http.py
--- a/elasticapm/transport/http.py
+++ b/elasticapm/transport/http.py
@@ -194,7 +194,7 @@ def fetch_server_info(self):
             body = response.data
             data = json_encoder.loads(body.decode("utf8"))
             version = data["version"]
-            logger.info("Fetched APM Server version %s", version)
+            logger.debug("Fetched APM Server version %s", version)
             self.client.server_version = version_string_to_tuple(version)
         except (urllib3.exceptions.RequestError, urllib3.exceptions.HTTPError) as e:
             logger.warning("HTTP error while fetching server information: %s", str(e))


Test patch:
Repository: elastic/apm-agent-python

Issue:
Reduce default stack_trace_limit from 500 to 50
Looking through the [config docs](https://docs.google.com/spreadsheets/d/1JJjZotapacA3FkHc2sv_0wiChILi3uKnkwLTjtBmxwU/edit#gid=0&range=A63), all other agents set the default limit to 50.

Setting a modest limit for the stack traces is important for APM Server to avoid out of memory issues when the in-memory queue fills up. The APM Server's queue size is measured in the number of events, not bytes. Therefore, it's important to be able to estimate the maximum event size in bytes so that we can provision an appropriate amount of memory for the default queue size.

cc @simitt 


Discussion:
[good first issue](https://github.com/elastic/apm-agent-python/issues?q=is%3Aissue+is%3Aclosed+label%3A%22good+first+issue%22 ) label? :-)

Resolving patch:
diff --git a/elasticapm/conf/__init__.py b/elasticapm/conf/__init__.py
--- a/elasticapm/conf/__init__.py
+++ b/elasticapm/conf/__init__.py
@@ -574,7 +574,7 @@ class Config(_ConfigBase):
         "TRANSACTION_SAMPLE_RATE", type=float, validators=[PrecisionValidator(4, 0.0001)], default=1.0
     )
     transaction_max_spans = _ConfigValue("TRANSACTION_MAX_SPANS", type=int, default=500)
-    stack_trace_limit = _ConfigValue("STACK_TRACE_LIMIT", type=int, default=500)
+    stack_trace_limit = _ConfigValue("STACK_TRACE_LIMIT", type=int, default=50)
     span_frames_min_duration = _ConfigValue(
         "SPAN_FRAMES_MIN_DURATION",
         default=5,


Test patch:
Repository: elastic/apm-agent-python

Issue:
[META 576] Sanitize `*auth*` instead of `authorization`
[![issue details](https://img.shields.io/endpoint?label=meta-issue:&url=https%3A%2F%2Fgiss.app.elstc.co%2Fapi%2Fstatus%2Felastic%2Fapm%2F576)](https://github.com/elastic/apm/issues/576)

[![issue details](https://img.shields.io/endpoint?label=spec-issue:&url=https%3A%2F%2Fgiss.app.elstc.co%2Fapi%2Fstatus%2Felastic%2Fapm%2F577)](https://github.com/elastic/apm/issues/577)

Sanitize `*auth*` instead of `authorization`


Discussion:

Resolving patch:
diff --git a/elasticapm/conf/constants.py b/elasticapm/conf/constants.py
--- a/elasticapm/conf/constants.py
+++ b/elasticapm/conf/constants.py
@@ -95,7 +95,7 @@ def _starmatch_to_regex(pattern):
     "*session*",
     "*credit*",
     "*card*",
-    "authorization",
+    "*auth*",
     "set-cookie",
 ]
 


Test patch:
Repository: elastic/apm-agent-python

Issue:
[META 619] Change default behavior for span compression and dropping of spans
[![issue details](https://img.shields.io/endpoint?label=meta-issue:&url=https%3A%2F%2Fgiss.app.elstc.co%2Fapi%2Fstatus%2Felastic%2Fapm%2F619)](https://github.com/elastic/apm/issues/619)

Spec change: https://github.com/elastic/apm/pull/611

This includes:
- [x] Change default value for `span_compression_enabled` to `true`
- [x] Change default value for `span_compression_same_kind_max_duration` to `0ms`


Discussion:

Resolving patch:
diff --git a/elasticapm/conf/__init__.py b/elasticapm/conf/__init__.py
--- a/elasticapm/conf/__init__.py
+++ b/elasticapm/conf/__init__.py
@@ -611,14 +611,14 @@ class Config(_ConfigBase):
     span_stack_trace_min_duration = _DurationConfigValue(
         "SPAN_STACK_TRACE_MIN_DURATION", default=timedelta(seconds=0.005), unitless_factor=0.001
     )
-    span_compression_enabled = _BoolConfigValue("SPAN_COMPRESSION_ENABLED", default=False)
+    span_compression_enabled = _BoolConfigValue("SPAN_COMPRESSION_ENABLED", default=True)
     span_compression_exact_match_max_duration = _DurationConfigValue(
         "SPAN_COMPRESSION_EXACT_MATCH_MAX_DURATION",
         default=timedelta(seconds=0.05),
     )
     span_compression_same_kind_max_duration = _DurationConfigValue(
         "SPAN_COMPRESSION_SAME_KIND_MAX_DURATION",
-        default=timedelta(seconds=0.005),
+        default=timedelta(seconds=0),
     )
     exit_span_min_duration = _DurationConfigValue(
         "EXIT_SPAN_MIN_DURATION",


Test patch:
Repository: elastic/apm-agent-python

Issue:
KeyError: 'otel_attributes'
elastic-apm:  6.9.0

```
KeyError: 'otel_attributes'
  File "elasticapm/contrib/starlette/__init__.py", line 185, in __call__
    self.client.end_transaction()
  File "elasticapm/base.py", line 313, in end_transaction
    transaction = self.tracer.end_transaction(result, name, duration=duration)
  File "elasticapm/traces.py", line 898, in end_transaction
    transaction.end(duration=duration)
  File "elasticapm/traces.py", line 232, in end
    super().end(skip_frames, duration)
  File "elasticapm/traces.py", line 126, in end
    self.compression_buffer.report()
  File "elasticapm/traces.py", line 670, in report
    self.tracer.queue_func(SPAN, self.to_dict())
  File "elasticapm/traces.py", line 580, in to_dict
    attributes = self.context.pop("otel_attributes")
```



Discussion:

Resolving patch:
diff --git a/elasticapm/traces.py b/elasticapm/traces.py
--- a/elasticapm/traces.py
+++ b/elasticapm/traces.py
@@ -577,7 +577,7 @@ def to_dict(self) -> dict:
                         result["otel"]["attributes"] = self.context.pop("otel_attributes")
             else:
                 # Attributes map to labels for older versions
-                attributes = self.context.pop("otel_attributes")
+                attributes = self.context.pop("otel_attributes", {})
                 if attributes and ("tags" not in self.context):
                     self.context["tags"] = {}
                 for key, value in attributes.items():


Test patch:
diff --git a/tests/client/transaction_tests.py b/tests/client/transaction_tests.py
--- a/tests/client/transaction_tests.py
+++ b/tests/client/transaction_tests.py
@@ -38,6 +38,23 @@
 from elasticapm.utils.disttracing import TraceParent
 
 
+@pytest.mark.parametrize("elasticapm_client", [{"server_version": (7, 15)}, {"server_version": (7, 16)}], indirect=True)
+def test_transaction_span(elasticapm_client):
+    elasticapm_client.begin_transaction("test")
+    with elasticapm.capture_span("test", extra={"a": "b"}):
+        pass
+    elasticapm_client.end_transaction("test", constants.OUTCOME.SUCCESS)
+    transactions = elasticapm_client.events[constants.TRANSACTION]
+    assert len(transactions) == 1
+    assert transactions[0]["name"] == "test"
+    assert transactions[0]["type"] == "test"
+    assert transactions[0]["result"] == constants.OUTCOME.SUCCESS
+
+    spans = elasticapm_client.events[constants.SPAN]
+    assert len(spans) == 1
+    assert spans[0]["name"] == "test"
+
+
 @pytest.mark.parametrize(
     "elasticapm_client", [{"transactions_ignore_patterns": ["^OPTIONS", "views.api.v2"]}], indirect=True
 )
Repository: elastic/apm-agent-python

Issue:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 369: invalid start byte
**Describe the bug**: 
Sending PUT request to FastAPI with binary file encoded, its returns a error.

**To Reproduce**

1. Configure FastAPI with elasticapm.contrib.starlette
2. Send a PUT request with binary file

**Environment (please complete the following information)**
- OS: Linux
- Python version: 3.8
- Framework and version: fastapi 0.61.2
- APM Server version: 8
- Agent version: 8

The same problema was resolved in the main code : [#344](https://github.com/elastic/apm-agent-python/issues/334)



Discussion:

Resolving patch:
diff --git a/elasticapm/contrib/starlette/utils.py b/elasticapm/contrib/starlette/utils.py
--- a/elasticapm/contrib/starlette/utils.py
+++ b/elasticapm/contrib/starlette/utils.py
@@ -129,7 +129,7 @@ async def get_body(request: Request) -> str:
 
     request._stream_consumed = False
 
-    return body.decode("utf-8")
+    return body.decode("utf-8", errors="replace")
 
 
 async def query_params_to_dict(query_params: str) -> dict:


Test patch: