We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Support ElasticSearch 7.14
The python package `elasticsearch-py` introduced the `terms_enum` parameter from ElasticSearch 7.14. This is currently not being instrumented and breaking tests.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/scout_apm/instruments/elasticsearch.py`
Content:
```
1 # coding=utf-8
2 from __future__ import absolute_import, division, print_function, unicode_literals
3 
4 import logging
5 from collections import namedtuple
6 
7 import wrapt
8 
9 from scout_apm.compat import get_pos_args, unwrap_decorators
10 from scout_apm.core.tracked_request import TrackedRequest
11 
12 try:
13     from elasticsearch import Elasticsearch, Transport
14 except ImportError:  # pragma: no cover
15     Elasticsearch = None
16     Transport = None
17 
18 logger = logging.getLogger(__name__)
19 
20 
21 def ensure_installed():
22     logger.debug("Instrumenting elasticsearch.")
23 
24     if Elasticsearch is None:
25         logger.debug(
26             "Couldn't import elasticsearch.Elasticsearch - probably not installed."
27         )
28     else:
29         ensure_client_instrumented()
30         ensure_transport_instrumented()
31 
32 
33 ClientMethod = namedtuple("ClientMethod", ["name", "takes_index_argument"])
34 
35 CLIENT_METHODS = [
36     ClientMethod("bulk", True),
37     ClientMethod("clear_scroll", False),
38     ClientMethod("close", False),
39     ClientMethod("close_point_in_time", False),
40     ClientMethod("count", True),
41     ClientMethod("create", True),
42     ClientMethod("delete", True),
43     ClientMethod("delete_by_query", True),
44     ClientMethod("delete_by_query_rethrottle", False),
45     ClientMethod("delete_script", False),
46     ClientMethod("exists", True),
47     ClientMethod("exists_source", True),
48     ClientMethod("explain", True),
49     ClientMethod("field_caps", True),
50     ClientMethod("get", True),
51     ClientMethod("get_script", False),
52     ClientMethod("get_script_context", False),
53     ClientMethod("get_script_languages", False),
54     ClientMethod("get_source", True),
55     ClientMethod("index", True),
56     ClientMethod("info", False),
57     ClientMethod("mget", True),
58     ClientMethod("msearch", True),
59     ClientMethod("msearch_template", True),
60     ClientMethod("mtermvectors", True),
61     ClientMethod("open_point_in_time", True),
62     ClientMethod("ping", False),
63     ClientMethod("put_script", False),
64     ClientMethod("rank_eval", True),
65     ClientMethod("reindex", False),
66     ClientMethod("reindex_rethrottle", False),
67     ClientMethod("render_search_template", False),
68     ClientMethod("scripts_painless_execute", False),
69     ClientMethod("scroll", False),
70     ClientMethod("search", True),
71     ClientMethod("search_shards", True),
72     ClientMethod("search_template", True),
73     ClientMethod("termvectors", True),
74     ClientMethod("update", True),
75     ClientMethod("update_by_query", True),
76     ClientMethod("update_by_query_rethrottle", False),
77 ]
78 
79 
80 have_patched_client = False
81 
82 
83 def ensure_client_instrumented():
84     global have_patched_client
85 
86     if not have_patched_client:
87         for name, takes_index_argument in CLIENT_METHODS:
88             try:
89                 method = getattr(Elasticsearch, name)
90                 if takes_index_argument:
91                     wrapped = wrap_client_index_method(method)
92                 else:
93                     wrapped = wrap_client_method(method)
94                 setattr(Elasticsearch, name, wrapped)
95             except Exception as exc:
96                 logger.warning(
97                     "Failed to instrument elasticsearch.Elasticsearch.%s: %r",
98                     name,
99                     exc,
100                     exc_info=exc,
101                 )
102 
103         have_patched_client = True
104 
105 
106 @wrapt.decorator
107 def wrap_client_index_method(wrapped, instance, args, kwargs):
108     # elasticsearch-py 7.5.1 changed the order of arguments for client methods,
109     # so to be safe we need to inspect the wrapped method's positional
110     # arguments to see if we should pull it from there
111     if "index" in kwargs:
112         index = kwargs["index"]
113     else:
114         unwrapped = unwrap_decorators(wrapped)
115         pos_args = get_pos_args(unwrapped)
116         try:
117             index_index = pos_args.index("index")
118         except ValueError:  # pragma: no cover
119             # This guards against the method not accepting an 'index' argument
120             # but they all do - for now
121             index = ""
122         else:
123             try:
124                 index = args[index_index - 1]  # subtract 'self'
125             except IndexError:
126                 index = ""
127 
128     if isinstance(index, (list, tuple)):
129         index = ",".join(index)
130     if index == "":
131         index = "Unknown"
132     index = index.title()
133 
134     camel_name = "".join(c.title() for c in wrapped.__name__.split("_"))
135     operation = "Elasticsearch/{}/{}".format(index, camel_name)
136     tracked_request = TrackedRequest.instance()
137     with tracked_request.span(operation=operation, ignore_children=True):
138         return wrapped(*args, **kwargs)
139 
140 
141 @wrapt.decorator
142 def wrap_client_method(wrapped, instance, args, kwargs):
143     camel_name = "".join(c.title() for c in wrapped.__name__.split("_"))
144     operation = "Elasticsearch/{}".format(camel_name)
145     tracked_request = TrackedRequest.instance()
146     with tracked_request.span(operation=operation, ignore_children=True):
147         return wrapped(*args, **kwargs)
148 
149 
150 have_patched_transport = False
151 
152 
153 def ensure_transport_instrumented():
154     global have_patched_transport
155 
156     if not have_patched_transport:
157         try:
158             Transport.perform_request = wrapped_perform_request(
159                 Transport.perform_request
160             )
161         except Exception as exc:
162             logger.warning(
163                 "Failed to instrument elasticsearch.Transport.perform_request: %r",
164                 exc,
165                 exc_info=exc,
166             )
167 
168     have_patched_transport = True
169 
170 
171 def _sanitize_name(name):
172     try:
173         op = name.split("/")[-1]
174         op = op[1:]  # chop leading '_' from op
175         known_names = (
176             "bench",
177             "bulk",
178             "count",
179             "exists",
180             "explain",
181             "field_stats",
182             "health",
183             "mget",
184             "mlt",
185             "mpercolate",
186             "msearch",
187             "mtermvectors",
188             "percolate",
189             "query",
190             "scroll",
191             "search_shards",
192             "source",
193             "suggest",
194             "template",
195             "termvectors",
196             "update",
197             "search",
198         )
199         if op in known_names:
200             return op.title()
201         return "Unknown"
202     except Exception:
203         return "Unknown"
204 
205 
206 @wrapt.decorator
207 def wrapped_perform_request(wrapped, instance, args, kwargs):
208     try:
209         op = _sanitize_name(args[1])
210     except IndexError:
211         op = "Unknown"
212 
213     tracked_request = TrackedRequest.instance()
214     with tracked_request.span(
215         operation="Elasticsearch/{}".format(op),
216         ignore_children=True,
217     ):
218         return wrapped(*args, **kwargs)
219
```
--- 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/src/scout_apm/instruments/elasticsearch.py b/src/scout_apm/instruments/elasticsearch.py
--- a/src/scout_apm/instruments/elasticsearch.py
+++ b/src/scout_apm/instruments/elasticsearch.py
@@ -71,6 +71,7 @@
     ClientMethod("search_shards", True),
     ClientMethod("search_template", True),
     ClientMethod("termvectors", True),
+    ClientMethod("terms_enum", True),
     ClientMethod("update", True),
     ClientMethod("update_by_query", True),
     ClientMethod("update_by_query_rethrottle", False),

{"golden_diff": "diff --git a/src/scout_apm/instruments/elasticsearch.py b/src/scout_apm/instruments/elasticsearch.py\n--- a/src/scout_apm/instruments/elasticsearch.py\n+++ b/src/scout_apm/instruments/elasticsearch.py\n@@ -71,6 +71,7 @@\n     ClientMethod(\"search_shards\", True),\n     ClientMethod(\"search_template\", True),\n     ClientMethod(\"termvectors\", True),\n+    ClientMethod(\"terms_enum\", True),\n     ClientMethod(\"update\", True),\n     ClientMethod(\"update_by_query\", True),\n     ClientMethod(\"update_by_query_rethrottle\", False),\n", "issue": "Support ElasticSearch 7.14\nThe python package `elasticsearch-py` introduced the `terms_enum` parameter from ElasticSearch 7.14. This is currently not being instrumented and breaking tests.\n", "before_files": [{"content": "# coding=utf-8\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport logging\nfrom collections import namedtuple\n\nimport wrapt\n\nfrom scout_apm.compat import get_pos_args, unwrap_decorators\nfrom scout_apm.core.tracked_request import TrackedRequest\n\ntry:\n    from elasticsearch import Elasticsearch, Transport\nexcept ImportError:  # pragma: no cover\n    Elasticsearch = None\n    Transport = None\n\nlogger = logging.getLogger(__name__)\n\n\ndef ensure_installed():\n    logger.debug(\"Instrumenting elasticsearch.\")\n\n    if Elasticsearch is None:\n        logger.debug(\n            \"Couldn't import elasticsearch.Elasticsearch - probably not installed.\"\n        )\n    else:\n        ensure_client_instrumented()\n        ensure_transport_instrumented()\n\n\nClientMethod = namedtuple(\"ClientMethod\", [\"name\", \"takes_index_argument\"])\n\nCLIENT_METHODS = [\n    ClientMethod(\"bulk\", True),\n    ClientMethod(\"clear_scroll\", False),\n    ClientMethod(\"close\", False),\n    ClientMethod(\"close_point_in_time\", False),\n    ClientMethod(\"count\", True),\n    ClientMethod(\"create\", True),\n    ClientMethod(\"delete\", True),\n    ClientMethod(\"delete_by_query\", True),\n    ClientMethod(\"delete_by_query_rethrottle\", False),\n    ClientMethod(\"delete_script\", False),\n    ClientMethod(\"exists\", True),\n    ClientMethod(\"exists_source\", True),\n    ClientMethod(\"explain\", True),\n    ClientMethod(\"field_caps\", True),\n    ClientMethod(\"get\", True),\n    ClientMethod(\"get_script\", False),\n    ClientMethod(\"get_script_context\", False),\n    ClientMethod(\"get_script_languages\", False),\n    ClientMethod(\"get_source\", True),\n    ClientMethod(\"index\", True),\n    ClientMethod(\"info\", False),\n    ClientMethod(\"mget\", True),\n    ClientMethod(\"msearch\", True),\n    ClientMethod(\"msearch_template\", True),\n    ClientMethod(\"mtermvectors\", True),\n    ClientMethod(\"open_point_in_time\", True),\n    ClientMethod(\"ping\", False),\n    ClientMethod(\"put_script\", False),\n    ClientMethod(\"rank_eval\", True),\n    ClientMethod(\"reindex\", False),\n    ClientMethod(\"reindex_rethrottle\", False),\n    ClientMethod(\"render_search_template\", False),\n    ClientMethod(\"scripts_painless_execute\", False),\n    ClientMethod(\"scroll\", False),\n    ClientMethod(\"search\", True),\n    ClientMethod(\"search_shards\", True),\n    ClientMethod(\"search_template\", True),\n    ClientMethod(\"termvectors\", True),\n    ClientMethod(\"update\", True),\n    ClientMethod(\"update_by_query\", True),\n    ClientMethod(\"update_by_query_rethrottle\", False),\n]\n\n\nhave_patched_client = False\n\n\ndef ensure_client_instrumented():\n    global have_patched_client\n\n    if not have_patched_client:\n        for name, takes_index_argument in CLIENT_METHODS:\n            try:\n                method = getattr(Elasticsearch, name)\n                if takes_index_argument:\n                    wrapped = wrap_client_index_method(method)\n                else:\n                    wrapped = wrap_client_method(method)\n                setattr(Elasticsearch, name, wrapped)\n            except Exception as exc:\n                logger.warning(\n                    \"Failed to instrument elasticsearch.Elasticsearch.%s: %r\",\n                    name,\n                    exc,\n                    exc_info=exc,\n                )\n\n        have_patched_client = True\n\n\n@wrapt.decorator\ndef wrap_client_index_method(wrapped, instance, args, kwargs):\n    # elasticsearch-py 7.5.1 changed the order of arguments for client methods,\n    # so to be safe we need to inspect the wrapped method's positional\n    # arguments to see if we should pull it from there\n    if \"index\" in kwargs:\n        index = kwargs[\"index\"]\n    else:\n        unwrapped = unwrap_decorators(wrapped)\n        pos_args = get_pos_args(unwrapped)\n        try:\n            index_index = pos_args.index(\"index\")\n        except ValueError:  # pragma: no cover\n            # This guards against the method not accepting an 'index' argument\n            # but they all do - for now\n            index = \"\"\n        else:\n            try:\n                index = args[index_index - 1]  # subtract 'self'\n            except IndexError:\n                index = \"\"\n\n    if isinstance(index, (list, tuple)):\n        index = \",\".join(index)\n    if index == \"\":\n        index = \"Unknown\"\n    index = index.title()\n\n    camel_name = \"\".join(c.title() for c in wrapped.__name__.split(\"_\"))\n    operation = \"Elasticsearch/{}/{}\".format(index, camel_name)\n    tracked_request = TrackedRequest.instance()\n    with tracked_request.span(operation=operation, ignore_children=True):\n        return wrapped(*args, **kwargs)\n\n\n@wrapt.decorator\ndef wrap_client_method(wrapped, instance, args, kwargs):\n    camel_name = \"\".join(c.title() for c in wrapped.__name__.split(\"_\"))\n    operation = \"Elasticsearch/{}\".format(camel_name)\n    tracked_request = TrackedRequest.instance()\n    with tracked_request.span(operation=operation, ignore_children=True):\n        return wrapped(*args, **kwargs)\n\n\nhave_patched_transport = False\n\n\ndef ensure_transport_instrumented():\n    global have_patched_transport\n\n    if not have_patched_transport:\n        try:\n            Transport.perform_request = wrapped_perform_request(\n                Transport.perform_request\n            )\n        except Exception as exc:\n            logger.warning(\n                \"Failed to instrument elasticsearch.Transport.perform_request: %r\",\n                exc,\n                exc_info=exc,\n            )\n\n    have_patched_transport = True\n\n\ndef _sanitize_name(name):\n    try:\n        op = name.split(\"/\")[-1]\n        op = op[1:]  # chop leading '_' from op\n        known_names = (\n            \"bench\",\n            \"bulk\",\n            \"count\",\n            \"exists\",\n            \"explain\",\n            \"field_stats\",\n            \"health\",\n            \"mget\",\n            \"mlt\",\n            \"mpercolate\",\n            \"msearch\",\n            \"mtermvectors\",\n            \"percolate\",\n            \"query\",\n            \"scroll\",\n            \"search_shards\",\n            \"source\",\n            \"suggest\",\n            \"template\",\n            \"termvectors\",\n            \"update\",\n            \"search\",\n        )\n        if op in known_names:\n            return op.title()\n        return \"Unknown\"\n    except Exception:\n        return \"Unknown\"\n\n\n@wrapt.decorator\ndef wrapped_perform_request(wrapped, instance, args, kwargs):\n    try:\n        op = _sanitize_name(args[1])\n    except IndexError:\n        op = \"Unknown\"\n\n    tracked_request = TrackedRequest.instance()\n    with tracked_request.span(\n        operation=\"Elasticsearch/{}\".format(op),\n        ignore_children=True,\n    ):\n        return wrapped(*args, **kwargs)\n", "path": "src/scout_apm/instruments/elasticsearch.py"}], "after_files": [{"content": "# coding=utf-8\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport logging\nfrom collections import namedtuple\n\nimport wrapt\n\nfrom scout_apm.compat import get_pos_args, unwrap_decorators\nfrom scout_apm.core.tracked_request import TrackedRequest\n\ntry:\n    from elasticsearch import Elasticsearch, Transport\nexcept ImportError:  # pragma: no cover\n    Elasticsearch = None\n    Transport = None\n\nlogger = logging.getLogger(__name__)\n\n\ndef ensure_installed():\n    logger.debug(\"Instrumenting elasticsearch.\")\n\n    if Elasticsearch is None:\n        logger.debug(\n            \"Couldn't import elasticsearch.Elasticsearch - probably not installed.\"\n        )\n    else:\n        ensure_client_instrumented()\n        ensure_transport_instrumented()\n\n\nClientMethod = namedtuple(\"ClientMethod\", [\"name\", \"takes_index_argument\"])\n\nCLIENT_METHODS = [\n    ClientMethod(\"bulk\", True),\n    ClientMethod(\"clear_scroll\", False),\n    ClientMethod(\"close\", False),\n    ClientMethod(\"close_point_in_time\", False),\n    ClientMethod(\"count\", True),\n    ClientMethod(\"create\", True),\n    ClientMethod(\"delete\", True),\n    ClientMethod(\"delete_by_query\", True),\n    ClientMethod(\"delete_by_query_rethrottle\", False),\n    ClientMethod(\"delete_script\", False),\n    ClientMethod(\"exists\", True),\n    ClientMethod(\"exists_source\", True),\n    ClientMethod(\"explain\", True),\n    ClientMethod(\"field_caps\", True),\n    ClientMethod(\"get\", True),\n    ClientMethod(\"get_script\", False),\n    ClientMethod(\"get_script_context\", False),\n    ClientMethod(\"get_script_languages\", False),\n    ClientMethod(\"get_source\", True),\n    ClientMethod(\"index\", True),\n    ClientMethod(\"info\", False),\n    ClientMethod(\"mget\", True),\n    ClientMethod(\"msearch\", True),\n    ClientMethod(\"msearch_template\", True),\n    ClientMethod(\"mtermvectors\", True),\n    ClientMethod(\"open_point_in_time\", True),\n    ClientMethod(\"ping\", False),\n    ClientMethod(\"put_script\", False),\n    ClientMethod(\"rank_eval\", True),\n    ClientMethod(\"reindex\", False),\n    ClientMethod(\"reindex_rethrottle\", False),\n    ClientMethod(\"render_search_template\", False),\n    ClientMethod(\"scripts_painless_execute\", False),\n    ClientMethod(\"scroll\", False),\n    ClientMethod(\"search\", True),\n    ClientMethod(\"search_shards\", True),\n    ClientMethod(\"search_template\", True),\n    ClientMethod(\"termvectors\", True),\n    ClientMethod(\"terms_enum\", True),\n    ClientMethod(\"update\", True),\n    ClientMethod(\"update_by_query\", True),\n    ClientMethod(\"update_by_query_rethrottle\", False),\n]\n\n\nhave_patched_client = False\n\n\ndef ensure_client_instrumented():\n    global have_patched_client\n\n    if not have_patched_client:\n        for name, takes_index_argument in CLIENT_METHODS:\n            try:\n                method = getattr(Elasticsearch, name)\n                if takes_index_argument:\n                    wrapped = wrap_client_index_method(method)\n                else:\n                    wrapped = wrap_client_method(method)\n                setattr(Elasticsearch, name, wrapped)\n            except Exception as exc:\n                logger.warning(\n                    \"Failed to instrument elasticsearch.Elasticsearch.%s: %r\",\n                    name,\n                    exc,\n                    exc_info=exc,\n                )\n\n        have_patched_client = True\n\n\n@wrapt.decorator\ndef wrap_client_index_method(wrapped, instance, args, kwargs):\n    # elasticsearch-py 7.5.1 changed the order of arguments for client methods,\n    # so to be safe we need to inspect the wrapped method's positional\n    # arguments to see if we should pull it from there\n    if \"index\" in kwargs:\n        index = kwargs[\"index\"]\n    else:\n        unwrapped = unwrap_decorators(wrapped)\n        pos_args = get_pos_args(unwrapped)\n        try:\n            index_index = pos_args.index(\"index\")\n        except ValueError:  # pragma: no cover\n            # This guards against the method not accepting an 'index' argument\n            # but they all do - for now\n            index = \"\"\n        else:\n            try:\n                index = args[index_index - 1]  # subtract 'self'\n            except IndexError:\n                index = \"\"\n\n    if isinstance(index, (list, tuple)):\n        index = \",\".join(index)\n    if index == \"\":\n        index = \"Unknown\"\n    index = index.title()\n\n    camel_name = \"\".join(c.title() for c in wrapped.__name__.split(\"_\"))\n    operation = \"Elasticsearch/{}/{}\".format(index, camel_name)\n    tracked_request = TrackedRequest.instance()\n    with tracked_request.span(operation=operation, ignore_children=True):\n        return wrapped(*args, **kwargs)\n\n\n@wrapt.decorator\ndef wrap_client_method(wrapped, instance, args, kwargs):\n    camel_name = \"\".join(c.title() for c in wrapped.__name__.split(\"_\"))\n    operation = \"Elasticsearch/{}\".format(camel_name)\n    tracked_request = TrackedRequest.instance()\n    with tracked_request.span(operation=operation, ignore_children=True):\n        return wrapped(*args, **kwargs)\n\n\nhave_patched_transport = False\n\n\ndef ensure_transport_instrumented():\n    global have_patched_transport\n\n    if not have_patched_transport:\n        try:\n            Transport.perform_request = wrapped_perform_request(\n                Transport.perform_request\n            )\n        except Exception as exc:\n            logger.warning(\n                \"Failed to instrument elasticsearch.Transport.perform_request: %r\",\n                exc,\n                exc_info=exc,\n            )\n\n    have_patched_transport = True\n\n\ndef _sanitize_name(name):\n    try:\n        op = name.split(\"/\")[-1]\n        op = op[1:]  # chop leading '_' from op\n        known_names = (\n            \"bench\",\n            \"bulk\",\n            \"count\",\n            \"exists\",\n            \"explain\",\n            \"field_stats\",\n            \"health\",\n            \"mget\",\n            \"mlt\",\n            \"mpercolate\",\n            \"msearch\",\n            \"mtermvectors\",\n            \"percolate\",\n            \"query\",\n            \"scroll\",\n            \"search_shards\",\n            \"source\",\n            \"suggest\",\n            \"template\",\n            \"termvectors\",\n            \"update\",\n            \"search\",\n        )\n        if op in known_names:\n            return op.title()\n        return \"Unknown\"\n    except Exception:\n        return \"Unknown\"\n\n\n@wrapt.decorator\ndef wrapped_perform_request(wrapped, instance, args, kwargs):\n    try:\n        op = _sanitize_name(args[1])\n    except IndexError:\n        op = \"Unknown\"\n\n    tracked_request = TrackedRequest.instance()\n    with tracked_request.span(\n        operation=\"Elasticsearch/{}\".format(op),\n        ignore_children=True,\n    ):\n        return wrapped(*args, **kwargs)\n", "path": "src/scout_apm/instruments/elasticsearch.py"}]}