28
28
29
29
"""MySQL instrumentation supporting mysql-connector."""
30
30
# mypy: disable-error-code="no-redef"
31
- # pylint: disable=protected-access,global-statement,invalid-name
31
+ # pylint: disable=protected-access,global-statement,invalid-name,unused-argument
32
32
33
33
from __future__ import annotations
34
34
48
48
# is a circular import issue when there isn't.
49
49
50
50
from ..abstracts import MySQLConnectionAbstract , MySQLCursorAbstract
51
- from ..connection import MySQLConnection
52
51
from ..pooling import PooledMySQLConnection
53
52
54
- try :
55
- from ..connection_cext import CMySQLConnection
56
- except ImportError :
57
- # The cext is not available.
58
- pass
59
-
60
53
from ... import connector
61
54
from ..constants import CNX_POOL_ARGS , DEFAULT_CONFIGURATION
62
55
from ..logger import logger
@@ -214,12 +207,10 @@ def set_connection_span_attrs(
214
207
cnx_span .set_attributes (attrs )
215
208
216
209
217
- def with_connection_span_attached (method : Callable ) -> Callable :
218
- """Attach the connection span while executing a connection method."""
210
+ def with_cnx_span_attached (method : Callable ) -> Callable :
211
+ """Attach the connection span while executing the connection method."""
219
212
220
- def wrapper (
221
- cnx : Union ["MySQLConnection" , "CMySQLConnection" ], * args : Any , ** kwargs : Any
222
- ) -> Any :
213
+ def wrapper (cnx : "MySQLConnectionAbstract" , * args : Any , ** kwargs : Any ) -> Any :
223
214
"""Connection span attacher decorator."""
224
215
with trace .use_span (
225
216
cnx ._span , end_on_exit = False
@@ -229,41 +220,62 @@ def wrapper(
229
220
return wrapper
230
221
231
222
232
- def _instrument_execution (
233
- query_method : Callable ,
234
- tracer : trace .Tracer ,
235
- connection_span_link : trace .Link ,
236
- wrapped : "MySQLCursorAbstract" ,
237
- * args : Any ,
238
- ** kwargs : Any ,
239
- ) -> Callable :
240
- """Instruments the execution of `query_method`.
223
+ def with_cnx_query_span (method : Callable ) -> Callable :
224
+ """Create a query span while executing the connection method."""
241
225
242
- A query span with a link to the corresponding connection span is generated.
243
- """
244
- connection : Union ["MySQLConnection" , "CMySQLConnection" ] = (
245
- getattr (wrapped , "_connection" )
246
- if hasattr (wrapped , "_connection" )
247
- else getattr (wrapped , "_cnx" )
248
- )
249
-
250
- # SpanAttributes.DB_NAME: connection.database or ""; introduces performance
251
- # degradation, at this time the database attribute is something nice to have but
252
- # not a requirement.
253
- query_span_attributes : Dict = {
254
- SpanAttributes .DB_SYSTEM : DB_SYSTEM ,
255
- SpanAttributes .DB_USER : connection ._user ,
256
- SpanAttributes .THREAD_ID : DEFAULT_THREAD_ID ,
257
- SpanAttributes .THREAD_NAME : DEFAULT_THREAD_NAME ,
258
- "cursor_type" : wrapped .__class__ .__name__ ,
259
- }
260
- with tracer .start_as_current_span (
261
- name = get_operation_name (args [0 ]) or "SQL statement" ,
262
- kind = trace .SpanKind .CLIENT ,
263
- links = [connection_span_link ],
264
- attributes = query_span_attributes ,
265
- ):
266
- return query_method (* args , ** kwargs )
226
+ def wrapper (cnx : TracedMySQLConnection , * args : Any , ** kwargs : Any ) -> Any :
227
+ """Query span creator decorator."""
228
+ logger .info ("Creating query span for connection.%s" , method .__name__ )
229
+
230
+ query_span_attributes : Dict = {
231
+ SpanAttributes .DB_SYSTEM : DB_SYSTEM ,
232
+ SpanAttributes .DB_USER : cnx ._user ,
233
+ SpanAttributes .THREAD_ID : DEFAULT_THREAD_ID ,
234
+ SpanAttributes .THREAD_NAME : DEFAULT_THREAD_NAME ,
235
+ "connection_type" : cnx .get_wrapped_class (),
236
+ }
237
+
238
+ with cnx ._tracer .start_as_current_span (
239
+ name = method .__name__ .upper (),
240
+ kind = trace .SpanKind .CLIENT ,
241
+ links = [trace .Link (cnx ._span .get_span_context ())],
242
+ attributes = query_span_attributes ,
243
+ ) if cnx ._span and cnx ._span .is_recording () else nullcontext ():
244
+ return method (cnx , * args , ** kwargs )
245
+
246
+ return wrapper
247
+
248
+
249
+ def with_cursor_query_span (method : Callable ) -> Callable :
250
+ """Create a query span while executing the cursor method."""
251
+
252
+ def wrapper (cur : TracedMySQLCursor , * args : Any , ** kwargs : Any ) -> Any :
253
+ """Query span creator decorator."""
254
+ logger .info ("Creating query span for cursor.%s" , method .__name__ )
255
+
256
+ connection : "MySQLConnectionAbstract" = (
257
+ getattr (cur ._wrapped , "_connection" )
258
+ if hasattr (cur ._wrapped , "_connection" )
259
+ else getattr (cur ._wrapped , "_cnx" )
260
+ )
261
+
262
+ query_span_attributes : Dict = {
263
+ SpanAttributes .DB_SYSTEM : DB_SYSTEM ,
264
+ SpanAttributes .DB_USER : connection ._user ,
265
+ SpanAttributes .THREAD_ID : DEFAULT_THREAD_ID ,
266
+ SpanAttributes .THREAD_NAME : DEFAULT_THREAD_NAME ,
267
+ "cursor_type" : cur .get_wrapped_class (),
268
+ }
269
+
270
+ with cur ._tracer .start_as_current_span (
271
+ name = get_operation_name (args [0 ]) or "SQL statement" ,
272
+ kind = trace .SpanKind .CLIENT ,
273
+ links = [cur ._connection_span_link ],
274
+ attributes = query_span_attributes ,
275
+ ):
276
+ return method (cur , * args , ** kwargs )
277
+
278
+ return wrapper
267
279
268
280
269
281
class BaseMySQLTracer (ABC ):
@@ -291,7 +303,7 @@ def __setattr__(self, name: str, value: Any) -> None:
291
303
self .__dict__ ["_wrapped" ] = value
292
304
return
293
305
294
- if name in self .__dict__ :
306
+ if name in self .__dict__ or name == "autocommit" :
295
307
# this object has it
296
308
super ().__setattr__ (name , value )
297
309
return
@@ -328,38 +340,20 @@ def __init__(
328
340
connection_span .get_span_context ()
329
341
)
330
342
343
+ @with_cursor_query_span
331
344
def execute (self , * args : Any , ** kwargs : Any ) -> Any :
332
- """Instruments execute method."""
333
- return _instrument_execution (
334
- self ._wrapped .execute ,
335
- self ._tracer ,
336
- self ._connection_span_link ,
337
- self ._wrapped ,
338
- * args ,
339
- ** kwargs ,
340
- )
345
+ """Instrument method."""
346
+ return self ._wrapped .execute (* args , ** kwargs )
341
347
348
+ @with_cursor_query_span
342
349
def executemany (self , * args : Any , ** kwargs : Any ) -> Any :
343
- """Instruments executemany method."""
344
- return _instrument_execution (
345
- self ._wrapped .executemany ,
346
- self ._tracer ,
347
- self ._connection_span_link ,
348
- self ._wrapped ,
349
- * args ,
350
- ** kwargs ,
351
- )
350
+ """Instrument method."""
351
+ return self ._wrapped .executemany (* args , ** kwargs )
352
352
353
+ @with_cursor_query_span
353
354
def callproc (self , * args : Any , ** kwargs : Any ) -> Any :
354
- """Instruments callproc method."""
355
- return _instrument_execution (
356
- self ._wrapped .callproc ,
357
- self ._tracer ,
358
- self ._connection_span_link ,
359
- self ._wrapped ,
360
- * args ,
361
- ** kwargs ,
362
- )
355
+ """Instrument method."""
356
+ return self ._wrapped .callproc (* args , ** kwargs )
363
357
364
358
365
359
class TracedMySQLConnection (BaseMySQLTracer ):
@@ -381,11 +375,156 @@ def cursor(self, *args: Any, **kwargs: Any) -> TracedMySQLCursor:
381
375
connection_span = self ._span ,
382
376
)
383
377
384
- @with_connection_span_attached
378
+ @with_cnx_query_span
385
379
def cmd_change_user (self , * args : Any , ** kwargs : Any ) -> Any :
386
- """Wraps the object method."""
380
+ """Instrument method."""
387
381
return self ._wrapped .cmd_change_user (* args , ** kwargs )
388
382
383
+ @with_cnx_query_span
384
+ def commit (self , * args : Any , ** kwargs : Any ) -> Any :
385
+ """Instrument method."""
386
+ return self ._wrapped .commit (* args , ** kwargs )
387
+
388
+ @with_cnx_query_span
389
+ def rollback (self , * args : Any , ** kwargs : Any ) -> Any :
390
+ """Instrument method."""
391
+ return self ._wrapped .rollback (* args , ** kwargs )
392
+
393
+ @with_cnx_query_span
394
+ def cmd_query (self , * args : Any , ** kwargs : Any ) -> Any :
395
+ """Instrument method."""
396
+ return self ._wrapped .cmd_query (* args , ** kwargs )
397
+
398
+ @with_cnx_query_span
399
+ def cmd_init_db (self , * args : Any , ** kwargs : Any ) -> Any :
400
+ """Instrument method."""
401
+ return self ._wrapped .cmd_init_db (* args , ** kwargs )
402
+
403
+ @with_cnx_query_span
404
+ def cmd_refresh (self , * args : Any , ** kwargs : Any ) -> Any :
405
+ """Instrument method."""
406
+ return self ._wrapped .cmd_refresh (* args , ** kwargs )
407
+
408
+ @with_cnx_query_span
409
+ def cmd_quit (self , * args : Any , ** kwargs : Any ) -> Any :
410
+ """Instrument method."""
411
+ return self ._wrapped .cmd_quit (* args , ** kwargs )
412
+
413
+ @with_cnx_query_span
414
+ def cmd_shutdown (self , * args : Any , ** kwargs : Any ) -> Any :
415
+ """Instrument method."""
416
+ return self ._wrapped .cmd_shutdown (* args , ** kwargs )
417
+
418
+ @with_cnx_query_span
419
+ def cmd_statistics (self , * args : Any , ** kwargs : Any ) -> Any :
420
+ """Instrument method."""
421
+ return self ._wrapped .cmd_statistics (* args , ** kwargs )
422
+
423
+ @with_cnx_query_span
424
+ def cmd_process_kill (self , * args : Any , ** kwargs : Any ) -> Any :
425
+ """Instrument method."""
426
+ return self ._wrapped .cmd_process_kill (* args , ** kwargs )
427
+
428
+ @with_cnx_query_span
429
+ def cmd_debug (self , * args : Any , ** kwargs : Any ) -> Any :
430
+ """Instrument method."""
431
+ return self ._wrapped .cmd_debug (* args , ** kwargs )
432
+
433
+ @with_cnx_query_span
434
+ def cmd_ping (self , * args : Any , ** kwargs : Any ) -> Any :
435
+ """Instrument method."""
436
+ return self ._wrapped .cmd_ping (* args , ** kwargs )
437
+
438
+ @property
439
+ @with_cnx_query_span
440
+ def database (self , * args : Any , ** kwargs : Any ) -> str :
441
+ """Instrument method."""
442
+ return self ._wrapped .database
443
+
444
+ @with_cnx_query_span
445
+ def is_connected (self , * args : Any , ** kwargs : Any ) -> Any :
446
+ """Instrument method."""
447
+ return self ._wrapped .is_connected (* args , ** kwargs )
448
+
449
+ @with_cnx_query_span
450
+ def reset_session (self , * args : Any , ** kwargs : Any ) -> Any :
451
+ """Instrument method."""
452
+ return self ._wrapped .reset_session (* args , ** kwargs )
453
+
454
+ @with_cnx_query_span
455
+ def ping (self , * args : Any , ** kwargs : Any ) -> Any :
456
+ """Instrument method."""
457
+ return self ._wrapped .ping (* args , ** kwargs )
458
+
459
+ @with_cnx_query_span
460
+ def info_query (self , * args : Any , ** kwargs : Any ) -> Any :
461
+ """Instrument method."""
462
+ return self ._wrapped .info_query (* args , ** kwargs )
463
+
464
+ @with_cnx_query_span
465
+ def cmd_stmt_prepare (self , * args : Any , ** kwargs : Any ) -> Any :
466
+ """Instrument method."""
467
+ return self ._wrapped .cmd_stmt_prepare (* args , ** kwargs )
468
+
469
+ @with_cnx_query_span
470
+ def cmd_stmt_execute (self , * args : Any , ** kwargs : Any ) -> Any :
471
+ """Instrument method."""
472
+ return self ._wrapped .cmd_stmt_execute (* args , ** kwargs )
473
+
474
+ @with_cnx_query_span
475
+ def cmd_stmt_close (self , * args : Any , ** kwargs : Any ) -> Any :
476
+ """Instrument method."""
477
+ return self ._wrapped .cmd_stmt_close (* args , ** kwargs )
478
+
479
+ @with_cnx_query_span
480
+ def cmd_stmt_send_long_data (self , * args : Any , ** kwargs : Any ) -> Any :
481
+ """Instrument method."""
482
+ return self ._wrapped .cmd_stmt_send_long_data (* args , ** kwargs )
483
+
484
+ @with_cnx_query_span
485
+ def cmd_stmt_reset (self , * args : Any , ** kwargs : Any ) -> Any :
486
+ """Instrument method."""
487
+ return self ._wrapped .cmd_stmt_reset (* args , ** kwargs )
488
+
489
+ @with_cnx_query_span
490
+ def cmd_reset_connection (self , * args : Any , ** kwargs : Any ) -> Any :
491
+ """Instrument method."""
492
+ return self ._wrapped .cmd_reset_connection (* args , ** kwargs )
493
+
494
+ @property
495
+ @with_cnx_query_span
496
+ def time_zone (self , * args : Any , ** kwargs : Any ) -> str :
497
+ """Instrument method."""
498
+ return self ._wrapped .time_zone
499
+
500
+ @property
501
+ @with_cnx_query_span
502
+ def sql_mode (self , * args : Any , ** kwargs : Any ) -> str :
503
+ """Instrument method."""
504
+ return self ._wrapped .sql_mode
505
+
506
+ @property
507
+ @with_cnx_query_span
508
+ def autocommit (self , * args : Any , ** kwargs : Any ) -> bool :
509
+ """Instrument method."""
510
+ return self ._wrapped .autocommit
511
+
512
+ @autocommit .setter
513
+ @with_cnx_query_span
514
+ def autocommit (self , value : bool ) -> None :
515
+ """Instrument method."""
516
+ self ._wrapped .autocommit = value
517
+
518
+ @with_cnx_query_span
519
+ def set_charset_collation (self , * args : Any , ** kwargs : Any ) -> Any :
520
+ """Instrument method."""
521
+ return self ._wrapped .set_charset_collation (* args , ** kwargs )
522
+
523
+ @with_cnx_query_span
524
+ def start_transaction (self , * args : Any , ** kwargs : Any ) -> Any :
525
+ """Instrument method."""
526
+ return self ._wrapped .start_transaction (* args , ** kwargs )
527
+
389
528
390
529
def _instrument_connect (
391
530
connect : Callable [..., Union ["MySQLConnectionAbstract" , "PooledMySQLConnection" ]],
0 commit comments