wrapture-instrumentation-mysql 1.0.0.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. wrapture_instrumentation_mysql-1.0.0.dev1/CHANGES.md +9 -0
  2. wrapture_instrumentation_mysql-1.0.0.dev1/Dockerfile +20 -0
  3. wrapture_instrumentation_mysql-1.0.0.dev1/LICENSE +24 -0
  4. wrapture_instrumentation_mysql-1.0.0.dev1/MANIFEST.in +8 -0
  5. wrapture_instrumentation_mysql-1.0.0.dev1/PKG-INFO +181 -0
  6. wrapture_instrumentation_mysql-1.0.0.dev1/README.md +158 -0
  7. wrapture_instrumentation_mysql-1.0.0.dev1/TESTING.md +310 -0
  8. wrapture_instrumentation_mysql-1.0.0.dev1/compose.yml +82 -0
  9. wrapture_instrumentation_mysql-1.0.0.dev1/demo/__init__.py +0 -0
  10. wrapture_instrumentation_mysql-1.0.0.dev1/demo/aiomysql.py +169 -0
  11. wrapture_instrumentation_mysql-1.0.0.dev1/demo/mysqldb.py +156 -0
  12. wrapture_instrumentation_mysql-1.0.0.dev1/demo/pymysql.py +157 -0
  13. wrapture_instrumentation_mysql-1.0.0.dev1/pyproject.toml +134 -0
  14. wrapture_instrumentation_mysql-1.0.0.dev1/setup.cfg +4 -0
  15. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/__init__.py +26 -0
  16. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/aiomysql/README.md +174 -0
  17. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/aiomysql/__init__.py +58 -0
  18. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/aiomysql/connection.py +113 -0
  19. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/aiomysql/cursor.py +99 -0
  20. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/common.py +151 -0
  21. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/mysqldb/README.md +179 -0
  22. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/mysqldb/__init__.py +98 -0
  23. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/mysqldb/connection.py +161 -0
  24. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/mysqldb/cursor.py +110 -0
  25. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/py.typed +0 -0
  26. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/pymysql/README.md +166 -0
  27. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/pymysql/__init__.py +54 -0
  28. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/pymysql/connection.py +113 -0
  29. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql/pymysql/cursor.py +97 -0
  30. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql.egg-info/PKG-INFO +181 -0
  31. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql.egg-info/SOURCES.txt +58 -0
  32. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql.egg-info/dependency_links.txt +1 -0
  33. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql.egg-info/entry_points.txt +4 -0
  34. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql.egg-info/not-zip-safe +1 -0
  35. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql.egg-info/requires.txt +1 -0
  36. wrapture_instrumentation_mysql-1.0.0.dev1/src/wrapture_instrumentation_mysql.egg-info/top_level.txt +1 -0
  37. wrapture_instrumentation_mysql-1.0.0.dev1/tests/__init__.py +0 -0
  38. wrapture_instrumentation_mysql-1.0.0.dev1/tests/aiomysql/__init__.py +0 -0
  39. wrapture_instrumentation_mysql-1.0.0.dev1/tests/aiomysql/conftest.py +35 -0
  40. wrapture_instrumentation_mysql-1.0.0.dev1/tests/aiomysql/test_apply_remove.py +117 -0
  41. wrapture_instrumentation_mysql-1.0.0.dev1/tests/aiomysql/test_class.py +70 -0
  42. wrapture_instrumentation_mysql-1.0.0.dev1/tests/aiomysql/test_composition.py +151 -0
  43. wrapture_instrumentation_mysql-1.0.0.dev1/tests/aiomysql/test_recording.py +536 -0
  44. wrapture_instrumentation_mysql-1.0.0.dev1/tests/aiomysql/test_registration.py +85 -0
  45. wrapture_instrumentation_mysql-1.0.0.dev1/tests/conftest.py +333 -0
  46. wrapture_instrumentation_mysql-1.0.0.dev1/tests/mysqldb/__init__.py +0 -0
  47. wrapture_instrumentation_mysql-1.0.0.dev1/tests/mysqldb/conftest.py +23 -0
  48. wrapture_instrumentation_mysql-1.0.0.dev1/tests/mysqldb/test_apply_remove.py +136 -0
  49. wrapture_instrumentation_mysql-1.0.0.dev1/tests/mysqldb/test_class.py +74 -0
  50. wrapture_instrumentation_mysql-1.0.0.dev1/tests/mysqldb/test_composition.py +156 -0
  51. wrapture_instrumentation_mysql-1.0.0.dev1/tests/mysqldb/test_recording.py +533 -0
  52. wrapture_instrumentation_mysql-1.0.0.dev1/tests/mysqldb/test_registration.py +82 -0
  53. wrapture_instrumentation_mysql-1.0.0.dev1/tests/pymysql/__init__.py +0 -0
  54. wrapture_instrumentation_mysql-1.0.0.dev1/tests/pymysql/conftest.py +22 -0
  55. wrapture_instrumentation_mysql-1.0.0.dev1/tests/pymysql/test_apply_remove.py +106 -0
  56. wrapture_instrumentation_mysql-1.0.0.dev1/tests/pymysql/test_class.py +70 -0
  57. wrapture_instrumentation_mysql-1.0.0.dev1/tests/pymysql/test_composition.py +154 -0
  58. wrapture_instrumentation_mysql-1.0.0.dev1/tests/pymysql/test_recording.py +495 -0
  59. wrapture_instrumentation_mysql-1.0.0.dev1/tests/pymysql/test_registration.py +80 -0
  60. wrapture_instrumentation_mysql-1.0.0.dev1/tests/test_package.py +179 -0
@@ -0,0 +1,9 @@
1
+ # Changes
2
+
3
+ ## Version 1.0.0
4
+
5
+ Initial release of wrapture-instrumentation-mysql. Everything is new
6
+ in this version, so rather than listing changes, see the
7
+ [README](README.md) for what the package provides: the table of
8
+ covered targets there links to each target's own notes describing
9
+ what it records and its settings.
@@ -0,0 +1,20 @@
1
+ # The environment the test matrix runs in: Debian with uv, plus what
2
+ # mysqlclient needs to build from its source distribution, since it
3
+ # ships no Linux or macOS wheels: pkg-config, the MySQL client
4
+ # development package (Debian's default-libmysqlclient-dev, which is
5
+ # MariaDB Connector/C) and a C compiler. Nothing else is baked in: uv
6
+ # fetches whichever interpreter the run asks for and installs the
7
+ # test dependencies into a per-version environment, both on named
8
+ # volumes so they persist across runs (see compose.yml), so the build
9
+ # of mysqlclient happens once per version. The repository is
10
+ # bind-mounted at run time, so the image never goes stale as the code
11
+ # changes.
12
+
13
+ FROM ghcr.io/astral-sh/uv:debian-slim
14
+
15
+ RUN apt-get update \
16
+ && apt-get install -y --no-install-recommends \
17
+ default-libmysqlclient-dev pkg-config gcc libc6-dev \
18
+ && rm -rf /var/lib/apt/lists/*
19
+
20
+ WORKDIR /work
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2026, Graham Dumpleton
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
+ POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,8 @@
1
+ # setuptools includes test_*.py files by default but not the helpers
2
+ # they import (conftest.py, the package __init__.py), so the tests
3
+ # directory is taken whole, with the repository's other notes and the
4
+ # docker files the test matrix runs under.
5
+ graft tests
6
+ graft demo
7
+ include CHANGES.md TESTING.md compose.yml Dockerfile
8
+ global-exclude __pycache__ *.py[cod]
@@ -0,0 +1,181 @@
1
+ Metadata-Version: 2.4
2
+ Name: wrapture-instrumentation-mysql
3
+ Version: 1.0.0.dev1
4
+ Summary: Instrumentation for the MySQL client libraries (PyMySQL, mysqlclient, aiomysql), applied through wrapture.
5
+ Author-email: Graham Dumpleton <Graham.Dumpleton@gmail.com>
6
+ License-Expression: BSD-2-Clause
7
+ Project-URL: Homepage, https://github.com/GrahamDumpleton/wrapture-instrumentation-mysql
8
+ Project-URL: Documentation, https://wrapture.readthedocs.io
9
+ Project-URL: Bug Tracker, https://github.com/GrahamDumpleton/wrapture-instrumentation-mysql/issues/
10
+ Keywords: wrapture,instrumentation,mysql,pymysql,mysqlclient,MySQLdb,aiomysql,tracing
11
+ Classifier: Development Status :: 2 - Pre-Alpha
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Programming Language :: Python :: 3.15
17
+ Classifier: Programming Language :: Python :: Implementation :: CPython
18
+ Requires-Python: >=3.12
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: wrapture>=1.0.0a21
22
+ Dynamic: license-file
23
+
24
+ # wrapture-instrumentation-mysql
25
+
26
+ Instrumentation for the MySQL client libraries, applied through
27
+ [wrapture](https://github.com/GrahamDumpleton/wrapture).
28
+
29
+ wrapture attaches bindings to arbitrary Python call sites without
30
+ modifying the code being observed, and its config layer can switch on
31
+ packaged instrumentation for a third-party package by name. This is
32
+ the MySQL package in that collection: one `wrapture.Instrumentation`
33
+ class per client library, so tracing every query, connection and
34
+ transaction your application sends to MySQL (or MariaDB, through the
35
+ same drivers) is one config entry and no code.
36
+
37
+ > **Status: alpha, ahead of 1.0.0.** Developed against wrapture's
38
+ > alpha series, with pre-releases published to
39
+ > [PyPI](https://pypi.org/project/wrapture-instrumentation-mysql/),
40
+ > and until 1.0.0 is final a plain `pip install
41
+ > wrapture-instrumentation-mysql` picks up the latest pre-release
42
+ > automatically, so there is no need to pin a specific version.
43
+
44
+ ## Why a separate package
45
+
46
+ The core
47
+ [wrapture-instrumentation](https://github.com/GrahamDumpleton/wrapture-instrumentation)
48
+ package deliberately covers only the standard library and third-party
49
+ packages that can be exercised in-process, with no separate backend
50
+ product or service needed to test against. A MySQL driver is exactly
51
+ the kind of target the separate-package rule was drawn for: its tests
52
+ need a real server, so this package's suite runs one in a docker
53
+ container, and it carries the drivers as test dependencies (one of
54
+ them built from source against a MySQL client library) and its own
55
+ release cadence, so the core package's test matrix stays light. One
56
+ package covers every client library for the one backend.
57
+
58
+ ## Installation
59
+
60
+ ```console
61
+ $ pip install wrapture-instrumentation-mysql
62
+ ```
63
+
64
+ Installing it brings wrapture and nothing else. No driver is a
65
+ dependency: each instrumentation is inert until its driver is present,
66
+ and wrapture checks the installed version against the range the
67
+ instrumentation supports at apply time.
68
+
69
+ ## Using it
70
+
71
+ An `[[instrument]]` entry in `wrapture.toml` names the target:
72
+
73
+ ```toml
74
+ [[instrument]]
75
+ name = "pymysql"
76
+
77
+ [[sink]]
78
+ type = "printer"
79
+ ```
80
+
81
+ and the runner applies it before the application starts, so the patch
82
+ is in place before the driver is imported:
83
+
84
+ ```console
85
+ $ python -m wrapture -m myapp
86
+ ```
87
+
88
+ The same config works through
89
+ [autowrapt](https://github.com/GrahamDumpleton/autowrapt) injection
90
+ (`AUTOWRAPT_BOOTSTRAP=wrapture python myapp.py`); through
91
+ [manual setup](https://wrapture.readthedocs.io/en/latest/manual-setup.html),
92
+ a few lines in the application's own startup where wrapping the launch
93
+ from outside is awkward; and, in a test, through
94
+ `wrapture.instrumentation("pymysql")` scoping the instrumentation to
95
+ a block. The
96
+ [ad-hoc tracing guide](https://wrapture.readthedocs.io/en/latest/ad-hoc-tracing.html)
97
+ covers the config file itself.
98
+
99
+ To see what is installed, what it supports in the current
100
+ environment, and what settings it takes:
101
+
102
+ ```console
103
+ $ python -m wrapture.tools instrumentation --verbose
104
+ ```
105
+
106
+ ## Provided instrumentation
107
+
108
+ | Target | Supported versions | Records | Settings |
109
+ | ------ | ------------------ | ------- | -------- |
110
+ | [`pymysql`](https://github.com/GrahamDumpleton/wrapture-instrumentation-mysql/blob/develop/src/wrapture_instrumentation_mysql/pymysql/README.md) | PyMySQL 1.1.1+ (1.x) | Every query as one `database` leaf, however it was issued (a cursor's `execute`, `executemany` or `callproc`, through whichever cursor class the application chose), plus the connection being opened and each transaction boundary the connection performs itself (`begin`, `commit`, `rollback`). Each event carries the system, the operation, and the database, host and port it reached; a failing statement records the driver's exception. The SQL text (the template with its placeholders) is recorded only with the `statement` setting on, bound parameters never. | `statement` |
111
+ | [`MySQLdb`](https://github.com/GrahamDumpleton/wrapture-instrumentation-mysql/blob/develop/src/wrapture_instrumentation_mysql/mysqldb/README.md) | mysqlclient 2.2.1+ (2.x), imported as `MySQLdb` | The same shapes through mysqlclient: every query as one `database` leaf (`execute`, `executemany`, `callproc`, through every cursor class), the connection being opened, and `begin`, `commit` and `rollback`, the last two bound over the C core's own methods. Each event carries the system, the operation, and the host and port it reached, plus the database from mysqlclient 2.2.7 on (earlier versions do not keep it); a failing statement records the driver's exception. The SQL text (the template with its placeholders) is recorded only with the `statement` setting on, bound parameters never. | `statement` |
112
+ | [`aiomysql`](https://github.com/GrahamDumpleton/wrapture-instrumentation-mysql/blob/develop/src/wrapture_instrumentation_mysql/aiomysql/README.md) | aiomysql 0.2+ (0.x) | The same shapes through aiomysql, each event recorded around its await: every query as one `database` leaf (`execute`, `executemany`, `callproc`, through every cursor class), the connection being opened (from a pool too), and `begin`, `commit` and `rollback`. Each event carries the system, the operation, and the database, host and port it reached; a failing statement records the driver's exception. The SQL text (the template with its placeholders) is recorded only with the `statement` setting on, bound parameters never. | `statement` |
113
+
114
+ The entry point name is the config's `name`, and is the import name
115
+ of the package the instrumentation patches (so mysqlclient's is
116
+ `MySQLdb`); the linked per-target README is the full user
117
+ documentation: what records, what the events carry, the setting, and
118
+ what is deliberately not traced.
119
+
120
+ ## What is not traced
121
+
122
+ By design, and where it goes:
123
+
124
+ - Fetching rows: a query event closes when its execute returns, so
125
+ time spent iterating rows afterwards is the application's. An
126
+ unbuffered cursor (`SSCursor`) therefore records the send and the
127
+ wait for the first packet, not the streaming of the rows.
128
+
129
+ - The connection's context manager: in these drivers leaving a
130
+ `with connection:` block closes the connection and performs no
131
+ commit or rollback, so it is not a transaction boundary and records
132
+ nothing. The explicit `commit()` and `rollback()` calls do.
133
+
134
+ - Mode changes and housekeeping (`autocommit()`, `select_db()`,
135
+ `ping()`, `set_character_set()`, `show_warnings()`): not database
136
+ operations in the sense the events record.
137
+
138
+ - Pool bookkeeping (aiomysql): taking a connection from a pool and
139
+ returning it are not database operations; the connections the pool
140
+ opens do record.
141
+
142
+ - `LOAD DATA LOCAL INFILE` records as a statement like any other; the
143
+ file's contents never do.
144
+
145
+ ## Testing against a server
146
+
147
+ The test suite drives the real drivers against a real MySQL server.
148
+ `WRAPTURE_MYSQL_URL` in the environment names one
149
+ (`mysql://user:password@host:port/database`); without it the suite
150
+ runs a throwaway `mysql:8.4` container itself, which needs Docker
151
+ Desktop or another docker daemon. With neither it fails rather than
152
+ skips. The mysqlclient driver builds from source against a MySQL
153
+ client library, so its suite runs inside a docker container that
154
+ carries the toolchain (`just test-docker`), and a plain native run
155
+ skips that one suite visibly rather than asking for a client library
156
+ on the machine. [TESTING.md](TESTING.md) covers the details, including how
157
+ the suite copes with MySQL 8's `caching_sha2_password` authentication
158
+ (the readiness probe's first connection warms the server's credential
159
+ cache, after which every driver connects plainly; a real application
160
+ on a cold cache over a plain socket needs the driver's own RSA or TLS
161
+ option, which is the driver's concern, not the instrumentation's).
162
+
163
+ ## Adding a target
164
+
165
+ Each client library is its own subpackage and entry point here. The
166
+ subpackage's `__init__.py` holds one `wrapture.Instrumentation`
167
+ subclass and imports only wrapture (and the package's own `common.py`,
168
+ which imports only wrapture too); everything that touches the driver
169
+ lives in sibling modules imported inside the hook. The class is
170
+ registered in `pyproject.toml` under
171
+ `[project.entry-points."wrapture.instrumentation"]`, and gets its own
172
+ test suite under `tests/<target>/` and a `README.md` linked from the
173
+ table above. The
174
+ [instrumentation packages](https://wrapture.readthedocs.io/en/latest/instrumentation-packages.html)
175
+ page of the wrapture documentation is the full contract; TESTING.md
176
+ here covers the tests and the server they run against.
177
+
178
+ ## License
179
+
180
+ BSD 2-Clause. See
181
+ [LICENSE](https://github.com/GrahamDumpleton/wrapture-instrumentation-mysql/blob/develop/LICENSE).
@@ -0,0 +1,158 @@
1
+ # wrapture-instrumentation-mysql
2
+
3
+ Instrumentation for the MySQL client libraries, applied through
4
+ [wrapture](https://github.com/GrahamDumpleton/wrapture).
5
+
6
+ wrapture attaches bindings to arbitrary Python call sites without
7
+ modifying the code being observed, and its config layer can switch on
8
+ packaged instrumentation for a third-party package by name. This is
9
+ the MySQL package in that collection: one `wrapture.Instrumentation`
10
+ class per client library, so tracing every query, connection and
11
+ transaction your application sends to MySQL (or MariaDB, through the
12
+ same drivers) is one config entry and no code.
13
+
14
+ > **Status: alpha, ahead of 1.0.0.** Developed against wrapture's
15
+ > alpha series, with pre-releases published to
16
+ > [PyPI](https://pypi.org/project/wrapture-instrumentation-mysql/),
17
+ > and until 1.0.0 is final a plain `pip install
18
+ > wrapture-instrumentation-mysql` picks up the latest pre-release
19
+ > automatically, so there is no need to pin a specific version.
20
+
21
+ ## Why a separate package
22
+
23
+ The core
24
+ [wrapture-instrumentation](https://github.com/GrahamDumpleton/wrapture-instrumentation)
25
+ package deliberately covers only the standard library and third-party
26
+ packages that can be exercised in-process, with no separate backend
27
+ product or service needed to test against. A MySQL driver is exactly
28
+ the kind of target the separate-package rule was drawn for: its tests
29
+ need a real server, so this package's suite runs one in a docker
30
+ container, and it carries the drivers as test dependencies (one of
31
+ them built from source against a MySQL client library) and its own
32
+ release cadence, so the core package's test matrix stays light. One
33
+ package covers every client library for the one backend.
34
+
35
+ ## Installation
36
+
37
+ ```console
38
+ $ pip install wrapture-instrumentation-mysql
39
+ ```
40
+
41
+ Installing it brings wrapture and nothing else. No driver is a
42
+ dependency: each instrumentation is inert until its driver is present,
43
+ and wrapture checks the installed version against the range the
44
+ instrumentation supports at apply time.
45
+
46
+ ## Using it
47
+
48
+ An `[[instrument]]` entry in `wrapture.toml` names the target:
49
+
50
+ ```toml
51
+ [[instrument]]
52
+ name = "pymysql"
53
+
54
+ [[sink]]
55
+ type = "printer"
56
+ ```
57
+
58
+ and the runner applies it before the application starts, so the patch
59
+ is in place before the driver is imported:
60
+
61
+ ```console
62
+ $ python -m wrapture -m myapp
63
+ ```
64
+
65
+ The same config works through
66
+ [autowrapt](https://github.com/GrahamDumpleton/autowrapt) injection
67
+ (`AUTOWRAPT_BOOTSTRAP=wrapture python myapp.py`); through
68
+ [manual setup](https://wrapture.readthedocs.io/en/latest/manual-setup.html),
69
+ a few lines in the application's own startup where wrapping the launch
70
+ from outside is awkward; and, in a test, through
71
+ `wrapture.instrumentation("pymysql")` scoping the instrumentation to
72
+ a block. The
73
+ [ad-hoc tracing guide](https://wrapture.readthedocs.io/en/latest/ad-hoc-tracing.html)
74
+ covers the config file itself.
75
+
76
+ To see what is installed, what it supports in the current
77
+ environment, and what settings it takes:
78
+
79
+ ```console
80
+ $ python -m wrapture.tools instrumentation --verbose
81
+ ```
82
+
83
+ ## Provided instrumentation
84
+
85
+ | Target | Supported versions | Records | Settings |
86
+ | ------ | ------------------ | ------- | -------- |
87
+ | [`pymysql`](https://github.com/GrahamDumpleton/wrapture-instrumentation-mysql/blob/develop/src/wrapture_instrumentation_mysql/pymysql/README.md) | PyMySQL 1.1.1+ (1.x) | Every query as one `database` leaf, however it was issued (a cursor's `execute`, `executemany` or `callproc`, through whichever cursor class the application chose), plus the connection being opened and each transaction boundary the connection performs itself (`begin`, `commit`, `rollback`). Each event carries the system, the operation, and the database, host and port it reached; a failing statement records the driver's exception. The SQL text (the template with its placeholders) is recorded only with the `statement` setting on, bound parameters never. | `statement` |
88
+ | [`MySQLdb`](https://github.com/GrahamDumpleton/wrapture-instrumentation-mysql/blob/develop/src/wrapture_instrumentation_mysql/mysqldb/README.md) | mysqlclient 2.2.1+ (2.x), imported as `MySQLdb` | The same shapes through mysqlclient: every query as one `database` leaf (`execute`, `executemany`, `callproc`, through every cursor class), the connection being opened, and `begin`, `commit` and `rollback`, the last two bound over the C core's own methods. Each event carries the system, the operation, and the host and port it reached, plus the database from mysqlclient 2.2.7 on (earlier versions do not keep it); a failing statement records the driver's exception. The SQL text (the template with its placeholders) is recorded only with the `statement` setting on, bound parameters never. | `statement` |
89
+ | [`aiomysql`](https://github.com/GrahamDumpleton/wrapture-instrumentation-mysql/blob/develop/src/wrapture_instrumentation_mysql/aiomysql/README.md) | aiomysql 0.2+ (0.x) | The same shapes through aiomysql, each event recorded around its await: every query as one `database` leaf (`execute`, `executemany`, `callproc`, through every cursor class), the connection being opened (from a pool too), and `begin`, `commit` and `rollback`. Each event carries the system, the operation, and the database, host and port it reached; a failing statement records the driver's exception. The SQL text (the template with its placeholders) is recorded only with the `statement` setting on, bound parameters never. | `statement` |
90
+
91
+ The entry point name is the config's `name`, and is the import name
92
+ of the package the instrumentation patches (so mysqlclient's is
93
+ `MySQLdb`); the linked per-target README is the full user
94
+ documentation: what records, what the events carry, the setting, and
95
+ what is deliberately not traced.
96
+
97
+ ## What is not traced
98
+
99
+ By design, and where it goes:
100
+
101
+ - Fetching rows: a query event closes when its execute returns, so
102
+ time spent iterating rows afterwards is the application's. An
103
+ unbuffered cursor (`SSCursor`) therefore records the send and the
104
+ wait for the first packet, not the streaming of the rows.
105
+
106
+ - The connection's context manager: in these drivers leaving a
107
+ `with connection:` block closes the connection and performs no
108
+ commit or rollback, so it is not a transaction boundary and records
109
+ nothing. The explicit `commit()` and `rollback()` calls do.
110
+
111
+ - Mode changes and housekeeping (`autocommit()`, `select_db()`,
112
+ `ping()`, `set_character_set()`, `show_warnings()`): not database
113
+ operations in the sense the events record.
114
+
115
+ - Pool bookkeeping (aiomysql): taking a connection from a pool and
116
+ returning it are not database operations; the connections the pool
117
+ opens do record.
118
+
119
+ - `LOAD DATA LOCAL INFILE` records as a statement like any other; the
120
+ file's contents never do.
121
+
122
+ ## Testing against a server
123
+
124
+ The test suite drives the real drivers against a real MySQL server.
125
+ `WRAPTURE_MYSQL_URL` in the environment names one
126
+ (`mysql://user:password@host:port/database`); without it the suite
127
+ runs a throwaway `mysql:8.4` container itself, which needs Docker
128
+ Desktop or another docker daemon. With neither it fails rather than
129
+ skips. The mysqlclient driver builds from source against a MySQL
130
+ client library, so its suite runs inside a docker container that
131
+ carries the toolchain (`just test-docker`), and a plain native run
132
+ skips that one suite visibly rather than asking for a client library
133
+ on the machine. [TESTING.md](TESTING.md) covers the details, including how
134
+ the suite copes with MySQL 8's `caching_sha2_password` authentication
135
+ (the readiness probe's first connection warms the server's credential
136
+ cache, after which every driver connects plainly; a real application
137
+ on a cold cache over a plain socket needs the driver's own RSA or TLS
138
+ option, which is the driver's concern, not the instrumentation's).
139
+
140
+ ## Adding a target
141
+
142
+ Each client library is its own subpackage and entry point here. The
143
+ subpackage's `__init__.py` holds one `wrapture.Instrumentation`
144
+ subclass and imports only wrapture (and the package's own `common.py`,
145
+ which imports only wrapture too); everything that touches the driver
146
+ lives in sibling modules imported inside the hook. The class is
147
+ registered in `pyproject.toml` under
148
+ `[project.entry-points."wrapture.instrumentation"]`, and gets its own
149
+ test suite under `tests/<target>/` and a `README.md` linked from the
150
+ table above. The
151
+ [instrumentation packages](https://wrapture.readthedocs.io/en/latest/instrumentation-packages.html)
152
+ page of the wrapture documentation is the full contract; TESTING.md
153
+ here covers the tests and the server they run against.
154
+
155
+ ## License
156
+
157
+ BSD 2-Clause. See
158
+ [LICENSE](https://github.com/GrahamDumpleton/wrapture-instrumentation-mysql/blob/develop/LICENSE).