We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
wsgi: set error status on span
The wsgi instrumentation does not set an error status if an exception is caught while handling a request:

https://github.com/open-telemetry/opentelemetry-python/blob/master/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py#L212

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__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 provides a WSGI middleware that can be used on any WSGI framework
17 (such as Django / Flask) to track requests timing through OpenTelemetry.
18 
19 Usage (Flask)
20 -------------
21 
22 .. code-block:: python
23 
24     from flask import Flask
25     from opentelemetry.ext.wsgi import OpenTelemetryMiddleware
26 
27     app = Flask(__name__)
28     app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app)
29 
30     @app.route("/")
31     def hello():
32         return "Hello!"
33 
34     if __name__ == "__main__":
35         app.run(debug=True)
36 
37 
38 Usage (Django)
39 --------------
40 
41 Modify the application's ``wsgi.py`` file as shown below.
42 
43 .. code-block:: python
44 
45     import os
46     from opentelemetry.ext.wsgi import OpenTelemetryMiddleware
47     from django.core.wsgi import get_wsgi_application
48 
49     os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
50 
51     application = get_wsgi_application()
52     application = OpenTelemetryMiddleware(application)
53 
54 API
55 ---
56 """
57 
58 import functools
59 import typing
60 import wsgiref.util as wsgiref_util
61 
62 from opentelemetry import context, propagators, trace
63 from opentelemetry.ext.wsgi.version import __version__
64 from opentelemetry.instrumentation.utils import http_status_to_canonical_code
65 from opentelemetry.trace.status import Status, StatusCanonicalCode
66 
67 _HTTP_VERSION_PREFIX = "HTTP/"
68 
69 
70 def get_header_from_environ(
71     environ: dict, header_name: str
72 ) -> typing.List[str]:
73     """Retrieve a HTTP header value from the PEP3333-conforming WSGI environ.
74 
75     Returns:
76         A list with a single string with the header value if it exists, else an empty list.
77     """
78     environ_key = "HTTP_" + header_name.upper().replace("-", "_")
79     value = environ.get(environ_key)
80     if value is not None:
81         return [value]
82     return []
83 
84 
85 def setifnotnone(dic, key, value):
86     if value is not None:
87         dic[key] = value
88 
89 
90 def collect_request_attributes(environ):
91     """Collects HTTP request attributes from the PEP3333-conforming
92     WSGI environ and returns a dictionary to be used as span creation attributes."""
93 
94     result = {
95         "component": "http",
96         "http.method": environ.get("REQUEST_METHOD"),
97         "http.server_name": environ.get("SERVER_NAME"),
98         "http.scheme": environ.get("wsgi.url_scheme"),
99     }
100 
101     host_port = environ.get("SERVER_PORT")
102     if host_port is not None:
103         result.update({"host.port": int(host_port)})
104 
105     setifnotnone(result, "http.host", environ.get("HTTP_HOST"))
106     target = environ.get("RAW_URI")
107     if target is None:  # Note: `"" or None is None`
108         target = environ.get("REQUEST_URI")
109     if target is not None:
110         result["http.target"] = target
111     else:
112         result["http.url"] = wsgiref_util.request_uri(environ)
113 
114     remote_addr = environ.get("REMOTE_ADDR")
115     if remote_addr:
116         result["net.peer.ip"] = remote_addr
117     remote_host = environ.get("REMOTE_HOST")
118     if remote_host and remote_host != remote_addr:
119         result["net.peer.name"] = remote_host
120 
121     setifnotnone(result, "net.peer.port", environ.get("REMOTE_PORT"))
122     flavor = environ.get("SERVER_PROTOCOL", "")
123     if flavor.upper().startswith(_HTTP_VERSION_PREFIX):
124         flavor = flavor[len(_HTTP_VERSION_PREFIX) :]
125     if flavor:
126         result["http.flavor"] = flavor
127 
128     return result
129 
130 
131 def add_response_attributes(
132     span, start_response_status, response_headers
133 ):  # pylint: disable=unused-argument
134     """Adds HTTP response attributes to span using the arguments
135     passed to a PEP3333-conforming start_response callable."""
136 
137     status_code, status_text = start_response_status.split(" ", 1)
138     span.set_attribute("http.status_text", status_text)
139 
140     try:
141         status_code = int(status_code)
142     except ValueError:
143         span.set_status(
144             Status(
145                 StatusCanonicalCode.UNKNOWN,
146                 "Non-integer HTTP status: " + repr(status_code),
147             )
148         )
149     else:
150         span.set_attribute("http.status_code", status_code)
151         span.set_status(Status(http_status_to_canonical_code(status_code)))
152 
153 
154 def get_default_span_name(environ):
155     """Default implementation for name_callback, returns HTTP {METHOD_NAME}."""
156     return "HTTP {}".format(environ.get("REQUEST_METHOD", "")).strip()
157 
158 
159 class OpenTelemetryMiddleware:
160     """The WSGI application middleware.
161 
162     This class is a PEP 3333 conforming WSGI middleware that starts and
163     annotates spans for any requests it is invoked with.
164 
165     Args:
166         wsgi: The WSGI application callable to forward requests to.
167         name_callback: Callback which calculates a generic span name for an
168                        incoming HTTP request based on the PEP3333 WSGI environ.
169                        Optional: Defaults to get_default_span_name.
170     """
171 
172     def __init__(self, wsgi, name_callback=get_default_span_name):
173         self.wsgi = wsgi
174         self.tracer = trace.get_tracer(__name__, __version__)
175         self.name_callback = name_callback
176 
177     @staticmethod
178     def _create_start_response(span, start_response):
179         @functools.wraps(start_response)
180         def _start_response(status, response_headers, *args, **kwargs):
181             add_response_attributes(span, status, response_headers)
182             return start_response(status, response_headers, *args, **kwargs)
183 
184         return _start_response
185 
186     def __call__(self, environ, start_response):
187         """The WSGI application
188 
189         Args:
190             environ: A WSGI environment.
191             start_response: The WSGI start_response callable.
192         """
193 
194         token = context.attach(
195             propagators.extract(get_header_from_environ, environ)
196         )
197         span_name = self.name_callback(environ)
198 
199         span = self.tracer.start_span(
200             span_name,
201             kind=trace.SpanKind.SERVER,
202             attributes=collect_request_attributes(environ),
203         )
204 
205         try:
206             with self.tracer.use_span(span):
207                 start_response = self._create_start_response(
208                     span, start_response
209                 )
210                 iterable = self.wsgi(environ, start_response)
211                 return _end_span_after_iterating(
212                     iterable, span, self.tracer, token
213                 )
214         except:  # noqa
215             # TODO Set span status (cf. https://github.com/open-telemetry/opentelemetry-python/issues/292)
216             span.end()
217             context.detach(token)
218             raise
219 
220 
221 # Put this in a subfunction to not delay the call to the wrapped
222 # WSGI application (instrumentation should change the application
223 # behavior as little as possible).
224 def _end_span_after_iterating(iterable, span, tracer, token):
225     try:
226         with tracer.use_span(span):
227             for yielded in iterable:
228                 yield yielded
229     finally:
230         close = getattr(iterable, "close", None)
231         if close:
232             close()
233         span.end()
234         context.detach(token)
235
```
--- 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/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py b/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py
--- a/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py
+++ b/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py
@@ -11,7 +11,6 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-
 """
 This library provides a WSGI middleware that can be used on any WSGI framework
 (such as Django / Flask) to track requests timing through OpenTelemetry.
@@ -211,8 +210,8 @@
                 return _end_span_after_iterating(
                     iterable, span, self.tracer, token
                 )
-        except:  # noqa
-            # TODO Set span status (cf. https://github.com/open-telemetry/opentelemetry-python/issues/292)
+        except Exception as ex:
+            span.set_status(Status(StatusCanonicalCode.INTERNAL, str(ex)))
             span.end()
             context.detach(token)
             raise

{"golden_diff": "diff --git a/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py b/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py\n--- a/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py\n+++ b/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py\n@@ -11,7 +11,6 @@\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 This library provides a WSGI middleware that can be used on any WSGI framework\n (such as Django / Flask) to track requests timing through OpenTelemetry.\n@@ -211,8 +210,8 @@\n                 return _end_span_after_iterating(\n                     iterable, span, self.tracer, token\n                 )\n-        except:  # noqa\n-            # TODO Set span status (cf. https://github.com/open-telemetry/opentelemetry-python/issues/292)\n+        except Exception as ex:\n+            span.set_status(Status(StatusCanonicalCode.INTERNAL, str(ex)))\n             span.end()\n             context.detach(token)\n             raise\n", "issue": "wsgi: set error status on span\nThe wsgi instrumentation does not set an error status if an exception is caught while handling a request:\r\n\r\nhttps://github.com/open-telemetry/opentelemetry-python/blob/master/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py#L212\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 provides a WSGI middleware that can be used on any WSGI framework\n(such as Django / Flask) to track requests timing through OpenTelemetry.\n\nUsage (Flask)\n-------------\n\n.. code-block:: python\n\n    from flask import Flask\n    from opentelemetry.ext.wsgi import OpenTelemetryMiddleware\n\n    app = Flask(__name__)\n    app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app)\n\n    @app.route(\"/\")\n    def hello():\n        return \"Hello!\"\n\n    if __name__ == \"__main__\":\n        app.run(debug=True)\n\n\nUsage (Django)\n--------------\n\nModify the application's ``wsgi.py`` file as shown below.\n\n.. code-block:: python\n\n    import os\n    from opentelemetry.ext.wsgi import OpenTelemetryMiddleware\n    from django.core.wsgi import get_wsgi_application\n\n    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')\n\n    application = get_wsgi_application()\n    application = OpenTelemetryMiddleware(application)\n\nAPI\n---\n\"\"\"\n\nimport functools\nimport typing\nimport wsgiref.util as wsgiref_util\n\nfrom opentelemetry import context, propagators, trace\nfrom opentelemetry.ext.wsgi.version import __version__\nfrom opentelemetry.instrumentation.utils import http_status_to_canonical_code\nfrom opentelemetry.trace.status import Status, StatusCanonicalCode\n\n_HTTP_VERSION_PREFIX = \"HTTP/\"\n\n\ndef get_header_from_environ(\n    environ: dict, header_name: str\n) -> typing.List[str]:\n    \"\"\"Retrieve a HTTP header value from the PEP3333-conforming WSGI environ.\n\n    Returns:\n        A list with a single string with the header value if it exists, else an empty list.\n    \"\"\"\n    environ_key = \"HTTP_\" + header_name.upper().replace(\"-\", \"_\")\n    value = environ.get(environ_key)\n    if value is not None:\n        return [value]\n    return []\n\n\ndef setifnotnone(dic, key, value):\n    if value is not None:\n        dic[key] = value\n\n\ndef collect_request_attributes(environ):\n    \"\"\"Collects HTTP request attributes from the PEP3333-conforming\n    WSGI environ and returns a dictionary to be used as span creation attributes.\"\"\"\n\n    result = {\n        \"component\": \"http\",\n        \"http.method\": environ.get(\"REQUEST_METHOD\"),\n        \"http.server_name\": environ.get(\"SERVER_NAME\"),\n        \"http.scheme\": environ.get(\"wsgi.url_scheme\"),\n    }\n\n    host_port = environ.get(\"SERVER_PORT\")\n    if host_port is not None:\n        result.update({\"host.port\": int(host_port)})\n\n    setifnotnone(result, \"http.host\", environ.get(\"HTTP_HOST\"))\n    target = environ.get(\"RAW_URI\")\n    if target is None:  # Note: `\"\" or None is None`\n        target = environ.get(\"REQUEST_URI\")\n    if target is not None:\n        result[\"http.target\"] = target\n    else:\n        result[\"http.url\"] = wsgiref_util.request_uri(environ)\n\n    remote_addr = environ.get(\"REMOTE_ADDR\")\n    if remote_addr:\n        result[\"net.peer.ip\"] = remote_addr\n    remote_host = environ.get(\"REMOTE_HOST\")\n    if remote_host and remote_host != remote_addr:\n        result[\"net.peer.name\"] = remote_host\n\n    setifnotnone(result, \"net.peer.port\", environ.get(\"REMOTE_PORT\"))\n    flavor = environ.get(\"SERVER_PROTOCOL\", \"\")\n    if flavor.upper().startswith(_HTTP_VERSION_PREFIX):\n        flavor = flavor[len(_HTTP_VERSION_PREFIX) :]\n    if flavor:\n        result[\"http.flavor\"] = flavor\n\n    return result\n\n\ndef add_response_attributes(\n    span, start_response_status, response_headers\n):  # pylint: disable=unused-argument\n    \"\"\"Adds HTTP response attributes to span using the arguments\n    passed to a PEP3333-conforming start_response callable.\"\"\"\n\n    status_code, status_text = start_response_status.split(\" \", 1)\n    span.set_attribute(\"http.status_text\", status_text)\n\n    try:\n        status_code = int(status_code)\n    except ValueError:\n        span.set_status(\n            Status(\n                StatusCanonicalCode.UNKNOWN,\n                \"Non-integer HTTP status: \" + repr(status_code),\n            )\n        )\n    else:\n        span.set_attribute(\"http.status_code\", status_code)\n        span.set_status(Status(http_status_to_canonical_code(status_code)))\n\n\ndef get_default_span_name(environ):\n    \"\"\"Default implementation for name_callback, returns HTTP {METHOD_NAME}.\"\"\"\n    return \"HTTP {}\".format(environ.get(\"REQUEST_METHOD\", \"\")).strip()\n\n\nclass OpenTelemetryMiddleware:\n    \"\"\"The WSGI application middleware.\n\n    This class is a PEP 3333 conforming WSGI middleware that starts and\n    annotates spans for any requests it is invoked with.\n\n    Args:\n        wsgi: The WSGI application callable to forward requests to.\n        name_callback: Callback which calculates a generic span name for an\n                       incoming HTTP request based on the PEP3333 WSGI environ.\n                       Optional: Defaults to get_default_span_name.\n    \"\"\"\n\n    def __init__(self, wsgi, name_callback=get_default_span_name):\n        self.wsgi = wsgi\n        self.tracer = trace.get_tracer(__name__, __version__)\n        self.name_callback = name_callback\n\n    @staticmethod\n    def _create_start_response(span, start_response):\n        @functools.wraps(start_response)\n        def _start_response(status, response_headers, *args, **kwargs):\n            add_response_attributes(span, status, response_headers)\n            return start_response(status, response_headers, *args, **kwargs)\n\n        return _start_response\n\n    def __call__(self, environ, start_response):\n        \"\"\"The WSGI application\n\n        Args:\n            environ: A WSGI environment.\n            start_response: The WSGI start_response callable.\n        \"\"\"\n\n        token = context.attach(\n            propagators.extract(get_header_from_environ, environ)\n        )\n        span_name = self.name_callback(environ)\n\n        span = self.tracer.start_span(\n            span_name,\n            kind=trace.SpanKind.SERVER,\n            attributes=collect_request_attributes(environ),\n        )\n\n        try:\n            with self.tracer.use_span(span):\n                start_response = self._create_start_response(\n                    span, start_response\n                )\n                iterable = self.wsgi(environ, start_response)\n                return _end_span_after_iterating(\n                    iterable, span, self.tracer, token\n                )\n        except:  # noqa\n            # TODO Set span status (cf. https://github.com/open-telemetry/opentelemetry-python/issues/292)\n            span.end()\n            context.detach(token)\n            raise\n\n\n# Put this in a subfunction to not delay the call to the wrapped\n# WSGI application (instrumentation should change the application\n# behavior as little as possible).\ndef _end_span_after_iterating(iterable, span, tracer, token):\n    try:\n        with tracer.use_span(span):\n            for yielded in iterable:\n                yield yielded\n    finally:\n        close = getattr(iterable, \"close\", None)\n        if close:\n            close()\n        span.end()\n        context.detach(token)\n", "path": "ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__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\"\"\"\nThis library provides a WSGI middleware that can be used on any WSGI framework\n(such as Django / Flask) to track requests timing through OpenTelemetry.\n\nUsage (Flask)\n-------------\n\n.. code-block:: python\n\n    from flask import Flask\n    from opentelemetry.ext.wsgi import OpenTelemetryMiddleware\n\n    app = Flask(__name__)\n    app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app)\n\n    @app.route(\"/\")\n    def hello():\n        return \"Hello!\"\n\n    if __name__ == \"__main__\":\n        app.run(debug=True)\n\n\nUsage (Django)\n--------------\n\nModify the application's ``wsgi.py`` file as shown below.\n\n.. code-block:: python\n\n    import os\n    from opentelemetry.ext.wsgi import OpenTelemetryMiddleware\n    from django.core.wsgi import get_wsgi_application\n\n    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')\n\n    application = get_wsgi_application()\n    application = OpenTelemetryMiddleware(application)\n\nAPI\n---\n\"\"\"\n\nimport functools\nimport typing\nimport wsgiref.util as wsgiref_util\n\nfrom opentelemetry import context, propagators, trace\nfrom opentelemetry.ext.wsgi.version import __version__\nfrom opentelemetry.instrumentation.utils import http_status_to_canonical_code\nfrom opentelemetry.trace.status import Status, StatusCanonicalCode\n\n_HTTP_VERSION_PREFIX = \"HTTP/\"\n\n\ndef get_header_from_environ(\n    environ: dict, header_name: str\n) -> typing.List[str]:\n    \"\"\"Retrieve a HTTP header value from the PEP3333-conforming WSGI environ.\n\n    Returns:\n        A list with a single string with the header value if it exists, else an empty list.\n    \"\"\"\n    environ_key = \"HTTP_\" + header_name.upper().replace(\"-\", \"_\")\n    value = environ.get(environ_key)\n    if value is not None:\n        return [value]\n    return []\n\n\ndef setifnotnone(dic, key, value):\n    if value is not None:\n        dic[key] = value\n\n\ndef collect_request_attributes(environ):\n    \"\"\"Collects HTTP request attributes from the PEP3333-conforming\n    WSGI environ and returns a dictionary to be used as span creation attributes.\"\"\"\n\n    result = {\n        \"component\": \"http\",\n        \"http.method\": environ.get(\"REQUEST_METHOD\"),\n        \"http.server_name\": environ.get(\"SERVER_NAME\"),\n        \"http.scheme\": environ.get(\"wsgi.url_scheme\"),\n    }\n\n    host_port = environ.get(\"SERVER_PORT\")\n    if host_port is not None:\n        result.update({\"host.port\": int(host_port)})\n\n    setifnotnone(result, \"http.host\", environ.get(\"HTTP_HOST\"))\n    target = environ.get(\"RAW_URI\")\n    if target is None:  # Note: `\"\" or None is None`\n        target = environ.get(\"REQUEST_URI\")\n    if target is not None:\n        result[\"http.target\"] = target\n    else:\n        result[\"http.url\"] = wsgiref_util.request_uri(environ)\n\n    remote_addr = environ.get(\"REMOTE_ADDR\")\n    if remote_addr:\n        result[\"net.peer.ip\"] = remote_addr\n    remote_host = environ.get(\"REMOTE_HOST\")\n    if remote_host and remote_host != remote_addr:\n        result[\"net.peer.name\"] = remote_host\n\n    setifnotnone(result, \"net.peer.port\", environ.get(\"REMOTE_PORT\"))\n    flavor = environ.get(\"SERVER_PROTOCOL\", \"\")\n    if flavor.upper().startswith(_HTTP_VERSION_PREFIX):\n        flavor = flavor[len(_HTTP_VERSION_PREFIX) :]\n    if flavor:\n        result[\"http.flavor\"] = flavor\n\n    return result\n\n\ndef add_response_attributes(\n    span, start_response_status, response_headers\n):  # pylint: disable=unused-argument\n    \"\"\"Adds HTTP response attributes to span using the arguments\n    passed to a PEP3333-conforming start_response callable.\"\"\"\n\n    status_code, status_text = start_response_status.split(\" \", 1)\n    span.set_attribute(\"http.status_text\", status_text)\n\n    try:\n        status_code = int(status_code)\n    except ValueError:\n        span.set_status(\n            Status(\n                StatusCanonicalCode.UNKNOWN,\n                \"Non-integer HTTP status: \" + repr(status_code),\n            )\n        )\n    else:\n        span.set_attribute(\"http.status_code\", status_code)\n        span.set_status(Status(http_status_to_canonical_code(status_code)))\n\n\ndef get_default_span_name(environ):\n    \"\"\"Default implementation for name_callback, returns HTTP {METHOD_NAME}.\"\"\"\n    return \"HTTP {}\".format(environ.get(\"REQUEST_METHOD\", \"\")).strip()\n\n\nclass OpenTelemetryMiddleware:\n    \"\"\"The WSGI application middleware.\n\n    This class is a PEP 3333 conforming WSGI middleware that starts and\n    annotates spans for any requests it is invoked with.\n\n    Args:\n        wsgi: The WSGI application callable to forward requests to.\n        name_callback: Callback which calculates a generic span name for an\n                       incoming HTTP request based on the PEP3333 WSGI environ.\n                       Optional: Defaults to get_default_span_name.\n    \"\"\"\n\n    def __init__(self, wsgi, name_callback=get_default_span_name):\n        self.wsgi = wsgi\n        self.tracer = trace.get_tracer(__name__, __version__)\n        self.name_callback = name_callback\n\n    @staticmethod\n    def _create_start_response(span, start_response):\n        @functools.wraps(start_response)\n        def _start_response(status, response_headers, *args, **kwargs):\n            add_response_attributes(span, status, response_headers)\n            return start_response(status, response_headers, *args, **kwargs)\n\n        return _start_response\n\n    def __call__(self, environ, start_response):\n        \"\"\"The WSGI application\n\n        Args:\n            environ: A WSGI environment.\n            start_response: The WSGI start_response callable.\n        \"\"\"\n\n        token = context.attach(\n            propagators.extract(get_header_from_environ, environ)\n        )\n        span_name = self.name_callback(environ)\n\n        span = self.tracer.start_span(\n            span_name,\n            kind=trace.SpanKind.SERVER,\n            attributes=collect_request_attributes(environ),\n        )\n\n        try:\n            with self.tracer.use_span(span):\n                start_response = self._create_start_response(\n                    span, start_response\n                )\n                iterable = self.wsgi(environ, start_response)\n                return _end_span_after_iterating(\n                    iterable, span, self.tracer, token\n                )\n        except Exception as ex:\n            span.set_status(Status(StatusCanonicalCode.INTERNAL, str(ex)))\n            span.end()\n            context.detach(token)\n            raise\n\n\n# Put this in a subfunction to not delay the call to the wrapped\n# WSGI application (instrumentation should change the application\n# behavior as little as possible).\ndef _end_span_after_iterating(iterable, span, tracer, token):\n    try:\n        with tracer.use_span(span):\n            for yielded in iterable:\n                yield yielded\n    finally:\n        close = getattr(iterable, \"close\", None)\n        if close:\n            close()\n        span.end()\n        context.detach(token)\n", "path": "ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py"}]}