We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
opentelemetry-instrumentation-urllib


--- 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-urllib/src/opentelemetry/instrumentation/urllib/__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 """
17 This library allows tracing HTTP requests made by the
18 `urllib https://docs.python.org/3/library/urllib.html>`_ library.
19 
20 Usage
21 -----
22 
23 .. code-block:: python
24 
25     from urllib import request
26     from opentelemetry.instrumentation.urllib import URLLibInstrumentor
27 
28     # You can optionally pass a custom TracerProvider to
29     # URLLibInstrumentor().instrument()
30 
31     URLLibInstrumentor().instrument()
32     req = request.Request('https://postman-echo.com/post', method="POST")
33     r = request.urlopen(req)
34 
35 Configuration
36 -------------
37 
38 Request/Response hooks
39 **********************
40 
41 The urllib instrumentation supports extending tracing behavior with the help of
42 request and response hooks. These are functions that are called back by the instrumentation
43 right after a Span is created for a request and right before the span is finished processing a response respectively.
44 The hooks can be configured as follows:
45 
46 ..code:: python
47 
48     # `request_obj` is an instance of urllib.request.Request
49     def request_hook(span, request_obj):
50         pass
51 
52     # `request_obj` is an instance of urllib.request.Request
53     # `response` is an instance of http.client.HTTPResponse
54     def response_hook(span, request_obj, response)
55         pass
56 
57     URLLibInstrumentor.instrument(
58         request_hook=request_hook, response_hook=response_hook)
59     )
60 
61 API
62 ---
63 """
64 
65 import functools
66 import types
67 import typing
68 
69 # from urllib import response
70 from http import client
71 from typing import Collection
72 from urllib.request import (  # pylint: disable=no-name-in-module,import-error
73     OpenerDirector,
74     Request,
75 )
76 
77 from opentelemetry import context
78 from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
79 from opentelemetry.instrumentation.urllib.package import _instruments
80 from opentelemetry.instrumentation.urllib.version import __version__
81 from opentelemetry.instrumentation.utils import (
82     _SUPPRESS_INSTRUMENTATION_KEY,
83     http_status_to_status_code,
84 )
85 from opentelemetry.propagate import inject
86 from opentelemetry.semconv.trace import SpanAttributes
87 from opentelemetry.trace import Span, SpanKind, get_tracer
88 from opentelemetry.trace.status import Status
89 from opentelemetry.util.http import remove_url_credentials
90 
91 # A key to a context variable to avoid creating duplicate spans when instrumenting
92 # both, Session.request and Session.send, since Session.request calls into Session.send
93 _SUPPRESS_HTTP_INSTRUMENTATION_KEY = context.create_key(
94     "suppress_http_instrumentation"
95 )
96 
97 _RequestHookT = typing.Optional[typing.Callable[[Span, Request], None]]
98 _ResponseHookT = typing.Optional[
99     typing.Callable[[Span, Request, client.HTTPResponse], None]
100 ]
101 
102 
103 class URLLibInstrumentor(BaseInstrumentor):
104     """An instrumentor for urllib
105     See `BaseInstrumentor`
106     """
107 
108     def instrumentation_dependencies(self) -> Collection[str]:
109         return _instruments
110 
111     def _instrument(self, **kwargs):
112         """Instruments urllib module
113 
114         Args:
115             **kwargs: Optional arguments
116                 ``tracer_provider``: a TracerProvider, defaults to global
117                 ``request_hook``: An optional callback invoked that is invoked right after a span is created.
118                 ``response_hook``: An optional callback which is invoked right before the span is finished processing a response
119         """
120         tracer_provider = kwargs.get("tracer_provider")
121         tracer = get_tracer(__name__, __version__, tracer_provider)
122         _instrument(
123             tracer,
124             request_hook=kwargs.get("request_hook"),
125             response_hook=kwargs.get("response_hook"),
126         )
127 
128     def _uninstrument(self, **kwargs):
129         _uninstrument()
130 
131     def uninstrument_opener(
132         self, opener: OpenerDirector
133     ):  # pylint: disable=no-self-use
134         """uninstrument_opener a specific instance of urllib.request.OpenerDirector"""
135         _uninstrument_from(opener, restore_as_bound_func=True)
136 
137 
138 def _instrument(
139     tracer,
140     request_hook: _RequestHookT = None,
141     response_hook: _ResponseHookT = None,
142 ):
143     """Enables tracing of all requests calls that go through
144     :code:`urllib.Client._make_request`"""
145 
146     opener_open = OpenerDirector.open
147 
148     @functools.wraps(opener_open)
149     def instrumented_open(opener, fullurl, data=None, timeout=None):
150 
151         if isinstance(fullurl, str):
152             request_ = Request(fullurl, data)
153         else:
154             request_ = fullurl
155 
156         def get_or_create_headers():
157             return getattr(request_, "headers", {})
158 
159         def call_wrapped():
160             return opener_open(opener, request_, data=data, timeout=timeout)
161 
162         return _instrumented_open_call(
163             opener, request_, call_wrapped, get_or_create_headers
164         )
165 
166     def _instrumented_open_call(
167         _, request, call_wrapped, get_or_create_headers
168     ):  # pylint: disable=too-many-locals
169         if context.get_value(
170             _SUPPRESS_INSTRUMENTATION_KEY
171         ) or context.get_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY):
172             return call_wrapped()
173 
174         method = request.get_method().upper()
175         url = request.full_url
176 
177         span_name = f"HTTP {method}".strip()
178 
179         url = remove_url_credentials(url)
180 
181         labels = {
182             SpanAttributes.HTTP_METHOD: method,
183             SpanAttributes.HTTP_URL: url,
184         }
185 
186         with tracer.start_as_current_span(
187             span_name, kind=SpanKind.CLIENT
188         ) as span:
189             exception = None
190             if callable(request_hook):
191                 request_hook(span, request)
192             if span.is_recording():
193                 span.set_attribute(SpanAttributes.HTTP_METHOD, method)
194                 span.set_attribute(SpanAttributes.HTTP_URL, url)
195 
196             headers = get_or_create_headers()
197             inject(headers)
198 
199             token = context.attach(
200                 context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True)
201             )
202             try:
203                 result = call_wrapped()  # *** PROCEED
204             except Exception as exc:  # pylint: disable=W0703
205                 exception = exc
206                 result = getattr(exc, "file", None)
207             finally:
208                 context.detach(token)
209 
210             if result is not None:
211 
212                 code_ = result.getcode()
213                 labels[SpanAttributes.HTTP_STATUS_CODE] = str(code_)
214 
215                 if span.is_recording():
216                     span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, code_)
217                     span.set_status(Status(http_status_to_status_code(code_)))
218 
219                 ver_ = str(getattr(result, "version", ""))
220                 if ver_:
221                     labels[
222                         SpanAttributes.HTTP_FLAVOR
223                     ] = f"{ver_[:1]}.{ver_[:-1]}"
224 
225             if callable(response_hook):
226                 response_hook(span, request, result)
227 
228             if exception is not None:
229                 raise exception.with_traceback(exception.__traceback__)
230 
231         return result
232 
233     instrumented_open.opentelemetry_instrumentation_urllib_applied = True
234     OpenerDirector.open = instrumented_open
235 
236 
237 def _uninstrument():
238     """Disables instrumentation of :code:`urllib` through this module.
239 
240     Note that this only works if no other module also patches urllib."""
241     _uninstrument_from(OpenerDirector)
242 
243 
244 def _uninstrument_from(instr_root, restore_as_bound_func=False):
245 
246     instr_func_name = "open"
247     instr_func = getattr(instr_root, instr_func_name)
248     if not getattr(
249         instr_func,
250         "opentelemetry_instrumentation_urllib_applied",
251         False,
252     ):
253         return
254 
255     original = instr_func.__wrapped__  # pylint:disable=no-member
256     if restore_as_bound_func:
257         original = types.MethodType(original, instr_root)
258     setattr(instr_root, instr_func_name, original)
259
```
--- 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-urllib/src/opentelemetry/instrumentation/urllib/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py
--- a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py
+++ b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py
@@ -184,14 +184,11 @@
         }
 
         with tracer.start_as_current_span(
-            span_name, kind=SpanKind.CLIENT
+            span_name, kind=SpanKind.CLIENT, attributes=labels
         ) as span:
             exception = None
             if callable(request_hook):
                 request_hook(span, request)
-            if span.is_recording():
-                span.set_attribute(SpanAttributes.HTTP_METHOD, method)
-                span.set_attribute(SpanAttributes.HTTP_URL, url)
 
             headers = get_or_create_headers()
             inject(headers)

{"golden_diff": "diff --git a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py\n--- a/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py\n+++ b/instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py\n@@ -184,14 +184,11 @@\n         }\n \n         with tracer.start_as_current_span(\n-            span_name, kind=SpanKind.CLIENT\n+            span_name, kind=SpanKind.CLIENT, attributes=labels\n         ) as span:\n             exception = None\n             if callable(request_hook):\n                 request_hook(span, request)\n-            if span.is_recording():\n-                span.set_attribute(SpanAttributes.HTTP_METHOD, method)\n-                span.set_attribute(SpanAttributes.HTTP_URL, url)\n \n             headers = get_or_create_headers()\n             inject(headers)\n", "issue": "opentelemetry-instrumentation-urllib\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\n\"\"\"\nThis library allows tracing HTTP requests made by the\n`urllib https://docs.python.org/3/library/urllib.html>`_ library.\n\nUsage\n-----\n\n.. code-block:: python\n\n    from urllib import request\n    from opentelemetry.instrumentation.urllib import URLLibInstrumentor\n\n    # You can optionally pass a custom TracerProvider to\n    # URLLibInstrumentor().instrument()\n\n    URLLibInstrumentor().instrument()\n    req = request.Request('https://postman-echo.com/post', method=\"POST\")\n    r = request.urlopen(req)\n\nConfiguration\n-------------\n\nRequest/Response hooks\n**********************\n\nThe urllib instrumentation supports extending tracing behavior with the help of\nrequest and response hooks. These are functions that are called back by the instrumentation\nright after a Span is created for a request and right before the span is finished processing a response respectively.\nThe hooks can be configured as follows:\n\n..code:: python\n\n    # `request_obj` is an instance of urllib.request.Request\n    def request_hook(span, request_obj):\n        pass\n\n    # `request_obj` is an instance of urllib.request.Request\n    # `response` is an instance of http.client.HTTPResponse\n    def response_hook(span, request_obj, response)\n        pass\n\n    URLLibInstrumentor.instrument(\n        request_hook=request_hook, response_hook=response_hook)\n    )\n\nAPI\n---\n\"\"\"\n\nimport functools\nimport types\nimport typing\n\n# from urllib import response\nfrom http import client\nfrom typing import Collection\nfrom urllib.request import (  # pylint: disable=no-name-in-module,import-error\n    OpenerDirector,\n    Request,\n)\n\nfrom opentelemetry import context\nfrom opentelemetry.instrumentation.instrumentor import BaseInstrumentor\nfrom opentelemetry.instrumentation.urllib.package import _instruments\nfrom opentelemetry.instrumentation.urllib.version import __version__\nfrom opentelemetry.instrumentation.utils import (\n    _SUPPRESS_INSTRUMENTATION_KEY,\n    http_status_to_status_code,\n)\nfrom opentelemetry.propagate import inject\nfrom opentelemetry.semconv.trace import SpanAttributes\nfrom opentelemetry.trace import Span, SpanKind, get_tracer\nfrom opentelemetry.trace.status import Status\nfrom opentelemetry.util.http import remove_url_credentials\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_HTTP_INSTRUMENTATION_KEY = context.create_key(\n    \"suppress_http_instrumentation\"\n)\n\n_RequestHookT = typing.Optional[typing.Callable[[Span, Request], None]]\n_ResponseHookT = typing.Optional[\n    typing.Callable[[Span, Request, client.HTTPResponse], None]\n]\n\n\nclass URLLibInstrumentor(BaseInstrumentor):\n    \"\"\"An instrumentor for urllib\n    See `BaseInstrumentor`\n    \"\"\"\n\n    def instrumentation_dependencies(self) -> Collection[str]:\n        return _instruments\n\n    def _instrument(self, **kwargs):\n        \"\"\"Instruments urllib module\n\n        Args:\n            **kwargs: Optional arguments\n                ``tracer_provider``: a TracerProvider, defaults to global\n                ``request_hook``: An optional callback invoked that is invoked right after a span is created.\n                ``response_hook``: An optional callback which is invoked right before the span is finished processing a response\n        \"\"\"\n        tracer_provider = kwargs.get(\"tracer_provider\")\n        tracer = get_tracer(__name__, __version__, tracer_provider)\n        _instrument(\n            tracer,\n            request_hook=kwargs.get(\"request_hook\"),\n            response_hook=kwargs.get(\"response_hook\"),\n        )\n\n    def _uninstrument(self, **kwargs):\n        _uninstrument()\n\n    def uninstrument_opener(\n        self, opener: OpenerDirector\n    ):  # pylint: disable=no-self-use\n        \"\"\"uninstrument_opener a specific instance of urllib.request.OpenerDirector\"\"\"\n        _uninstrument_from(opener, restore_as_bound_func=True)\n\n\ndef _instrument(\n    tracer,\n    request_hook: _RequestHookT = None,\n    response_hook: _ResponseHookT = None,\n):\n    \"\"\"Enables tracing of all requests calls that go through\n    :code:`urllib.Client._make_request`\"\"\"\n\n    opener_open = OpenerDirector.open\n\n    @functools.wraps(opener_open)\n    def instrumented_open(opener, fullurl, data=None, timeout=None):\n\n        if isinstance(fullurl, str):\n            request_ = Request(fullurl, data)\n        else:\n            request_ = fullurl\n\n        def get_or_create_headers():\n            return getattr(request_, \"headers\", {})\n\n        def call_wrapped():\n            return opener_open(opener, request_, data=data, timeout=timeout)\n\n        return _instrumented_open_call(\n            opener, request_, call_wrapped, get_or_create_headers\n        )\n\n    def _instrumented_open_call(\n        _, request, call_wrapped, get_or_create_headers\n    ):  # pylint: disable=too-many-locals\n        if context.get_value(\n            _SUPPRESS_INSTRUMENTATION_KEY\n        ) or context.get_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY):\n            return call_wrapped()\n\n        method = request.get_method().upper()\n        url = request.full_url\n\n        span_name = f\"HTTP {method}\".strip()\n\n        url = remove_url_credentials(url)\n\n        labels = {\n            SpanAttributes.HTTP_METHOD: method,\n            SpanAttributes.HTTP_URL: url,\n        }\n\n        with tracer.start_as_current_span(\n            span_name, kind=SpanKind.CLIENT\n        ) as span:\n            exception = None\n            if callable(request_hook):\n                request_hook(span, request)\n            if span.is_recording():\n                span.set_attribute(SpanAttributes.HTTP_METHOD, method)\n                span.set_attribute(SpanAttributes.HTTP_URL, url)\n\n            headers = get_or_create_headers()\n            inject(headers)\n\n            token = context.attach(\n                context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True)\n            )\n            try:\n                result = call_wrapped()  # *** PROCEED\n            except Exception as exc:  # pylint: disable=W0703\n                exception = exc\n                result = getattr(exc, \"file\", None)\n            finally:\n                context.detach(token)\n\n            if result is not None:\n\n                code_ = result.getcode()\n                labels[SpanAttributes.HTTP_STATUS_CODE] = str(code_)\n\n                if span.is_recording():\n                    span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, code_)\n                    span.set_status(Status(http_status_to_status_code(code_)))\n\n                ver_ = str(getattr(result, \"version\", \"\"))\n                if ver_:\n                    labels[\n                        SpanAttributes.HTTP_FLAVOR\n                    ] = f\"{ver_[:1]}.{ver_[:-1]}\"\n\n            if callable(response_hook):\n                response_hook(span, request, result)\n\n            if exception is not None:\n                raise exception.with_traceback(exception.__traceback__)\n\n        return result\n\n    instrumented_open.opentelemetry_instrumentation_urllib_applied = True\n    OpenerDirector.open = instrumented_open\n\n\ndef _uninstrument():\n    \"\"\"Disables instrumentation of :code:`urllib` through this module.\n\n    Note that this only works if no other module also patches urllib.\"\"\"\n    _uninstrument_from(OpenerDirector)\n\n\ndef _uninstrument_from(instr_root, restore_as_bound_func=False):\n\n    instr_func_name = \"open\"\n    instr_func = getattr(instr_root, instr_func_name)\n    if not getattr(\n        instr_func,\n        \"opentelemetry_instrumentation_urllib_applied\",\n        False,\n    ):\n        return\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", "path": "instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__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\n\"\"\"\nThis library allows tracing HTTP requests made by the\n`urllib https://docs.python.org/3/library/urllib.html>`_ library.\n\nUsage\n-----\n\n.. code-block:: python\n\n    from urllib import request\n    from opentelemetry.instrumentation.urllib import URLLibInstrumentor\n\n    # You can optionally pass a custom TracerProvider to\n    # URLLibInstrumentor().instrument()\n\n    URLLibInstrumentor().instrument()\n    req = request.Request('https://postman-echo.com/post', method=\"POST\")\n    r = request.urlopen(req)\n\nConfiguration\n-------------\n\nRequest/Response hooks\n**********************\n\nThe urllib instrumentation supports extending tracing behavior with the help of\nrequest and response hooks. These are functions that are called back by the instrumentation\nright after a Span is created for a request and right before the span is finished processing a response respectively.\nThe hooks can be configured as follows:\n\n..code:: python\n\n    # `request_obj` is an instance of urllib.request.Request\n    def request_hook(span, request_obj):\n        pass\n\n    # `request_obj` is an instance of urllib.request.Request\n    # `response` is an instance of http.client.HTTPResponse\n    def response_hook(span, request_obj, response)\n        pass\n\n    URLLibInstrumentor.instrument(\n        request_hook=request_hook, response_hook=response_hook)\n    )\n\nAPI\n---\n\"\"\"\n\nimport functools\nimport types\nimport typing\n\n# from urllib import response\nfrom http import client\nfrom typing import Collection\nfrom urllib.request import (  # pylint: disable=no-name-in-module,import-error\n    OpenerDirector,\n    Request,\n)\n\nfrom opentelemetry import context\nfrom opentelemetry.instrumentation.instrumentor import BaseInstrumentor\nfrom opentelemetry.instrumentation.urllib.package import _instruments\nfrom opentelemetry.instrumentation.urllib.version import __version__\nfrom opentelemetry.instrumentation.utils import (\n    _SUPPRESS_INSTRUMENTATION_KEY,\n    http_status_to_status_code,\n)\nfrom opentelemetry.propagate import inject\nfrom opentelemetry.semconv.trace import SpanAttributes\nfrom opentelemetry.trace import Span, SpanKind, get_tracer\nfrom opentelemetry.trace.status import Status\nfrom opentelemetry.util.http import remove_url_credentials\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_HTTP_INSTRUMENTATION_KEY = context.create_key(\n    \"suppress_http_instrumentation\"\n)\n\n_RequestHookT = typing.Optional[typing.Callable[[Span, Request], None]]\n_ResponseHookT = typing.Optional[\n    typing.Callable[[Span, Request, client.HTTPResponse], None]\n]\n\n\nclass URLLibInstrumentor(BaseInstrumentor):\n    \"\"\"An instrumentor for urllib\n    See `BaseInstrumentor`\n    \"\"\"\n\n    def instrumentation_dependencies(self) -> Collection[str]:\n        return _instruments\n\n    def _instrument(self, **kwargs):\n        \"\"\"Instruments urllib module\n\n        Args:\n            **kwargs: Optional arguments\n                ``tracer_provider``: a TracerProvider, defaults to global\n                ``request_hook``: An optional callback invoked that is invoked right after a span is created.\n                ``response_hook``: An optional callback which is invoked right before the span is finished processing a response\n        \"\"\"\n        tracer_provider = kwargs.get(\"tracer_provider\")\n        tracer = get_tracer(__name__, __version__, tracer_provider)\n        _instrument(\n            tracer,\n            request_hook=kwargs.get(\"request_hook\"),\n            response_hook=kwargs.get(\"response_hook\"),\n        )\n\n    def _uninstrument(self, **kwargs):\n        _uninstrument()\n\n    def uninstrument_opener(\n        self, opener: OpenerDirector\n    ):  # pylint: disable=no-self-use\n        \"\"\"uninstrument_opener a specific instance of urllib.request.OpenerDirector\"\"\"\n        _uninstrument_from(opener, restore_as_bound_func=True)\n\n\ndef _instrument(\n    tracer,\n    request_hook: _RequestHookT = None,\n    response_hook: _ResponseHookT = None,\n):\n    \"\"\"Enables tracing of all requests calls that go through\n    :code:`urllib.Client._make_request`\"\"\"\n\n    opener_open = OpenerDirector.open\n\n    @functools.wraps(opener_open)\n    def instrumented_open(opener, fullurl, data=None, timeout=None):\n\n        if isinstance(fullurl, str):\n            request_ = Request(fullurl, data)\n        else:\n            request_ = fullurl\n\n        def get_or_create_headers():\n            return getattr(request_, \"headers\", {})\n\n        def call_wrapped():\n            return opener_open(opener, request_, data=data, timeout=timeout)\n\n        return _instrumented_open_call(\n            opener, request_, call_wrapped, get_or_create_headers\n        )\n\n    def _instrumented_open_call(\n        _, request, call_wrapped, get_or_create_headers\n    ):  # pylint: disable=too-many-locals\n        if context.get_value(\n            _SUPPRESS_INSTRUMENTATION_KEY\n        ) or context.get_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY):\n            return call_wrapped()\n\n        method = request.get_method().upper()\n        url = request.full_url\n\n        span_name = f\"HTTP {method}\".strip()\n\n        url = remove_url_credentials(url)\n\n        labels = {\n            SpanAttributes.HTTP_METHOD: method,\n            SpanAttributes.HTTP_URL: url,\n        }\n\n        with tracer.start_as_current_span(\n            span_name, kind=SpanKind.CLIENT, attributes=labels\n        ) as span:\n            exception = None\n            if callable(request_hook):\n                request_hook(span, request)\n\n            headers = get_or_create_headers()\n            inject(headers)\n\n            token = context.attach(\n                context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True)\n            )\n            try:\n                result = call_wrapped()  # *** PROCEED\n            except Exception as exc:  # pylint: disable=W0703\n                exception = exc\n                result = getattr(exc, \"file\", None)\n            finally:\n                context.detach(token)\n\n            if result is not None:\n\n                code_ = result.getcode()\n                labels[SpanAttributes.HTTP_STATUS_CODE] = str(code_)\n\n                if span.is_recording():\n                    span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, code_)\n                    span.set_status(Status(http_status_to_status_code(code_)))\n\n                ver_ = str(getattr(result, \"version\", \"\"))\n                if ver_:\n                    labels[\n                        SpanAttributes.HTTP_FLAVOR\n                    ] = f\"{ver_[:1]}.{ver_[:-1]}\"\n\n            if callable(response_hook):\n                response_hook(span, request, result)\n\n            if exception is not None:\n                raise exception.with_traceback(exception.__traceback__)\n\n        return result\n\n    instrumented_open.opentelemetry_instrumentation_urllib_applied = True\n    OpenerDirector.open = instrumented_open\n\n\ndef _uninstrument():\n    \"\"\"Disables instrumentation of :code:`urllib` through this module.\n\n    Note that this only works if no other module also patches urllib.\"\"\"\n    _uninstrument_from(OpenerDirector)\n\n\ndef _uninstrument_from(instr_root, restore_as_bound_func=False):\n\n    instr_func_name = \"open\"\n    instr_func = getattr(instr_root, instr_func_name)\n    if not getattr(\n        instr_func,\n        \"opentelemetry_instrumentation_urllib_applied\",\n        False,\n    ):\n        return\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", "path": "instrumentation/opentelemetry-instrumentation-urllib/src/opentelemetry/instrumentation/urllib/__init__.py"}]}