We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add readthedocs documentation tortoiseorm instrumentation
Part of [1491](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1491)

--- 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-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__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 Instrument `tortoise-orm`_ to report SQL queries.
17 
18 Usage
19 -----
20 
21 .. code:: python
22 
23     from fastapi import FastAPI
24     from tortoise.contrib.fastapi import register_tortoise
25     from opentelemetry.sdk.resources import SERVICE_NAME, Resource
26     from opentelemetry.sdk.trace import TracerProvider
27     from opentelemetry.instrumentation.tortoiseorm import TortoiseORMInstrumentor
28 
29     app = FastAPI()
30     tracer = TracerProvider(resource=Resource({SERVICE_NAME: "FastAPI"}))
31     TortoiseORMInstrumentor().instrument(tracer_provider=tracer)
32 
33     register_tortoise(
34         app,
35         db_url="sqlite://sample.db",
36         modules={"models": ["example_app.db_models"]}
37     )
38 
39 API
40 ---
41 """
42 from typing import Collection
43 
44 import wrapt
45 
46 from opentelemetry import trace
47 from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
48 from opentelemetry.instrumentation.tortoiseorm.package import _instruments
49 from opentelemetry.instrumentation.tortoiseorm.version import __version__
50 from opentelemetry.instrumentation.utils import unwrap
51 from opentelemetry.semconv.trace import DbSystemValues, SpanAttributes
52 from opentelemetry.trace import SpanKind
53 from opentelemetry.trace.status import Status, StatusCode
54 
55 try:
56     import tortoise.backends.asyncpg.client
57 
58     TORTOISE_POSTGRES_SUPPORT = True
59 except ModuleNotFoundError:
60     TORTOISE_POSTGRES_SUPPORT = False
61 
62 try:
63     import tortoise.backends.mysql.client
64 
65     TORTOISE_MYSQL_SUPPORT = True
66 except ModuleNotFoundError:
67     TORTOISE_MYSQL_SUPPORT = False
68 
69 try:
70     import tortoise.backends.sqlite.client
71 
72     TORTOISE_SQLITE_SUPPORT = True
73 except ModuleNotFoundError:
74     TORTOISE_SQLITE_SUPPORT = False
75 
76 import tortoise.contrib.pydantic.base
77 
78 
79 class TortoiseORMInstrumentor(BaseInstrumentor):
80     """An instrumentor for Tortoise-ORM
81     See `BaseInstrumentor`
82     """
83 
84     def instrumentation_dependencies(self) -> Collection[str]:
85         return _instruments
86 
87     def _instrument(self, **kwargs):
88         """Instruments Tortoise ORM backend methods.
89         Args:
90             **kwargs: Optional arguments
91                 ``tracer_provider``: a TracerProvider, defaults to global
92                 ``capture_parameters``: set to True to capture SQL query parameters
93         Returns:
94             None
95         """
96         tracer_provider = kwargs.get("tracer_provider")
97         # pylint: disable=attribute-defined-outside-init
98         self._tracer = trace.get_tracer(__name__, __version__, tracer_provider)
99         self.capture_parameters = kwargs.get("capture_parameters", False)
100         if TORTOISE_SQLITE_SUPPORT:
101             funcs = [
102                 "SqliteClient.execute_many",
103                 "SqliteClient.execute_query",
104                 "SqliteClient.execute_insert",
105                 "SqliteClient.execute_query_dict",
106                 "SqliteClient.execute_script",
107             ]
108             for func in funcs:
109                 wrapt.wrap_function_wrapper(
110                     "tortoise.backends.sqlite.client",
111                     func,
112                     self._do_execute,
113                 )
114 
115         if TORTOISE_POSTGRES_SUPPORT:
116             funcs = [
117                 "AsyncpgDBClient.execute_many",
118                 "AsyncpgDBClient.execute_query",
119                 "AsyncpgDBClient.execute_insert",
120                 "AsyncpgDBClient.execute_query_dict",
121                 "AsyncpgDBClient.execute_script",
122             ]
123             for func in funcs:
124                 wrapt.wrap_function_wrapper(
125                     "tortoise.backends.asyncpg.client",
126                     func,
127                     self._do_execute,
128                 )
129 
130         if TORTOISE_MYSQL_SUPPORT:
131             funcs = [
132                 "MySQLClient.execute_many",
133                 "MySQLClient.execute_query",
134                 "MySQLClient.execute_insert",
135                 "MySQLClient.execute_query_dict",
136                 "MySQLClient.execute_script",
137             ]
138             for func in funcs:
139                 wrapt.wrap_function_wrapper(
140                     "tortoise.backends.mysql.client",
141                     func,
142                     self._do_execute,
143                 )
144         wrapt.wrap_function_wrapper(
145             "tortoise.contrib.pydantic.base",
146             "PydanticModel.from_queryset",
147             self._from_queryset,
148         )
149         wrapt.wrap_function_wrapper(
150             "tortoise.contrib.pydantic.base",
151             "PydanticModel.from_queryset_single",
152             self._from_queryset,
153         )
154         wrapt.wrap_function_wrapper(
155             "tortoise.contrib.pydantic.base",
156             "PydanticListModel.from_queryset",
157             self._from_queryset,
158         )
159 
160     def _uninstrument(self, **kwargs):
161         if TORTOISE_SQLITE_SUPPORT:
162             unwrap(
163                 tortoise.backends.sqlite.client.SqliteClient, "execute_query"
164             )
165             unwrap(
166                 tortoise.backends.sqlite.client.SqliteClient, "execute_many"
167             )
168             unwrap(
169                 tortoise.backends.sqlite.client.SqliteClient, "execute_insert"
170             )
171             unwrap(
172                 tortoise.backends.sqlite.client.SqliteClient,
173                 "execute_query_dict",
174             )
175             unwrap(
176                 tortoise.backends.sqlite.client.SqliteClient, "execute_script"
177             )
178         if TORTOISE_MYSQL_SUPPORT:
179             unwrap(tortoise.backends.mysql.client.MySQLClient, "execute_query")
180             unwrap(tortoise.backends.mysql.client.MySQLClient, "execute_many")
181             unwrap(
182                 tortoise.backends.mysql.client.MySQLClient, "execute_insert"
183             )
184             unwrap(
185                 tortoise.backends.mysql.client.MySQLClient,
186                 "execute_query_dict",
187             )
188             unwrap(
189                 tortoise.backends.mysql.client.MySQLClient, "execute_script"
190             )
191         if TORTOISE_POSTGRES_SUPPORT:
192             unwrap(
193                 tortoise.backends.asyncpg.client.AsyncpgDBClient,
194                 "execute_query",
195             )
196             unwrap(
197                 tortoise.backends.asyncpg.client.AsyncpgDBClient,
198                 "execute_many",
199             )
200             unwrap(
201                 tortoise.backends.asyncpg.client.AsyncpgDBClient,
202                 "execute_insert",
203             )
204             unwrap(
205                 tortoise.backends.asyncpg.client.AsyncpgDBClient,
206                 "execute_query_dict",
207             )
208             unwrap(
209                 tortoise.backends.asyncpg.client.AsyncpgDBClient,
210                 "execute_script",
211             )
212         unwrap(tortoise.contrib.pydantic.base.PydanticModel, "from_queryset")
213         unwrap(
214             tortoise.contrib.pydantic.base.PydanticModel,
215             "from_queryset_single",
216         )
217         unwrap(
218             tortoise.contrib.pydantic.base.PydanticListModel, "from_queryset"
219         )
220 
221     def _hydrate_span_from_args(self, connection, query, parameters) -> dict:
222         """Get network and database attributes from connection."""
223         span_attributes = {}
224         capabilities = getattr(connection, "capabilities", None)
225         if capabilities is not None:
226             if capabilities.dialect == "sqlite":
227                 span_attributes[
228                     SpanAttributes.DB_SYSTEM
229                 ] = DbSystemValues.SQLITE.value
230             elif capabilities.dialect == "postgres":
231                 span_attributes[
232                     SpanAttributes.DB_SYSTEM
233                 ] = DbSystemValues.POSTGRESQL.value
234             elif capabilities.dialect == "mysql":
235                 span_attributes[
236                     SpanAttributes.DB_SYSTEM
237                 ] = DbSystemValues.MYSQL.value
238         dbname = getattr(connection, "filename", None)
239         if dbname:
240             span_attributes[SpanAttributes.DB_NAME] = dbname
241         dbname = getattr(connection, "database", None)
242         if dbname:
243             span_attributes[SpanAttributes.DB_NAME] = dbname
244         if query is not None:
245             span_attributes[SpanAttributes.DB_STATEMENT] = query
246         user = getattr(connection, "user", None)
247         if user:
248             span_attributes[SpanAttributes.DB_USER] = user
249         host = getattr(connection, "host", None)
250         if host:
251             span_attributes[SpanAttributes.NET_PEER_NAME] = host
252         port = getattr(connection, "port", None)
253         if port:
254             span_attributes[SpanAttributes.NET_PEER_PORT] = port
255 
256         if self.capture_parameters:
257             if parameters is not None and len(parameters) > 0:
258                 span_attributes["db.statement.parameters"] = str(parameters)
259 
260         return span_attributes
261 
262     async def _do_execute(self, func, instance, args, kwargs):
263 
264         exception = None
265         name = args[0].split()[0]
266 
267         with self._tracer.start_as_current_span(
268             name, kind=SpanKind.CLIENT
269         ) as span:
270             if span.is_recording():
271                 span_attributes = self._hydrate_span_from_args(
272                     instance,
273                     args[0],
274                     args[1:],
275                 )
276                 for attribute, value in span_attributes.items():
277                     span.set_attribute(attribute, value)
278 
279             try:
280                 result = await func(*args, **kwargs)
281             except Exception as exc:  # pylint: disable=W0703
282                 exception = exc
283                 raise
284             finally:
285                 if span.is_recording() and exception is not None:
286                     span.set_status(Status(StatusCode.ERROR))
287 
288         return result
289 
290     async def _from_queryset(self, func, modelcls, args, kwargs):
291 
292         exception = None
293         name = f"pydantic.{func.__name__}"
294 
295         with self._tracer.start_as_current_span(
296             name, kind=SpanKind.INTERNAL
297         ) as span:
298             if span.is_recording():
299                 span_attributes = {}
300 
301                 model_config = getattr(modelcls, "Config", None)
302                 if model_config:
303                     model_title = getattr(modelcls.Config, "title")
304                     if model_title:
305                         span_attributes["pydantic.model"] = model_title
306 
307                 for attribute, value in span_attributes.items():
308                     span.set_attribute(attribute, value)
309 
310             try:
311                 result = await func(*args, **kwargs)
312             except Exception as exc:  # pylint: disable=W0703
313                 exception = exc
314                 raise
315             finally:
316                 if span.is_recording() and exception is not None:
317                     span.set_status(Status(StatusCode.ERROR))
318 
319         return result
320
```
--- 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-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py b/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py
--- a/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py
+++ b/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 """
-Instrument `tortoise-orm`_ to report SQL queries.
+Instrument tortoise-orm to report SQL queries.
 
 Usage
 -----

{"golden_diff": "diff --git a/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py b/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py\n--- a/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py\n+++ b/instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py\n@@ -13,7 +13,7 @@\n # limitations under the License.\n \n \"\"\"\n-Instrument `tortoise-orm`_ to report SQL queries.\n+Instrument tortoise-orm to report SQL queries.\n \n Usage\n -----\n", "issue": "Add readthedocs documentation tortoiseorm instrumentation\nPart of [1491](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/1491)\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\"\"\"\nInstrument `tortoise-orm`_ to report SQL queries.\n\nUsage\n-----\n\n.. code:: python\n\n    from fastapi import FastAPI\n    from tortoise.contrib.fastapi import register_tortoise\n    from opentelemetry.sdk.resources import SERVICE_NAME, Resource\n    from opentelemetry.sdk.trace import TracerProvider\n    from opentelemetry.instrumentation.tortoiseorm import TortoiseORMInstrumentor\n\n    app = FastAPI()\n    tracer = TracerProvider(resource=Resource({SERVICE_NAME: \"FastAPI\"}))\n    TortoiseORMInstrumentor().instrument(tracer_provider=tracer)\n\n    register_tortoise(\n        app,\n        db_url=\"sqlite://sample.db\",\n        modules={\"models\": [\"example_app.db_models\"]}\n    )\n\nAPI\n---\n\"\"\"\nfrom typing import Collection\n\nimport wrapt\n\nfrom opentelemetry import trace\nfrom opentelemetry.instrumentation.instrumentor import BaseInstrumentor\nfrom opentelemetry.instrumentation.tortoiseorm.package import _instruments\nfrom opentelemetry.instrumentation.tortoiseorm.version import __version__\nfrom opentelemetry.instrumentation.utils import unwrap\nfrom opentelemetry.semconv.trace import DbSystemValues, SpanAttributes\nfrom opentelemetry.trace import SpanKind\nfrom opentelemetry.trace.status import Status, StatusCode\n\ntry:\n    import tortoise.backends.asyncpg.client\n\n    TORTOISE_POSTGRES_SUPPORT = True\nexcept ModuleNotFoundError:\n    TORTOISE_POSTGRES_SUPPORT = False\n\ntry:\n    import tortoise.backends.mysql.client\n\n    TORTOISE_MYSQL_SUPPORT = True\nexcept ModuleNotFoundError:\n    TORTOISE_MYSQL_SUPPORT = False\n\ntry:\n    import tortoise.backends.sqlite.client\n\n    TORTOISE_SQLITE_SUPPORT = True\nexcept ModuleNotFoundError:\n    TORTOISE_SQLITE_SUPPORT = False\n\nimport tortoise.contrib.pydantic.base\n\n\nclass TortoiseORMInstrumentor(BaseInstrumentor):\n    \"\"\"An instrumentor for Tortoise-ORM\n    See `BaseInstrumentor`\n    \"\"\"\n\n    def instrumentation_dependencies(self) -> Collection[str]:\n        return _instruments\n\n    def _instrument(self, **kwargs):\n        \"\"\"Instruments Tortoise ORM backend methods.\n        Args:\n            **kwargs: Optional arguments\n                ``tracer_provider``: a TracerProvider, defaults to global\n                ``capture_parameters``: set to True to capture SQL query parameters\n        Returns:\n            None\n        \"\"\"\n        tracer_provider = kwargs.get(\"tracer_provider\")\n        # pylint: disable=attribute-defined-outside-init\n        self._tracer = trace.get_tracer(__name__, __version__, tracer_provider)\n        self.capture_parameters = kwargs.get(\"capture_parameters\", False)\n        if TORTOISE_SQLITE_SUPPORT:\n            funcs = [\n                \"SqliteClient.execute_many\",\n                \"SqliteClient.execute_query\",\n                \"SqliteClient.execute_insert\",\n                \"SqliteClient.execute_query_dict\",\n                \"SqliteClient.execute_script\",\n            ]\n            for func in funcs:\n                wrapt.wrap_function_wrapper(\n                    \"tortoise.backends.sqlite.client\",\n                    func,\n                    self._do_execute,\n                )\n\n        if TORTOISE_POSTGRES_SUPPORT:\n            funcs = [\n                \"AsyncpgDBClient.execute_many\",\n                \"AsyncpgDBClient.execute_query\",\n                \"AsyncpgDBClient.execute_insert\",\n                \"AsyncpgDBClient.execute_query_dict\",\n                \"AsyncpgDBClient.execute_script\",\n            ]\n            for func in funcs:\n                wrapt.wrap_function_wrapper(\n                    \"tortoise.backends.asyncpg.client\",\n                    func,\n                    self._do_execute,\n                )\n\n        if TORTOISE_MYSQL_SUPPORT:\n            funcs = [\n                \"MySQLClient.execute_many\",\n                \"MySQLClient.execute_query\",\n                \"MySQLClient.execute_insert\",\n                \"MySQLClient.execute_query_dict\",\n                \"MySQLClient.execute_script\",\n            ]\n            for func in funcs:\n                wrapt.wrap_function_wrapper(\n                    \"tortoise.backends.mysql.client\",\n                    func,\n                    self._do_execute,\n                )\n        wrapt.wrap_function_wrapper(\n            \"tortoise.contrib.pydantic.base\",\n            \"PydanticModel.from_queryset\",\n            self._from_queryset,\n        )\n        wrapt.wrap_function_wrapper(\n            \"tortoise.contrib.pydantic.base\",\n            \"PydanticModel.from_queryset_single\",\n            self._from_queryset,\n        )\n        wrapt.wrap_function_wrapper(\n            \"tortoise.contrib.pydantic.base\",\n            \"PydanticListModel.from_queryset\",\n            self._from_queryset,\n        )\n\n    def _uninstrument(self, **kwargs):\n        if TORTOISE_SQLITE_SUPPORT:\n            unwrap(\n                tortoise.backends.sqlite.client.SqliteClient, \"execute_query\"\n            )\n            unwrap(\n                tortoise.backends.sqlite.client.SqliteClient, \"execute_many\"\n            )\n            unwrap(\n                tortoise.backends.sqlite.client.SqliteClient, \"execute_insert\"\n            )\n            unwrap(\n                tortoise.backends.sqlite.client.SqliteClient,\n                \"execute_query_dict\",\n            )\n            unwrap(\n                tortoise.backends.sqlite.client.SqliteClient, \"execute_script\"\n            )\n        if TORTOISE_MYSQL_SUPPORT:\n            unwrap(tortoise.backends.mysql.client.MySQLClient, \"execute_query\")\n            unwrap(tortoise.backends.mysql.client.MySQLClient, \"execute_many\")\n            unwrap(\n                tortoise.backends.mysql.client.MySQLClient, \"execute_insert\"\n            )\n            unwrap(\n                tortoise.backends.mysql.client.MySQLClient,\n                \"execute_query_dict\",\n            )\n            unwrap(\n                tortoise.backends.mysql.client.MySQLClient, \"execute_script\"\n            )\n        if TORTOISE_POSTGRES_SUPPORT:\n            unwrap(\n                tortoise.backends.asyncpg.client.AsyncpgDBClient,\n                \"execute_query\",\n            )\n            unwrap(\n                tortoise.backends.asyncpg.client.AsyncpgDBClient,\n                \"execute_many\",\n            )\n            unwrap(\n                tortoise.backends.asyncpg.client.AsyncpgDBClient,\n                \"execute_insert\",\n            )\n            unwrap(\n                tortoise.backends.asyncpg.client.AsyncpgDBClient,\n                \"execute_query_dict\",\n            )\n            unwrap(\n                tortoise.backends.asyncpg.client.AsyncpgDBClient,\n                \"execute_script\",\n            )\n        unwrap(tortoise.contrib.pydantic.base.PydanticModel, \"from_queryset\")\n        unwrap(\n            tortoise.contrib.pydantic.base.PydanticModel,\n            \"from_queryset_single\",\n        )\n        unwrap(\n            tortoise.contrib.pydantic.base.PydanticListModel, \"from_queryset\"\n        )\n\n    def _hydrate_span_from_args(self, connection, query, parameters) -> dict:\n        \"\"\"Get network and database attributes from connection.\"\"\"\n        span_attributes = {}\n        capabilities = getattr(connection, \"capabilities\", None)\n        if capabilities is not None:\n            if capabilities.dialect == \"sqlite\":\n                span_attributes[\n                    SpanAttributes.DB_SYSTEM\n                ] = DbSystemValues.SQLITE.value\n            elif capabilities.dialect == \"postgres\":\n                span_attributes[\n                    SpanAttributes.DB_SYSTEM\n                ] = DbSystemValues.POSTGRESQL.value\n            elif capabilities.dialect == \"mysql\":\n                span_attributes[\n                    SpanAttributes.DB_SYSTEM\n                ] = DbSystemValues.MYSQL.value\n        dbname = getattr(connection, \"filename\", None)\n        if dbname:\n            span_attributes[SpanAttributes.DB_NAME] = dbname\n        dbname = getattr(connection, \"database\", None)\n        if dbname:\n            span_attributes[SpanAttributes.DB_NAME] = dbname\n        if query is not None:\n            span_attributes[SpanAttributes.DB_STATEMENT] = query\n        user = getattr(connection, \"user\", None)\n        if user:\n            span_attributes[SpanAttributes.DB_USER] = user\n        host = getattr(connection, \"host\", None)\n        if host:\n            span_attributes[SpanAttributes.NET_PEER_NAME] = host\n        port = getattr(connection, \"port\", None)\n        if port:\n            span_attributes[SpanAttributes.NET_PEER_PORT] = port\n\n        if self.capture_parameters:\n            if parameters is not None and len(parameters) > 0:\n                span_attributes[\"db.statement.parameters\"] = str(parameters)\n\n        return span_attributes\n\n    async def _do_execute(self, func, instance, args, kwargs):\n\n        exception = None\n        name = args[0].split()[0]\n\n        with self._tracer.start_as_current_span(\n            name, kind=SpanKind.CLIENT\n        ) as span:\n            if span.is_recording():\n                span_attributes = self._hydrate_span_from_args(\n                    instance,\n                    args[0],\n                    args[1:],\n                )\n                for attribute, value in span_attributes.items():\n                    span.set_attribute(attribute, value)\n\n            try:\n                result = await func(*args, **kwargs)\n            except Exception as exc:  # pylint: disable=W0703\n                exception = exc\n                raise\n            finally:\n                if span.is_recording() and exception is not None:\n                    span.set_status(Status(StatusCode.ERROR))\n\n        return result\n\n    async def _from_queryset(self, func, modelcls, args, kwargs):\n\n        exception = None\n        name = f\"pydantic.{func.__name__}\"\n\n        with self._tracer.start_as_current_span(\n            name, kind=SpanKind.INTERNAL\n        ) as span:\n            if span.is_recording():\n                span_attributes = {}\n\n                model_config = getattr(modelcls, \"Config\", None)\n                if model_config:\n                    model_title = getattr(modelcls.Config, \"title\")\n                    if model_title:\n                        span_attributes[\"pydantic.model\"] = model_title\n\n                for attribute, value in span_attributes.items():\n                    span.set_attribute(attribute, value)\n\n            try:\n                result = await func(*args, **kwargs)\n            except Exception as exc:  # pylint: disable=W0703\n                exception = exc\n                raise\n            finally:\n                if span.is_recording() and exception is not None:\n                    span.set_status(Status(StatusCode.ERROR))\n\n        return result\n", "path": "instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__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\"\"\"\nInstrument tortoise-orm to report SQL queries.\n\nUsage\n-----\n\n.. code:: python\n\n    from fastapi import FastAPI\n    from tortoise.contrib.fastapi import register_tortoise\n    from opentelemetry.sdk.resources import SERVICE_NAME, Resource\n    from opentelemetry.sdk.trace import TracerProvider\n    from opentelemetry.instrumentation.tortoiseorm import TortoiseORMInstrumentor\n\n    app = FastAPI()\n    tracer = TracerProvider(resource=Resource({SERVICE_NAME: \"FastAPI\"}))\n    TortoiseORMInstrumentor().instrument(tracer_provider=tracer)\n\n    register_tortoise(\n        app,\n        db_url=\"sqlite://sample.db\",\n        modules={\"models\": [\"example_app.db_models\"]}\n    )\n\nAPI\n---\n\"\"\"\nfrom typing import Collection\n\nimport wrapt\n\nfrom opentelemetry import trace\nfrom opentelemetry.instrumentation.instrumentor import BaseInstrumentor\nfrom opentelemetry.instrumentation.tortoiseorm.package import _instruments\nfrom opentelemetry.instrumentation.tortoiseorm.version import __version__\nfrom opentelemetry.instrumentation.utils import unwrap\nfrom opentelemetry.semconv.trace import DbSystemValues, SpanAttributes\nfrom opentelemetry.trace import SpanKind\nfrom opentelemetry.trace.status import Status, StatusCode\n\ntry:\n    import tortoise.backends.asyncpg.client\n\n    TORTOISE_POSTGRES_SUPPORT = True\nexcept ModuleNotFoundError:\n    TORTOISE_POSTGRES_SUPPORT = False\n\ntry:\n    import tortoise.backends.mysql.client\n\n    TORTOISE_MYSQL_SUPPORT = True\nexcept ModuleNotFoundError:\n    TORTOISE_MYSQL_SUPPORT = False\n\ntry:\n    import tortoise.backends.sqlite.client\n\n    TORTOISE_SQLITE_SUPPORT = True\nexcept ModuleNotFoundError:\n    TORTOISE_SQLITE_SUPPORT = False\n\nimport tortoise.contrib.pydantic.base\n\n\nclass TortoiseORMInstrumentor(BaseInstrumentor):\n    \"\"\"An instrumentor for Tortoise-ORM\n    See `BaseInstrumentor`\n    \"\"\"\n\n    def instrumentation_dependencies(self) -> Collection[str]:\n        return _instruments\n\n    def _instrument(self, **kwargs):\n        \"\"\"Instruments Tortoise ORM backend methods.\n        Args:\n            **kwargs: Optional arguments\n                ``tracer_provider``: a TracerProvider, defaults to global\n                ``capture_parameters``: set to True to capture SQL query parameters\n        Returns:\n            None\n        \"\"\"\n        tracer_provider = kwargs.get(\"tracer_provider\")\n        # pylint: disable=attribute-defined-outside-init\n        self._tracer = trace.get_tracer(__name__, __version__, tracer_provider)\n        self.capture_parameters = kwargs.get(\"capture_parameters\", False)\n        if TORTOISE_SQLITE_SUPPORT:\n            funcs = [\n                \"SqliteClient.execute_many\",\n                \"SqliteClient.execute_query\",\n                \"SqliteClient.execute_insert\",\n                \"SqliteClient.execute_query_dict\",\n                \"SqliteClient.execute_script\",\n            ]\n            for func in funcs:\n                wrapt.wrap_function_wrapper(\n                    \"tortoise.backends.sqlite.client\",\n                    func,\n                    self._do_execute,\n                )\n\n        if TORTOISE_POSTGRES_SUPPORT:\n            funcs = [\n                \"AsyncpgDBClient.execute_many\",\n                \"AsyncpgDBClient.execute_query\",\n                \"AsyncpgDBClient.execute_insert\",\n                \"AsyncpgDBClient.execute_query_dict\",\n                \"AsyncpgDBClient.execute_script\",\n            ]\n            for func in funcs:\n                wrapt.wrap_function_wrapper(\n                    \"tortoise.backends.asyncpg.client\",\n                    func,\n                    self._do_execute,\n                )\n\n        if TORTOISE_MYSQL_SUPPORT:\n            funcs = [\n                \"MySQLClient.execute_many\",\n                \"MySQLClient.execute_query\",\n                \"MySQLClient.execute_insert\",\n                \"MySQLClient.execute_query_dict\",\n                \"MySQLClient.execute_script\",\n            ]\n            for func in funcs:\n                wrapt.wrap_function_wrapper(\n                    \"tortoise.backends.mysql.client\",\n                    func,\n                    self._do_execute,\n                )\n        wrapt.wrap_function_wrapper(\n            \"tortoise.contrib.pydantic.base\",\n            \"PydanticModel.from_queryset\",\n            self._from_queryset,\n        )\n        wrapt.wrap_function_wrapper(\n            \"tortoise.contrib.pydantic.base\",\n            \"PydanticModel.from_queryset_single\",\n            self._from_queryset,\n        )\n        wrapt.wrap_function_wrapper(\n            \"tortoise.contrib.pydantic.base\",\n            \"PydanticListModel.from_queryset\",\n            self._from_queryset,\n        )\n\n    def _uninstrument(self, **kwargs):\n        if TORTOISE_SQLITE_SUPPORT:\n            unwrap(\n                tortoise.backends.sqlite.client.SqliteClient, \"execute_query\"\n            )\n            unwrap(\n                tortoise.backends.sqlite.client.SqliteClient, \"execute_many\"\n            )\n            unwrap(\n                tortoise.backends.sqlite.client.SqliteClient, \"execute_insert\"\n            )\n            unwrap(\n                tortoise.backends.sqlite.client.SqliteClient,\n                \"execute_query_dict\",\n            )\n            unwrap(\n                tortoise.backends.sqlite.client.SqliteClient, \"execute_script\"\n            )\n        if TORTOISE_MYSQL_SUPPORT:\n            unwrap(tortoise.backends.mysql.client.MySQLClient, \"execute_query\")\n            unwrap(tortoise.backends.mysql.client.MySQLClient, \"execute_many\")\n            unwrap(\n                tortoise.backends.mysql.client.MySQLClient, \"execute_insert\"\n            )\n            unwrap(\n                tortoise.backends.mysql.client.MySQLClient,\n                \"execute_query_dict\",\n            )\n            unwrap(\n                tortoise.backends.mysql.client.MySQLClient, \"execute_script\"\n            )\n        if TORTOISE_POSTGRES_SUPPORT:\n            unwrap(\n                tortoise.backends.asyncpg.client.AsyncpgDBClient,\n                \"execute_query\",\n            )\n            unwrap(\n                tortoise.backends.asyncpg.client.AsyncpgDBClient,\n                \"execute_many\",\n            )\n            unwrap(\n                tortoise.backends.asyncpg.client.AsyncpgDBClient,\n                \"execute_insert\",\n            )\n            unwrap(\n                tortoise.backends.asyncpg.client.AsyncpgDBClient,\n                \"execute_query_dict\",\n            )\n            unwrap(\n                tortoise.backends.asyncpg.client.AsyncpgDBClient,\n                \"execute_script\",\n            )\n        unwrap(tortoise.contrib.pydantic.base.PydanticModel, \"from_queryset\")\n        unwrap(\n            tortoise.contrib.pydantic.base.PydanticModel,\n            \"from_queryset_single\",\n        )\n        unwrap(\n            tortoise.contrib.pydantic.base.PydanticListModel, \"from_queryset\"\n        )\n\n    def _hydrate_span_from_args(self, connection, query, parameters) -> dict:\n        \"\"\"Get network and database attributes from connection.\"\"\"\n        span_attributes = {}\n        capabilities = getattr(connection, \"capabilities\", None)\n        if capabilities is not None:\n            if capabilities.dialect == \"sqlite\":\n                span_attributes[\n                    SpanAttributes.DB_SYSTEM\n                ] = DbSystemValues.SQLITE.value\n            elif capabilities.dialect == \"postgres\":\n                span_attributes[\n                    SpanAttributes.DB_SYSTEM\n                ] = DbSystemValues.POSTGRESQL.value\n            elif capabilities.dialect == \"mysql\":\n                span_attributes[\n                    SpanAttributes.DB_SYSTEM\n                ] = DbSystemValues.MYSQL.value\n        dbname = getattr(connection, \"filename\", None)\n        if dbname:\n            span_attributes[SpanAttributes.DB_NAME] = dbname\n        dbname = getattr(connection, \"database\", None)\n        if dbname:\n            span_attributes[SpanAttributes.DB_NAME] = dbname\n        if query is not None:\n            span_attributes[SpanAttributes.DB_STATEMENT] = query\n        user = getattr(connection, \"user\", None)\n        if user:\n            span_attributes[SpanAttributes.DB_USER] = user\n        host = getattr(connection, \"host\", None)\n        if host:\n            span_attributes[SpanAttributes.NET_PEER_NAME] = host\n        port = getattr(connection, \"port\", None)\n        if port:\n            span_attributes[SpanAttributes.NET_PEER_PORT] = port\n\n        if self.capture_parameters:\n            if parameters is not None and len(parameters) > 0:\n                span_attributes[\"db.statement.parameters\"] = str(parameters)\n\n        return span_attributes\n\n    async def _do_execute(self, func, instance, args, kwargs):\n\n        exception = None\n        name = args[0].split()[0]\n\n        with self._tracer.start_as_current_span(\n            name, kind=SpanKind.CLIENT\n        ) as span:\n            if span.is_recording():\n                span_attributes = self._hydrate_span_from_args(\n                    instance,\n                    args[0],\n                    args[1:],\n                )\n                for attribute, value in span_attributes.items():\n                    span.set_attribute(attribute, value)\n\n            try:\n                result = await func(*args, **kwargs)\n            except Exception as exc:  # pylint: disable=W0703\n                exception = exc\n                raise\n            finally:\n                if span.is_recording() and exception is not None:\n                    span.set_status(Status(StatusCode.ERROR))\n\n        return result\n\n    async def _from_queryset(self, func, modelcls, args, kwargs):\n\n        exception = None\n        name = f\"pydantic.{func.__name__}\"\n\n        with self._tracer.start_as_current_span(\n            name, kind=SpanKind.INTERNAL\n        ) as span:\n            if span.is_recording():\n                span_attributes = {}\n\n                model_config = getattr(modelcls, \"Config\", None)\n                if model_config:\n                    model_title = getattr(modelcls.Config, \"title\")\n                    if model_title:\n                        span_attributes[\"pydantic.model\"] = model_title\n\n                for attribute, value in span_attributes.items():\n                    span.set_attribute(attribute, value)\n\n            try:\n                result = await func(*args, **kwargs)\n            except Exception as exc:  # pylint: disable=W0703\n                exception = exc\n                raise\n            finally:\n                if span.is_recording() and exception is not None:\n                    span.set_status(Status(StatusCode.ERROR))\n\n        return result\n", "path": "instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py"}]}