We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Allow to modify the computed Span name via callback.
# Description

With Redis and Databases in a traces, there is no easy way from the span name to see if a "SELECT" is going to Redis or the database.


## Type of change

Please delete options that are not relevant.

- [X] New feature (non-breaking change which adds functionality)

# How Has This Been Tested?

- [X] TestRedis::test_name_callback

# Does This PR Require a Core Repo Change?

- [ ] Yes. - Link to PR: 
- [X] No.

# Checklist:

See [contributing.md](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/CONTRIBUTING.md) for styleguide, changelog guidelines, and more.

- [?] Followed the style guidelines of this project
- [X] Changelogs have been updated
- [X] Unit tests have been added
- [X] Documentation has been updated


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py`
Content:
```
1 # Copyright The OpenTelemetry Authors
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 """
16 This library allows tracing HTTP requests made by the
17 `requests <https://requests.readthedocs.io/en/master/>`_ library.
18 
19 Usage
20 -----
21 
22 .. code-block:: python
23 
24     import requests
25     import opentelemetry.instrumentation.requests
26 
27     # You can optionally pass a custom TracerProvider to
28     # RequestInstrumentor.instrument()
29     opentelemetry.instrumentation.requests.RequestsInstrumentor().instrument()
30     response = requests.get(url="https://www.example.org/")
31 
32 API
33 ---
34 """
35 
36 import functools
37 import types
38 
39 from requests import Timeout, URLRequired
40 from requests.exceptions import InvalidSchema, InvalidURL, MissingSchema
41 from requests.sessions import Session
42 from requests.structures import CaseInsensitiveDict
43 
44 from opentelemetry import context, propagators
45 from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
46 from opentelemetry.instrumentation.metric import (
47     HTTPMetricRecorder,
48     HTTPMetricType,
49     MetricMixin,
50 )
51 from opentelemetry.instrumentation.requests.version import __version__
52 from opentelemetry.instrumentation.utils import http_status_to_status_code
53 from opentelemetry.trace import SpanKind, get_tracer
54 from opentelemetry.trace.status import Status, StatusCode
55 
56 # A key to a context variable to avoid creating duplicate spans when instrumenting
57 # both, Session.request and Session.send, since Session.request calls into Session.send
58 _SUPPRESS_REQUESTS_INSTRUMENTATION_KEY = "suppress_requests_instrumentation"
59 
60 
61 # pylint: disable=unused-argument
62 # pylint: disable=R0915
63 def _instrument(tracer_provider=None, span_callback=None, name_callback=None):
64     """Enables tracing of all requests calls that go through
65     :code:`requests.session.Session.request` (this includes
66     :code:`requests.get`, etc.)."""
67 
68     # Since
69     # https://github.com/psf/requests/commit/d72d1162142d1bf8b1b5711c664fbbd674f349d1
70     # (v0.7.0, Oct 23, 2011), get, post, etc are implemented via request which
71     # again, is implemented via Session.request (`Session` was named `session`
72     # before v1.0.0, Dec 17, 2012, see
73     # https://github.com/psf/requests/commit/4e5c4a6ab7bb0195dececdd19bb8505b872fe120)
74 
75     wrapped_request = Session.request
76     wrapped_send = Session.send
77 
78     @functools.wraps(wrapped_request)
79     def instrumented_request(self, method, url, *args, **kwargs):
80         def get_or_create_headers():
81             headers = kwargs.get("headers")
82             if headers is None:
83                 headers = {}
84                 kwargs["headers"] = headers
85 
86             return headers
87 
88         def call_wrapped():
89             return wrapped_request(self, method, url, *args, **kwargs)
90 
91         return _instrumented_requests_call(
92             method, url, call_wrapped, get_or_create_headers
93         )
94 
95     @functools.wraps(wrapped_send)
96     def instrumented_send(self, request, **kwargs):
97         def get_or_create_headers():
98             request.headers = (
99                 request.headers
100                 if request.headers is not None
101                 else CaseInsensitiveDict()
102             )
103             return request.headers
104 
105         def call_wrapped():
106             return wrapped_send(self, request, **kwargs)
107 
108         return _instrumented_requests_call(
109             request.method, request.url, call_wrapped, get_or_create_headers
110         )
111 
112     def _instrumented_requests_call(
113         method: str, url: str, call_wrapped, get_or_create_headers
114     ):
115         if context.get_value("suppress_instrumentation") or context.get_value(
116             _SUPPRESS_REQUESTS_INSTRUMENTATION_KEY
117         ):
118             return call_wrapped()
119 
120         # See
121         # https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#http-client
122         method = method.upper()
123         span_name = ""
124         if name_callback is not None:
125             span_name = name_callback()
126         if not span_name or not isinstance(span_name, str):
127             span_name = get_default_span_name(method)
128 
129         recorder = RequestsInstrumentor().metric_recorder
130 
131         labels = {}
132         labels["http.method"] = method
133         labels["http.url"] = url
134 
135         with get_tracer(
136             __name__, __version__, tracer_provider
137         ).start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
138             exception = None
139             with recorder.record_client_duration(labels):
140                 if span.is_recording():
141                     span.set_attribute("component", "http")
142                     span.set_attribute("http.method", method)
143                     span.set_attribute("http.url", url)
144 
145                 headers = get_or_create_headers()
146                 propagators.inject(type(headers).__setitem__, headers)
147 
148                 token = context.attach(
149                     context.set_value(
150                         _SUPPRESS_REQUESTS_INSTRUMENTATION_KEY, True
151                     )
152                 )
153                 try:
154                     result = call_wrapped()  # *** PROCEED
155                 except Exception as exc:  # pylint: disable=W0703
156                     exception = exc
157                     result = getattr(exc, "response", None)
158                 finally:
159                     context.detach(token)
160 
161                 if result is not None:
162                     if span.is_recording():
163                         span.set_attribute(
164                             "http.status_code", result.status_code
165                         )
166                         span.set_attribute("http.status_text", result.reason)
167                         span.set_status(
168                             Status(
169                                 http_status_to_status_code(result.status_code)
170                             )
171                         )
172                     labels["http.status_code"] = str(result.status_code)
173                     if result.raw and result.raw.version:
174                         labels["http.flavor"] = (
175                             str(result.raw.version)[:1]
176                             + "."
177                             + str(result.raw.version)[:-1]
178                         )
179                 if span_callback is not None:
180                     span_callback(span, result)
181 
182             if exception is not None:
183                 raise exception.with_traceback(exception.__traceback__)
184 
185         return result
186 
187     instrumented_request.opentelemetry_instrumentation_requests_applied = True
188     Session.request = instrumented_request
189 
190     instrumented_send.opentelemetry_instrumentation_requests_applied = True
191     Session.send = instrumented_send
192 
193 
194 def _uninstrument():
195     """Disables instrumentation of :code:`requests` through this module.
196 
197     Note that this only works if no other module also patches requests."""
198     _uninstrument_from(Session)
199 
200 
201 def _uninstrument_from(instr_root, restore_as_bound_func=False):
202     for instr_func_name in ("request", "send"):
203         instr_func = getattr(instr_root, instr_func_name)
204         if not getattr(
205             instr_func,
206             "opentelemetry_instrumentation_requests_applied",
207             False,
208         ):
209             continue
210 
211         original = instr_func.__wrapped__  # pylint:disable=no-member
212         if restore_as_bound_func:
213             original = types.MethodType(original, instr_root)
214         setattr(instr_root, instr_func_name, original)
215 
216 
217 def get_default_span_name(method):
218     """Default implementation for name_callback, returns HTTP {method_name}."""
219     return "HTTP {}".format(method).strip()
220 
221 
222 class RequestsInstrumentor(BaseInstrumentor, MetricMixin):
223     """An instrumentor for requests
224     See `BaseInstrumentor`
225     """
226 
227     def _instrument(self, **kwargs):
228         """Instruments requests module
229 
230         Args:
231             **kwargs: Optional arguments
232                 ``tracer_provider``: a TracerProvider, defaults to global
233                 ``span_callback``: An optional callback invoked before returning the http response. Invoked with Span and requests.Response
234                 ``name_callback``: Callback which calculates a generic span name for an
235                     outgoing HTTP request based on the method and url.
236                     Optional: Defaults to get_default_span_name.
237         """
238         _instrument(
239             tracer_provider=kwargs.get("tracer_provider"),
240             span_callback=kwargs.get("span_callback"),
241             name_callback=kwargs.get("name_callback"),
242         )
243         self.init_metrics(
244             __name__, __version__,
245         )
246         # pylint: disable=W0201
247         self.metric_recorder = HTTPMetricRecorder(
248             self.meter, HTTPMetricType.CLIENT
249         )
250 
251     def _uninstrument(self, **kwargs):
252         _uninstrument()
253 
254     @staticmethod
255     def uninstrument_session(session):
256         """Disables instrumentation on the session object."""
257         _uninstrument_from(session, restore_as_bound_func=True)
258
```
--- 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/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py
--- a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py
+++ b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py
@@ -25,7 +25,7 @@
     import opentelemetry.instrumentation.requests
 
     # You can optionally pass a custom TracerProvider to
-    # RequestInstrumentor.instrument()
+    # RequestsInstrumentor.instrument()
     opentelemetry.instrumentation.requests.RequestsInstrumentor().instrument()
     response = requests.get(url="https://www.example.org/")

{"golden_diff": "diff --git a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py\n--- a/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py\n+++ b/instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py\n@@ -25,7 +25,7 @@\n     import opentelemetry.instrumentation.requests\n \n     # You can optionally pass a custom TracerProvider to\n-    # RequestInstrumentor.instrument()\n+    # RequestsInstrumentor.instrument()\n     opentelemetry.instrumentation.requests.RequestsInstrumentor().instrument()\n     response = requests.get(url=\"https://www.example.org/\")\n", "issue": "Allow to modify the computed Span name via callback.\n# Description\r\n\r\nWith Redis and Databases in a traces, there is no easy way from the span name to see if a \"SELECT\" is going to Redis or the database.\r\n\r\n\r\n## Type of change\r\n\r\nPlease delete options that are not relevant.\r\n\r\n- [X] New feature (non-breaking change which adds functionality)\r\n\r\n# How Has This Been Tested?\r\n\r\n- [X] TestRedis::test_name_callback\r\n\r\n# Does This PR Require a Core Repo Change?\r\n\r\n- [ ] Yes. - Link to PR: \r\n- [X] No.\r\n\r\n# Checklist:\r\n\r\nSee [contributing.md](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/CONTRIBUTING.md) for styleguide, changelog guidelines, and more.\r\n\r\n- [?] Followed the style guidelines of this project\r\n- [X] Changelogs have been updated\r\n- [X] Unit tests have been added\r\n- [X] Documentation has been updated\r\n\n", "before_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nThis library allows tracing HTTP requests made by the\n`requests <https://requests.readthedocs.io/en/master/>`_ library.\n\nUsage\n-----\n\n.. code-block:: python\n\n    import requests\n    import opentelemetry.instrumentation.requests\n\n    # You can optionally pass a custom TracerProvider to\n    # RequestInstrumentor.instrument()\n    opentelemetry.instrumentation.requests.RequestsInstrumentor().instrument()\n    response = requests.get(url=\"https://www.example.org/\")\n\nAPI\n---\n\"\"\"\n\nimport functools\nimport types\n\nfrom requests import Timeout, URLRequired\nfrom requests.exceptions import InvalidSchema, InvalidURL, MissingSchema\nfrom requests.sessions import Session\nfrom requests.structures import CaseInsensitiveDict\n\nfrom opentelemetry import context, propagators\nfrom opentelemetry.instrumentation.instrumentor import BaseInstrumentor\nfrom opentelemetry.instrumentation.metric import (\n    HTTPMetricRecorder,\n    HTTPMetricType,\n    MetricMixin,\n)\nfrom opentelemetry.instrumentation.requests.version import __version__\nfrom opentelemetry.instrumentation.utils import http_status_to_status_code\nfrom opentelemetry.trace import SpanKind, get_tracer\nfrom opentelemetry.trace.status import Status, StatusCode\n\n# A key to a context variable to avoid creating duplicate spans when instrumenting\n# both, Session.request and Session.send, since Session.request calls into Session.send\n_SUPPRESS_REQUESTS_INSTRUMENTATION_KEY = \"suppress_requests_instrumentation\"\n\n\n# pylint: disable=unused-argument\n# pylint: disable=R0915\ndef _instrument(tracer_provider=None, span_callback=None, name_callback=None):\n    \"\"\"Enables tracing of all requests calls that go through\n    :code:`requests.session.Session.request` (this includes\n    :code:`requests.get`, etc.).\"\"\"\n\n    # Since\n    # https://github.com/psf/requests/commit/d72d1162142d1bf8b1b5711c664fbbd674f349d1\n    # (v0.7.0, Oct 23, 2011), get, post, etc are implemented via request which\n    # again, is implemented via Session.request (`Session` was named `session`\n    # before v1.0.0, Dec 17, 2012, see\n    # https://github.com/psf/requests/commit/4e5c4a6ab7bb0195dececdd19bb8505b872fe120)\n\n    wrapped_request = Session.request\n    wrapped_send = Session.send\n\n    @functools.wraps(wrapped_request)\n    def instrumented_request(self, method, url, *args, **kwargs):\n        def get_or_create_headers():\n            headers = kwargs.get(\"headers\")\n            if headers is None:\n                headers = {}\n                kwargs[\"headers\"] = headers\n\n            return headers\n\n        def call_wrapped():\n            return wrapped_request(self, method, url, *args, **kwargs)\n\n        return _instrumented_requests_call(\n            method, url, call_wrapped, get_or_create_headers\n        )\n\n    @functools.wraps(wrapped_send)\n    def instrumented_send(self, request, **kwargs):\n        def get_or_create_headers():\n            request.headers = (\n                request.headers\n                if request.headers is not None\n                else CaseInsensitiveDict()\n            )\n            return request.headers\n\n        def call_wrapped():\n            return wrapped_send(self, request, **kwargs)\n\n        return _instrumented_requests_call(\n            request.method, request.url, call_wrapped, get_or_create_headers\n        )\n\n    def _instrumented_requests_call(\n        method: str, url: str, call_wrapped, get_or_create_headers\n    ):\n        if context.get_value(\"suppress_instrumentation\") or context.get_value(\n            _SUPPRESS_REQUESTS_INSTRUMENTATION_KEY\n        ):\n            return call_wrapped()\n\n        # See\n        # https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#http-client\n        method = method.upper()\n        span_name = \"\"\n        if name_callback is not None:\n            span_name = name_callback()\n        if not span_name or not isinstance(span_name, str):\n            span_name = get_default_span_name(method)\n\n        recorder = RequestsInstrumentor().metric_recorder\n\n        labels = {}\n        labels[\"http.method\"] = method\n        labels[\"http.url\"] = url\n\n        with get_tracer(\n            __name__, __version__, tracer_provider\n        ).start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:\n            exception = None\n            with recorder.record_client_duration(labels):\n                if span.is_recording():\n                    span.set_attribute(\"component\", \"http\")\n                    span.set_attribute(\"http.method\", method)\n                    span.set_attribute(\"http.url\", url)\n\n                headers = get_or_create_headers()\n                propagators.inject(type(headers).__setitem__, headers)\n\n                token = context.attach(\n                    context.set_value(\n                        _SUPPRESS_REQUESTS_INSTRUMENTATION_KEY, True\n                    )\n                )\n                try:\n                    result = call_wrapped()  # *** PROCEED\n                except Exception as exc:  # pylint: disable=W0703\n                    exception = exc\n                    result = getattr(exc, \"response\", None)\n                finally:\n                    context.detach(token)\n\n                if result is not None:\n                    if span.is_recording():\n                        span.set_attribute(\n                            \"http.status_code\", result.status_code\n                        )\n                        span.set_attribute(\"http.status_text\", result.reason)\n                        span.set_status(\n                            Status(\n                                http_status_to_status_code(result.status_code)\n                            )\n                        )\n                    labels[\"http.status_code\"] = str(result.status_code)\n                    if result.raw and result.raw.version:\n                        labels[\"http.flavor\"] = (\n                            str(result.raw.version)[:1]\n                            + \".\"\n                            + str(result.raw.version)[:-1]\n                        )\n                if span_callback is not None:\n                    span_callback(span, result)\n\n            if exception is not None:\n                raise exception.with_traceback(exception.__traceback__)\n\n        return result\n\n    instrumented_request.opentelemetry_instrumentation_requests_applied = True\n    Session.request = instrumented_request\n\n    instrumented_send.opentelemetry_instrumentation_requests_applied = True\n    Session.send = instrumented_send\n\n\ndef _uninstrument():\n    \"\"\"Disables instrumentation of :code:`requests` through this module.\n\n    Note that this only works if no other module also patches requests.\"\"\"\n    _uninstrument_from(Session)\n\n\ndef _uninstrument_from(instr_root, restore_as_bound_func=False):\n    for instr_func_name in (\"request\", \"send\"):\n        instr_func = getattr(instr_root, instr_func_name)\n        if not getattr(\n            instr_func,\n            \"opentelemetry_instrumentation_requests_applied\",\n            False,\n        ):\n            continue\n\n        original = instr_func.__wrapped__  # pylint:disable=no-member\n        if restore_as_bound_func:\n            original = types.MethodType(original, instr_root)\n        setattr(instr_root, instr_func_name, original)\n\n\ndef get_default_span_name(method):\n    \"\"\"Default implementation for name_callback, returns HTTP {method_name}.\"\"\"\n    return \"HTTP {}\".format(method).strip()\n\n\nclass RequestsInstrumentor(BaseInstrumentor, MetricMixin):\n    \"\"\"An instrumentor for requests\n    See `BaseInstrumentor`\n    \"\"\"\n\n    def _instrument(self, **kwargs):\n        \"\"\"Instruments requests module\n\n        Args:\n            **kwargs: Optional arguments\n                ``tracer_provider``: a TracerProvider, defaults to global\n                ``span_callback``: An optional callback invoked before returning the http response. Invoked with Span and requests.Response\n                ``name_callback``: Callback which calculates a generic span name for an\n                    outgoing HTTP request based on the method and url.\n                    Optional: Defaults to get_default_span_name.\n        \"\"\"\n        _instrument(\n            tracer_provider=kwargs.get(\"tracer_provider\"),\n            span_callback=kwargs.get(\"span_callback\"),\n            name_callback=kwargs.get(\"name_callback\"),\n        )\n        self.init_metrics(\n            __name__, __version__,\n        )\n        # pylint: disable=W0201\n        self.metric_recorder = HTTPMetricRecorder(\n            self.meter, HTTPMetricType.CLIENT\n        )\n\n    def _uninstrument(self, **kwargs):\n        _uninstrument()\n\n    @staticmethod\n    def uninstrument_session(session):\n        \"\"\"Disables instrumentation on the session object.\"\"\"\n        _uninstrument_from(session, restore_as_bound_func=True)\n", "path": "instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py"}], "after_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nThis library allows tracing HTTP requests made by the\n`requests <https://requests.readthedocs.io/en/master/>`_ library.\n\nUsage\n-----\n\n.. code-block:: python\n\n    import requests\n    import opentelemetry.instrumentation.requests\n\n    # You can optionally pass a custom TracerProvider to\n    # RequestsInstrumentor.instrument()\n    opentelemetry.instrumentation.requests.RequestsInstrumentor().instrument()\n    response = requests.get(url=\"https://www.example.org/\")\n\nAPI\n---\n\"\"\"\n\nimport functools\nimport types\n\nfrom requests import Timeout, URLRequired\nfrom requests.exceptions import InvalidSchema, InvalidURL, MissingSchema\nfrom requests.sessions import Session\nfrom requests.structures import CaseInsensitiveDict\n\nfrom opentelemetry import context, propagators\nfrom opentelemetry.instrumentation.instrumentor import BaseInstrumentor\nfrom opentelemetry.instrumentation.metric import (\n    HTTPMetricRecorder,\n    HTTPMetricType,\n    MetricMixin,\n)\nfrom opentelemetry.instrumentation.requests.version import __version__\nfrom opentelemetry.instrumentation.utils import http_status_to_status_code\nfrom opentelemetry.trace import SpanKind, get_tracer\nfrom opentelemetry.trace.status import Status, StatusCode\n\n# A key to a context variable to avoid creating duplicate spans when instrumenting\n# both, Session.request and Session.send, since Session.request calls into Session.send\n_SUPPRESS_REQUESTS_INSTRUMENTATION_KEY = \"suppress_requests_instrumentation\"\n\n\n# pylint: disable=unused-argument\n# pylint: disable=R0915\ndef _instrument(tracer_provider=None, span_callback=None, name_callback=None):\n    \"\"\"Enables tracing of all requests calls that go through\n    :code:`requests.session.Session.request` (this includes\n    :code:`requests.get`, etc.).\"\"\"\n\n    # Since\n    # https://github.com/psf/requests/commit/d72d1162142d1bf8b1b5711c664fbbd674f349d1\n    # (v0.7.0, Oct 23, 2011), get, post, etc are implemented via request which\n    # again, is implemented via Session.request (`Session` was named `session`\n    # before v1.0.0, Dec 17, 2012, see\n    # https://github.com/psf/requests/commit/4e5c4a6ab7bb0195dececdd19bb8505b872fe120)\n\n    wrapped_request = Session.request\n    wrapped_send = Session.send\n\n    @functools.wraps(wrapped_request)\n    def instrumented_request(self, method, url, *args, **kwargs):\n        def get_or_create_headers():\n            headers = kwargs.get(\"headers\")\n            if headers is None:\n                headers = {}\n                kwargs[\"headers\"] = headers\n\n            return headers\n\n        def call_wrapped():\n            return wrapped_request(self, method, url, *args, **kwargs)\n\n        return _instrumented_requests_call(\n            method, url, call_wrapped, get_or_create_headers\n        )\n\n    @functools.wraps(wrapped_send)\n    def instrumented_send(self, request, **kwargs):\n        def get_or_create_headers():\n            request.headers = (\n                request.headers\n                if request.headers is not None\n                else CaseInsensitiveDict()\n            )\n            return request.headers\n\n        def call_wrapped():\n            return wrapped_send(self, request, **kwargs)\n\n        return _instrumented_requests_call(\n            request.method, request.url, call_wrapped, get_or_create_headers\n        )\n\n    def _instrumented_requests_call(\n        method: str, url: str, call_wrapped, get_or_create_headers\n    ):\n        if context.get_value(\"suppress_instrumentation\") or context.get_value(\n            _SUPPRESS_REQUESTS_INSTRUMENTATION_KEY\n        ):\n            return call_wrapped()\n\n        # See\n        # https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#http-client\n        method = method.upper()\n        span_name = \"\"\n        if name_callback is not None:\n            span_name = name_callback()\n        if not span_name or not isinstance(span_name, str):\n            span_name = get_default_span_name(method)\n\n        recorder = RequestsInstrumentor().metric_recorder\n\n        labels = {}\n        labels[\"http.method\"] = method\n        labels[\"http.url\"] = url\n\n        with get_tracer(\n            __name__, __version__, tracer_provider\n        ).start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:\n            exception = None\n            with recorder.record_client_duration(labels):\n                if span.is_recording():\n                    span.set_attribute(\"component\", \"http\")\n                    span.set_attribute(\"http.method\", method)\n                    span.set_attribute(\"http.url\", url)\n\n                headers = get_or_create_headers()\n                propagators.inject(type(headers).__setitem__, headers)\n\n                token = context.attach(\n                    context.set_value(\n                        _SUPPRESS_REQUESTS_INSTRUMENTATION_KEY, True\n                    )\n                )\n                try:\n                    result = call_wrapped()  # *** PROCEED\n                except Exception as exc:  # pylint: disable=W0703\n                    exception = exc\n                    result = getattr(exc, \"response\", None)\n                finally:\n                    context.detach(token)\n\n                if result is not None:\n                    if span.is_recording():\n                        span.set_attribute(\n                            \"http.status_code\", result.status_code\n                        )\n                        span.set_attribute(\"http.status_text\", result.reason)\n                        span.set_status(\n                            Status(\n                                http_status_to_status_code(result.status_code)\n                            )\n                        )\n                    labels[\"http.status_code\"] = str(result.status_code)\n                    if result.raw and result.raw.version:\n                        labels[\"http.flavor\"] = (\n                            str(result.raw.version)[:1]\n                            + \".\"\n                            + str(result.raw.version)[:-1]\n                        )\n                if span_callback is not None:\n                    span_callback(span, result)\n\n            if exception is not None:\n                raise exception.with_traceback(exception.__traceback__)\n\n        return result\n\n    instrumented_request.opentelemetry_instrumentation_requests_applied = True\n    Session.request = instrumented_request\n\n    instrumented_send.opentelemetry_instrumentation_requests_applied = True\n    Session.send = instrumented_send\n\n\ndef _uninstrument():\n    \"\"\"Disables instrumentation of :code:`requests` through this module.\n\n    Note that this only works if no other module also patches requests.\"\"\"\n    _uninstrument_from(Session)\n\n\ndef _uninstrument_from(instr_root, restore_as_bound_func=False):\n    for instr_func_name in (\"request\", \"send\"):\n        instr_func = getattr(instr_root, instr_func_name)\n        if not getattr(\n            instr_func,\n            \"opentelemetry_instrumentation_requests_applied\",\n            False,\n        ):\n            continue\n\n        original = instr_func.__wrapped__  # pylint:disable=no-member\n        if restore_as_bound_func:\n            original = types.MethodType(original, instr_root)\n        setattr(instr_root, instr_func_name, original)\n\n\ndef get_default_span_name(method):\n    \"\"\"Default implementation for name_callback, returns HTTP {method_name}.\"\"\"\n    return \"HTTP {}\".format(method).strip()\n\n\nclass RequestsInstrumentor(BaseInstrumentor, MetricMixin):\n    \"\"\"An instrumentor for requests\n    See `BaseInstrumentor`\n    \"\"\"\n\n    def _instrument(self, **kwargs):\n        \"\"\"Instruments requests module\n\n        Args:\n            **kwargs: Optional arguments\n                ``tracer_provider``: a TracerProvider, defaults to global\n                ``span_callback``: An optional callback invoked before returning the http response. Invoked with Span and requests.Response\n                ``name_callback``: Callback which calculates a generic span name for an\n                    outgoing HTTP request based on the method and url.\n                    Optional: Defaults to get_default_span_name.\n        \"\"\"\n        _instrument(\n            tracer_provider=kwargs.get(\"tracer_provider\"),\n            span_callback=kwargs.get(\"span_callback\"),\n            name_callback=kwargs.get(\"name_callback\"),\n        )\n        self.init_metrics(\n            __name__, __version__,\n        )\n        # pylint: disable=W0201\n        self.metric_recorder = HTTPMetricRecorder(\n            self.meter, HTTPMetricType.CLIENT\n        )\n\n    def _uninstrument(self, **kwargs):\n        _uninstrument()\n\n    @staticmethod\n    def uninstrument_session(session):\n        \"\"\"Disables instrumentation on the session object.\"\"\"\n        _uninstrument_from(session, restore_as_bound_func=True)\n", "path": "instrumentation/opentelemetry-instrumentation-requests/src/opentelemetry/instrumentation/requests/__init__.py"}]}