Skip to content

Commit d83a5c4

Browse files
committed
Add mysql-connector instrumentor support for sqlcommenting (open-telemetry#3163)
1 parent 4b6cf60 commit d83a5c4

File tree

6 files changed

+483
-16
lines changed

6 files changed

+483
-16
lines changed

Diff for: CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5151
([#3206](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3206))
5252
- `opentelemetry-instrumentation-pymssql` Add pymssql instrumentation
5353
([#394](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/394))
54+
- `opentelemetry-instrumentation-mysql` Add sqlcommenter support
55+
([#3163](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3163))
5456

5557
### Fixed
5658

Diff for: instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,11 @@ def _update_args_with_added_sql_comment(self, args, cursor) -> tuple:
498498
args_list = list(args)
499499
self._capture_mysql_version(cursor)
500500
commenter_data = self._get_commenter_data()
501+
# Convert sql statement to string, handling psycopg2.sql.Composable object
502+
if hasattr(args_list[0], "as_string"):
503+
args_list[0] = args_list[0].as_string(cursor.connection)
504+
505+
args_list[0] = str(args_list[0])
501506
statement = _add_sql_comment(args_list[0], **commenter_data)
502507
args_list[0] = statement
503508
args = tuple(args_list)

Diff for: instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/middleware/sqlcommenter_middleware.py

+6
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ def __call__(self, execute: Type[T], sql, params, many, context) -> T:
8080
db_driver = context["connection"].settings_dict.get("ENGINE", "")
8181
resolver_match = self.request.resolver_match
8282

83+
# Convert sql statement to string, handling psycopg2.sql.Composable object
84+
if hasattr(sql, "as_string"):
85+
sql = sql.as_string(context["connection"])
86+
87+
sql = str(sql)
88+
8389
sql = _add_sql_comment(
8490
sql,
8591
# Information about the controller.

Diff for: instrumentation/opentelemetry-instrumentation-mysql/src/opentelemetry/instrumentation/mysql/__init__.py

+115-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,95 @@
5050
cursor.close()
5151
instrumented_cnx.close()
5252
53+
SQLCOMMENTER
54+
*****************************************
55+
You can optionally configure mysql-connector instrumentation to enable sqlcommenter which enriches the query with contextual information.
56+
57+
Usage
58+
-----
59+
60+
.. code:: python
61+
62+
import mysql.connector
63+
from opentelemetry.instrumentation.mysql import MySQLInstrumentor
64+
65+
MySQLInstrumentor().instrument(enable_commenter=True, commenter_options={})
66+
67+
cnx = mysql.connector.connect(database="MySQL_Database")
68+
cursor = cnx.cursor()
69+
cursor.execute("INSERT INTO test (testField) VALUES (123)")
70+
cursor.close()
71+
cnx.close()
72+
73+
74+
For example,
75+
::
76+
77+
Invoking cursor.execute("INSERT INTO test (testField) VALUES (123)") will lead to sql query "INSERT INTO test (testField) VALUES (123)" but when SQLCommenter is enabled
78+
the query will get appended with some configurable tags like "INSERT INTO test (testField) VALUES (123) /*tag=value*/;"
79+
80+
**WARNING:** sqlcommenter for mysql-connector instrumentation should NOT be used if your application initializes cursors with ``prepared=True``, which will natively prepare and execute MySQL statements. Adding sqlcommenting will introduce a severe performance penalty by repeating ``Prepare`` of statements by mysql-connector that are made unique by traceparent in sqlcomment. The penalty does not happen if cursor ``prepared=False`` (default) and instrumentor ``enable_commenter=True``.
81+
82+
SQLCommenter Configurations
83+
***************************
84+
We can configure the tags to be appended to the sqlquery log by adding configuration inside commenter_options(default:{}) keyword
85+
86+
db_driver = True(Default) or False
87+
88+
For example,
89+
::
90+
Enabling this flag will add mysql.connector and its version, e.g. /*mysql.connector%%3A1.2.3*/
91+
92+
dbapi_threadsafety = True(Default) or False
93+
94+
For example,
95+
::
96+
Enabling this flag will add threadsafety /*dbapi_threadsafety=2*/
97+
98+
dbapi_level = True(Default) or False
99+
100+
For example,
101+
::
102+
Enabling this flag will add dbapi_level /*dbapi_level='2.0'*/
103+
104+
mysql_client_version = True(Default) or False
105+
106+
For example,
107+
::
108+
Enabling this flag will add mysql_client_version /*mysql_client_version='123'*/
109+
110+
driver_paramstyle = True(Default) or False
111+
112+
For example,
113+
::
114+
Enabling this flag will add driver_paramstyle /*driver_paramstyle='pyformat'*/
115+
116+
opentelemetry_values = True(Default) or False
117+
118+
For example,
119+
::
120+
Enabling this flag will add traceparent values /*traceparent='00-03afa25236b8cd948fa853d67038ac79-405ff022e8247c46-01'*/
121+
122+
SQLComment in span attribute
123+
****************************
124+
If sqlcommenter is enabled, you can optionally configure mysql-connector instrumentation to append sqlcomment to query span attribute for convenience of your platform.
125+
126+
.. code:: python
127+
128+
from opentelemetry.instrumentation.mysql import MySQLInstrumentor
129+
130+
MySQLInstrumentor().instrument(
131+
enable_commenter=True,
132+
enable_attribute_commenter=True,
133+
)
134+
135+
136+
For example,
137+
::
138+
139+
Invoking cursor.execute("select * from auth_users") will lead to sql query "select * from auth_users" but when SQLCommenter and attribute_commenter are enabled
140+
the query will get appended with some configurable tags like "select * from auth_users /*tag=value*/;" for both server query and `db.statement` span attribute.
141+
53142
API
54143
---
55144
"""
@@ -82,6 +171,11 @@ def _instrument(self, **kwargs):
82171
https://dev.mysql.com/doc/connector-python/en/
83172
"""
84173
tracer_provider = kwargs.get("tracer_provider")
174+
enable_sqlcommenter = kwargs.get("enable_commenter", False)
175+
commenter_options = kwargs.get("commenter_options", {})
176+
enable_attribute_commenter = kwargs.get(
177+
"enable_attribute_commenter", False
178+
)
85179

86180
dbapi.wrap_connect(
87181
__name__,
@@ -91,14 +185,24 @@ def _instrument(self, **kwargs):
91185
self._CONNECTION_ATTRIBUTES,
92186
version=__version__,
93187
tracer_provider=tracer_provider,
188+
enable_commenter=enable_sqlcommenter,
189+
commenter_options=commenter_options,
190+
enable_attribute_commenter=enable_attribute_commenter,
94191
)
95192

96193
def _uninstrument(self, **kwargs):
97194
""" "Disable MySQL instrumentation"""
98195
dbapi.unwrap_connect(mysql.connector, "connect")
99196

100197
# pylint:disable=no-self-use
101-
def instrument_connection(self, connection, tracer_provider=None):
198+
def instrument_connection(
199+
self,
200+
connection,
201+
tracer_provider=None,
202+
enable_commenter=None,
203+
commenter_options=None,
204+
enable_attribute_commenter=None,
205+
):
102206
"""Enable instrumentation in a MySQL connection.
103207
104208
Args:
@@ -109,6 +213,12 @@ def instrument_connection(self, connection, tracer_provider=None):
109213
tracer_provider:
110214
An optional `TracerProvider` instance to use for tracing. If not provided, the globally
111215
configured tracer provider will be automatically used.
216+
enable_commenter:
217+
Optional flag to enable/disable sqlcommenter (default False).
218+
commenter_options:
219+
Optional configurations for tags to be appended at the sql query.
220+
enable_attribute_commenter:
221+
Optional flag to enable/disable addition of sqlcomment to span attribute (default False). Requires enable_commenter=True.
112222
113223
Returns:
114224
An instrumented MySQL connection with OpenTelemetry tracing enabled.
@@ -120,6 +230,10 @@ def instrument_connection(self, connection, tracer_provider=None):
120230
self._CONNECTION_ATTRIBUTES,
121231
version=__version__,
122232
tracer_provider=tracer_provider,
233+
enable_commenter=enable_commenter,
234+
commenter_options=commenter_options,
235+
connect_module=mysql.connector,
236+
enable_attribute_commenter=enable_attribute_commenter,
123237
)
124238

125239
def uninstrument_connection(self, connection):

0 commit comments

Comments
 (0)