We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
dictionary changed size during iteration
Same problem to https://github.com/elastic/apm-agent-python/issues/717

```
  File "/elasticapm/base.py", line 180, in <lambda>
    local_var,
  File "/elasticapm/utils/__init__.py", line 64, in varmap
    ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)
  File "/elasticapm/utils/__init__.py", line 64, in <genexpr>
    ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)

RuntimeError: dictionary changed size during iteration
```

Environment (please complete the following information)

OS: Ubuntu 20.04 stable
Python version: 2.7.18
Framework and version Django 1.3
APM Server version: 7.6.0
Agent version: 5.8
dictionary changed size during iteration
Same problem to https://github.com/elastic/apm-agent-python/issues/717

```
  File "/elasticapm/base.py", line 180, in <lambda>
    local_var,
  File "/elasticapm/utils/__init__.py", line 64, in varmap
    ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)
  File "/elasticapm/utils/__init__.py", line 64, in <genexpr>
    ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)

RuntimeError: dictionary changed size during iteration
```

Environment (please complete the following information)

OS: Ubuntu 20.04 stable
Python version: 2.7.18
Framework and version Django 1.3
APM Server version: 7.6.0
Agent version: 5.8

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `elasticapm/utils/__init__.py`
Content:
```
1 #  BSD 3-Clause License
2 #
3 #  Copyright (c) 2012, the Sentry Team, see AUTHORS for more details
4 #  Copyright (c) 2019, Elasticsearch BV
5 #  All rights reserved.
6 #
7 #  Redistribution and use in source and binary forms, with or without
8 #  modification, are permitted provided that the following conditions are met:
9 #
10 #  * Redistributions of source code must retain the above copyright notice, this
11 #    list of conditions and the following disclaimer.
12 #
13 #  * Redistributions in binary form must reproduce the above copyright notice,
14 #    this list of conditions and the following disclaimer in the documentation
15 #    and/or other materials provided with the distribution.
16 #
17 #  * Neither the name of the copyright holder nor the names of its
18 #    contributors may be used to endorse or promote products derived from
19 #    this software without specific prior written permission.
20 #
21 #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 #  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 #  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 #  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 #  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 #  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 #  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 #  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 #  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 
31 import base64
32 import os
33 import re
34 from functools import partial
35 
36 from elasticapm.conf import constants
37 from elasticapm.utils import compat, encoding
38 
39 try:
40     from functools import partialmethod
41 
42     partial_types = (partial, partialmethod)
43 except ImportError:
44     # Python 2
45     partial_types = (partial,)
46 
47 
48 default_ports = {"https": 443, "http": 80, "postgresql": 5432, "mysql": 3306, "mssql": 1433}
49 
50 
51 def varmap(func, var, context=None, name=None, **kwargs):
52     """
53     Executes ``func(key_name, value)`` on all values,
54     recursively discovering dict and list scoped
55     values.
56     """
57     if context is None:
58         context = set()
59     objid = id(var)
60     if objid in context:
61         return func(name, "<...>", **kwargs)
62     context.add(objid)
63     if isinstance(var, dict):
64         ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)
65     elif isinstance(var, (list, tuple)):
66         ret = func(name, [varmap(func, f, context, name, **kwargs) for f in var], **kwargs)
67     else:
68         ret = func(name, var, **kwargs)
69     context.remove(objid)
70     return ret
71 
72 
73 def get_name_from_func(func):
74     # partials don't have `__module__` or `__name__`, so we use the values from the "inner" function
75     if isinstance(func, partial_types):
76         return "partial({})".format(get_name_from_func(func.func))
77     elif hasattr(func, "_partialmethod") and hasattr(func._partialmethod, "func"):
78         return "partial({})".format(get_name_from_func(func._partialmethod.func))
79 
80     module = func.__module__
81 
82     if hasattr(func, "__name__"):
83         view_name = func.__name__
84     else:  # Fall back if there's no __name__
85         view_name = func.__class__.__name__
86 
87     return "{0}.{1}".format(module, view_name)
88 
89 
90 def build_name_with_http_method_prefix(name, request):
91     return " ".join((request.method, name)) if name else name
92 
93 
94 def is_master_process():
95     # currently only recognizes uwsgi master process
96     try:
97         import uwsgi
98 
99         return os.getpid() == uwsgi.masterpid()
100     except ImportError:
101         return False
102 
103 
104 def get_url_dict(url):
105     parse_result = compat.urlparse.urlparse(url)
106 
107     url_dict = {
108         "full": encoding.keyword_field(url),
109         "protocol": parse_result.scheme + ":",
110         "hostname": encoding.keyword_field(parse_result.hostname),
111         "pathname": encoding.keyword_field(parse_result.path),
112     }
113 
114     port = None if parse_result.port is None else str(parse_result.port)
115 
116     if port:
117         url_dict["port"] = port
118     if parse_result.query:
119         url_dict["search"] = encoding.keyword_field("?" + parse_result.query)
120     return url_dict
121 
122 
123 def sanitize_url(url):
124     if "@" not in url:
125         return url
126     parts = compat.urlparse.urlparse(url)
127     return url.replace("%s:%s" % (parts.username, parts.password), "%s:%s" % (parts.username, constants.MASK))
128 
129 
130 def get_host_from_url(url):
131     parsed_url = compat.urlparse.urlparse(url)
132     host = parsed_url.hostname or " "
133 
134     if parsed_url.port and default_ports.get(parsed_url.scheme) != parsed_url.port:
135         host += ":" + str(parsed_url.port)
136 
137     return host
138 
139 
140 def url_to_destination(url, service_type="external"):
141     parts = compat.urlparse.urlsplit(url)
142     hostname = parts.hostname
143     # preserve brackets for IPv6 URLs
144     if "://[" in url:
145         hostname = "[%s]" % hostname
146     try:
147         port = parts.port
148     except ValueError:
149         # Malformed port, just use None rather than raising an exception
150         port = None
151     default_port = default_ports.get(parts.scheme, None)
152     name = "%s://%s" % (parts.scheme, hostname)
153     resource = hostname
154     if not port and parts.scheme in default_ports:
155         port = default_ports[parts.scheme]
156     if port:
157         if port != default_port:
158             name += ":%d" % port
159         resource += ":%d" % port
160     return {"service": {"name": name, "resource": resource, "type": service_type}}
161 
162 
163 def read_pem_file(file_obj):
164     cert = b""
165     for line in file_obj:
166         if line.startswith(b"-----BEGIN CERTIFICATE-----"):
167             break
168     # scan until we find the first END CERTIFICATE marker
169     for line in file_obj:
170         if line.startswith(b"-----END CERTIFICATE-----"):
171             break
172         cert += line.strip()
173     return base64.b64decode(cert)
174 
175 
176 def starmatch_to_regex(pattern):
177     i, n = 0, len(pattern)
178     res = []
179     while i < n:
180         c = pattern[i]
181         i = i + 1
182         if c == "*":
183             res.append(".*")
184         else:
185             res.append(re.escape(c))
186     return re.compile(r"(?:%s)\Z" % "".join(res), re.IGNORECASE | re.DOTALL)
187
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/elasticapm/utils/__init__.py b/elasticapm/utils/__init__.py
--- a/elasticapm/utils/__init__.py
+++ b/elasticapm/utils/__init__.py
@@ -61,7 +61,10 @@
         return func(name, "<...>", **kwargs)
     context.add(objid)
     if isinstance(var, dict):
-        ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)
+        # iterate over a copy of the dictionary to avoid "dictionary changed size during iteration" issues
+        ret = func(
+            name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var.copy())), **kwargs
+        )
     elif isinstance(var, (list, tuple)):
         ret = func(name, [varmap(func, f, context, name, **kwargs) for f in var], **kwargs)
     else:

{"golden_diff": "diff --git a/elasticapm/utils/__init__.py b/elasticapm/utils/__init__.py\n--- a/elasticapm/utils/__init__.py\n+++ b/elasticapm/utils/__init__.py\n@@ -61,7 +61,10 @@\n         return func(name, \"<...>\", **kwargs)\n     context.add(objid)\n     if isinstance(var, dict):\n-        ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)\n+        # iterate over a copy of the dictionary to avoid \"dictionary changed size during iteration\" issues\n+        ret = func(\n+            name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var.copy())), **kwargs\n+        )\n     elif isinstance(var, (list, tuple)):\n         ret = func(name, [varmap(func, f, context, name, **kwargs) for f in var], **kwargs)\n     else:\n", "issue": "dictionary changed size during iteration\nSame problem to https://github.com/elastic/apm-agent-python/issues/717\r\n\r\n```\r\n  File \"/elasticapm/base.py\", line 180, in <lambda>\r\n    local_var,\r\n  File \"/elasticapm/utils/__init__.py\", line 64, in varmap\r\n    ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)\r\n  File \"/elasticapm/utils/__init__.py\", line 64, in <genexpr>\r\n    ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)\r\n\r\nRuntimeError: dictionary changed size during iteration\r\n```\r\n\r\nEnvironment (please complete the following information)\r\n\r\nOS: Ubuntu 20.04 stable\r\nPython version: 2.7.18\r\nFramework and version Django 1.3\r\nAPM Server version: 7.6.0\r\nAgent version: 5.8\ndictionary changed size during iteration\nSame problem to https://github.com/elastic/apm-agent-python/issues/717\r\n\r\n```\r\n  File \"/elasticapm/base.py\", line 180, in <lambda>\r\n    local_var,\r\n  File \"/elasticapm/utils/__init__.py\", line 64, in varmap\r\n    ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)\r\n  File \"/elasticapm/utils/__init__.py\", line 64, in <genexpr>\r\n    ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)\r\n\r\nRuntimeError: dictionary changed size during iteration\r\n```\r\n\r\nEnvironment (please complete the following information)\r\n\r\nOS: Ubuntu 20.04 stable\r\nPython version: 2.7.18\r\nFramework and version Django 1.3\r\nAPM Server version: 7.6.0\r\nAgent version: 5.8\n", "before_files": [{"content": "#  BSD 3-Clause License\n#\n#  Copyright (c) 2012, the Sentry Team, see AUTHORS for more details\n#  Copyright (c) 2019, Elasticsearch BV\n#  All rights reserved.\n#\n#  Redistribution and use in source and binary forms, with or without\n#  modification, are permitted provided that the following conditions are met:\n#\n#  * Redistributions of source code must retain the above copyright notice, this\n#    list of conditions and the following disclaimer.\n#\n#  * Redistributions in binary form must reproduce the above copyright notice,\n#    this list of conditions and the following disclaimer in the documentation\n#    and/or other materials provided with the distribution.\n#\n#  * Neither the name of the copyright holder nor the names of its\n#    contributors may be used to endorse or promote products derived from\n#    this software without specific prior written permission.\n#\n#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n#  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n#  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n#  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n#  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n\nimport base64\nimport os\nimport re\nfrom functools import partial\n\nfrom elasticapm.conf import constants\nfrom elasticapm.utils import compat, encoding\n\ntry:\n    from functools import partialmethod\n\n    partial_types = (partial, partialmethod)\nexcept ImportError:\n    # Python 2\n    partial_types = (partial,)\n\n\ndefault_ports = {\"https\": 443, \"http\": 80, \"postgresql\": 5432, \"mysql\": 3306, \"mssql\": 1433}\n\n\ndef varmap(func, var, context=None, name=None, **kwargs):\n    \"\"\"\n    Executes ``func(key_name, value)`` on all values,\n    recursively discovering dict and list scoped\n    values.\n    \"\"\"\n    if context is None:\n        context = set()\n    objid = id(var)\n    if objid in context:\n        return func(name, \"<...>\", **kwargs)\n    context.add(objid)\n    if isinstance(var, dict):\n        ret = func(name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var)), **kwargs)\n    elif isinstance(var, (list, tuple)):\n        ret = func(name, [varmap(func, f, context, name, **kwargs) for f in var], **kwargs)\n    else:\n        ret = func(name, var, **kwargs)\n    context.remove(objid)\n    return ret\n\n\ndef get_name_from_func(func):\n    # partials don't have `__module__` or `__name__`, so we use the values from the \"inner\" function\n    if isinstance(func, partial_types):\n        return \"partial({})\".format(get_name_from_func(func.func))\n    elif hasattr(func, \"_partialmethod\") and hasattr(func._partialmethod, \"func\"):\n        return \"partial({})\".format(get_name_from_func(func._partialmethod.func))\n\n    module = func.__module__\n\n    if hasattr(func, \"__name__\"):\n        view_name = func.__name__\n    else:  # Fall back if there's no __name__\n        view_name = func.__class__.__name__\n\n    return \"{0}.{1}\".format(module, view_name)\n\n\ndef build_name_with_http_method_prefix(name, request):\n    return \" \".join((request.method, name)) if name else name\n\n\ndef is_master_process():\n    # currently only recognizes uwsgi master process\n    try:\n        import uwsgi\n\n        return os.getpid() == uwsgi.masterpid()\n    except ImportError:\n        return False\n\n\ndef get_url_dict(url):\n    parse_result = compat.urlparse.urlparse(url)\n\n    url_dict = {\n        \"full\": encoding.keyword_field(url),\n        \"protocol\": parse_result.scheme + \":\",\n        \"hostname\": encoding.keyword_field(parse_result.hostname),\n        \"pathname\": encoding.keyword_field(parse_result.path),\n    }\n\n    port = None if parse_result.port is None else str(parse_result.port)\n\n    if port:\n        url_dict[\"port\"] = port\n    if parse_result.query:\n        url_dict[\"search\"] = encoding.keyword_field(\"?\" + parse_result.query)\n    return url_dict\n\n\ndef sanitize_url(url):\n    if \"@\" not in url:\n        return url\n    parts = compat.urlparse.urlparse(url)\n    return url.replace(\"%s:%s\" % (parts.username, parts.password), \"%s:%s\" % (parts.username, constants.MASK))\n\n\ndef get_host_from_url(url):\n    parsed_url = compat.urlparse.urlparse(url)\n    host = parsed_url.hostname or \" \"\n\n    if parsed_url.port and default_ports.get(parsed_url.scheme) != parsed_url.port:\n        host += \":\" + str(parsed_url.port)\n\n    return host\n\n\ndef url_to_destination(url, service_type=\"external\"):\n    parts = compat.urlparse.urlsplit(url)\n    hostname = parts.hostname\n    # preserve brackets for IPv6 URLs\n    if \"://[\" in url:\n        hostname = \"[%s]\" % hostname\n    try:\n        port = parts.port\n    except ValueError:\n        # Malformed port, just use None rather than raising an exception\n        port = None\n    default_port = default_ports.get(parts.scheme, None)\n    name = \"%s://%s\" % (parts.scheme, hostname)\n    resource = hostname\n    if not port and parts.scheme in default_ports:\n        port = default_ports[parts.scheme]\n    if port:\n        if port != default_port:\n            name += \":%d\" % port\n        resource += \":%d\" % port\n    return {\"service\": {\"name\": name, \"resource\": resource, \"type\": service_type}}\n\n\ndef read_pem_file(file_obj):\n    cert = b\"\"\n    for line in file_obj:\n        if line.startswith(b\"-----BEGIN CERTIFICATE-----\"):\n            break\n    # scan until we find the first END CERTIFICATE marker\n    for line in file_obj:\n        if line.startswith(b\"-----END CERTIFICATE-----\"):\n            break\n        cert += line.strip()\n    return base64.b64decode(cert)\n\n\ndef starmatch_to_regex(pattern):\n    i, n = 0, len(pattern)\n    res = []\n    while i < n:\n        c = pattern[i]\n        i = i + 1\n        if c == \"*\":\n            res.append(\".*\")\n        else:\n            res.append(re.escape(c))\n    return re.compile(r\"(?:%s)\\Z\" % \"\".join(res), re.IGNORECASE | re.DOTALL)\n", "path": "elasticapm/utils/__init__.py"}], "after_files": [{"content": "#  BSD 3-Clause License\n#\n#  Copyright (c) 2012, the Sentry Team, see AUTHORS for more details\n#  Copyright (c) 2019, Elasticsearch BV\n#  All rights reserved.\n#\n#  Redistribution and use in source and binary forms, with or without\n#  modification, are permitted provided that the following conditions are met:\n#\n#  * Redistributions of source code must retain the above copyright notice, this\n#    list of conditions and the following disclaimer.\n#\n#  * Redistributions in binary form must reproduce the above copyright notice,\n#    this list of conditions and the following disclaimer in the documentation\n#    and/or other materials provided with the distribution.\n#\n#  * Neither the name of the copyright holder nor the names of its\n#    contributors may be used to endorse or promote products derived from\n#    this software without specific prior written permission.\n#\n#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n#  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n#  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n#  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n#  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n\nimport base64\nimport os\nimport re\nfrom functools import partial\n\nfrom elasticapm.conf import constants\nfrom elasticapm.utils import compat, encoding\n\ntry:\n    from functools import partialmethod\n\n    partial_types = (partial, partialmethod)\nexcept ImportError:\n    # Python 2\n    partial_types = (partial,)\n\n\ndefault_ports = {\"https\": 443, \"http\": 80, \"postgresql\": 5432, \"mysql\": 3306, \"mssql\": 1433}\n\n\ndef varmap(func, var, context=None, name=None, **kwargs):\n    \"\"\"\n    Executes ``func(key_name, value)`` on all values,\n    recursively discovering dict and list scoped\n    values.\n    \"\"\"\n    if context is None:\n        context = set()\n    objid = id(var)\n    if objid in context:\n        return func(name, \"<...>\", **kwargs)\n    context.add(objid)\n    if isinstance(var, dict):\n        # iterate over a copy of the dictionary to avoid \"dictionary changed size during iteration\" issues\n        ret = func(\n            name, dict((k, varmap(func, v, context, k, **kwargs)) for k, v in compat.iteritems(var.copy())), **kwargs\n        )\n    elif isinstance(var, (list, tuple)):\n        ret = func(name, [varmap(func, f, context, name, **kwargs) for f in var], **kwargs)\n    else:\n        ret = func(name, var, **kwargs)\n    context.remove(objid)\n    return ret\n\n\ndef get_name_from_func(func):\n    # partials don't have `__module__` or `__name__`, so we use the values from the \"inner\" function\n    if isinstance(func, partial_types):\n        return \"partial({})\".format(get_name_from_func(func.func))\n    elif hasattr(func, \"_partialmethod\") and hasattr(func._partialmethod, \"func\"):\n        return \"partial({})\".format(get_name_from_func(func._partialmethod.func))\n\n    module = func.__module__\n\n    if hasattr(func, \"__name__\"):\n        view_name = func.__name__\n    else:  # Fall back if there's no __name__\n        view_name = func.__class__.__name__\n\n    return \"{0}.{1}\".format(module, view_name)\n\n\ndef build_name_with_http_method_prefix(name, request):\n    return \" \".join((request.method, name)) if name else name\n\n\ndef is_master_process():\n    # currently only recognizes uwsgi master process\n    try:\n        import uwsgi\n\n        return os.getpid() == uwsgi.masterpid()\n    except ImportError:\n        return False\n\n\ndef get_url_dict(url):\n    parse_result = compat.urlparse.urlparse(url)\n\n    url_dict = {\n        \"full\": encoding.keyword_field(url),\n        \"protocol\": parse_result.scheme + \":\",\n        \"hostname\": encoding.keyword_field(parse_result.hostname),\n        \"pathname\": encoding.keyword_field(parse_result.path),\n    }\n\n    port = None if parse_result.port is None else str(parse_result.port)\n\n    if port:\n        url_dict[\"port\"] = port\n    if parse_result.query:\n        url_dict[\"search\"] = encoding.keyword_field(\"?\" + parse_result.query)\n    return url_dict\n\n\ndef sanitize_url(url):\n    if \"@\" not in url:\n        return url\n    parts = compat.urlparse.urlparse(url)\n    return url.replace(\"%s:%s\" % (parts.username, parts.password), \"%s:%s\" % (parts.username, constants.MASK))\n\n\ndef get_host_from_url(url):\n    parsed_url = compat.urlparse.urlparse(url)\n    host = parsed_url.hostname or \" \"\n\n    if parsed_url.port and default_ports.get(parsed_url.scheme) != parsed_url.port:\n        host += \":\" + str(parsed_url.port)\n\n    return host\n\n\ndef url_to_destination(url, service_type=\"external\"):\n    parts = compat.urlparse.urlsplit(url)\n    hostname = parts.hostname\n    # preserve brackets for IPv6 URLs\n    if \"://[\" in url:\n        hostname = \"[%s]\" % hostname\n    try:\n        port = parts.port\n    except ValueError:\n        # Malformed port, just use None rather than raising an exception\n        port = None\n    default_port = default_ports.get(parts.scheme, None)\n    name = \"%s://%s\" % (parts.scheme, hostname)\n    resource = hostname\n    if not port and parts.scheme in default_ports:\n        port = default_ports[parts.scheme]\n    if port:\n        if port != default_port:\n            name += \":%d\" % port\n        resource += \":%d\" % port\n    return {\"service\": {\"name\": name, \"resource\": resource, \"type\": service_type}}\n\n\ndef read_pem_file(file_obj):\n    cert = b\"\"\n    for line in file_obj:\n        if line.startswith(b\"-----BEGIN CERTIFICATE-----\"):\n            break\n    # scan until we find the first END CERTIFICATE marker\n    for line in file_obj:\n        if line.startswith(b\"-----END CERTIFICATE-----\"):\n            break\n        cert += line.strip()\n    return base64.b64decode(cert)\n\n\ndef starmatch_to_regex(pattern):\n    i, n = 0, len(pattern)\n    res = []\n    while i < n:\n        c = pattern[i]\n        i = i + 1\n        if c == \"*\":\n            res.append(\".*\")\n        else:\n            res.append(re.escape(c))\n    return re.compile(r\"(?:%s)\\Z\" % \"\".join(res), re.IGNORECASE | re.DOTALL)\n", "path": "elasticapm/utils/__init__.py"}]}