Skip to content

Commit 340b6e1

Browse files
Add dbapi comment mysql_client_version fallback
1 parent fd21563 commit 340b6e1

File tree

2 files changed

+101
-3
lines changed

2 files changed

+101
-3
lines changed

instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -478,9 +478,24 @@ def _capture_mysql_version(self, cursor) -> None:
478478
"mysql_client_version"
479479
]
480480
):
481-
self._db_api_integration.commenter_data["mysql_client_version"] = (
482-
cursor._cnx._cmysql.get_client_info()
483-
)
481+
try:
482+
# Autoinstrumentation and some programmatic calls
483+
self._db_api_integration.commenter_data[
484+
"mysql_client_version"
485+
] = cursor._cnx._cmysql.get_client_info()
486+
except AttributeError:
487+
# Other programmatic instrumentation with reassigned wrapped connection
488+
try:
489+
self._db_api_integration.commenter_data[
490+
"mysql_client_version"
491+
] = cursor._connection._cmysql.get_client_info()
492+
except AttributeError as exc:
493+
_logger.error(
494+
"Could not set mysql_client_version: %s", exc
495+
)
496+
self._db_api_integration.commenter_data[
497+
"mysql_client_version"
498+
] = "unknown"
484499

485500
def _get_commenter_data(self) -> dict:
486501
"""Uses DB-API integration to return commenter data for sqlcomment"""

instrumentation/opentelemetry-instrumentation-dbapi/tests/test_dbapi_integration.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,89 @@ def test_non_string_sql_conversion(self):
11231123
spans_list = self.memory_exporter.get_finished_spans()
11241124
self.assertEqual(len(spans_list), 1)
11251125

1126+
def test_capture_mysql_version_primary_success(self):
1127+
connect_module = mock.MagicMock()
1128+
connect_module.__name__ = "mysql.connector"
1129+
connect_module.__version__ = "2.2.9"
1130+
db_integration = dbapi.DatabaseApiIntegration(
1131+
"instrumenting_module_test_name",
1132+
"mysql",
1133+
enable_commenter=True,
1134+
connect_module=connect_module,
1135+
)
1136+
mock_cursor = mock.MagicMock()
1137+
mock_cursor._cnx._cmysql.get_client_info.return_value = "8.0.32"
1138+
mock_connection = db_integration.wrapped_connection(
1139+
mock_connect, {}, {}
1140+
)
1141+
cursor = mock_connection.cursor()
1142+
cursor._cnx = mock_cursor._cnx
1143+
cursor.execute("SELECT 1;")
1144+
mock_cursor._cnx._cmysql.get_client_info.assert_called_once()
1145+
self.assertEqual(
1146+
db_integration.commenter_data["mysql_client_version"], "8.0.32"
1147+
)
1148+
1149+
def test_capture_mysql_version_fallback_success(self):
1150+
connect_module = mock.MagicMock()
1151+
connect_module.__name__ = "mysql.connector"
1152+
connect_module.__version__ = "2.2.9"
1153+
db_integration = dbapi.DatabaseApiIntegration(
1154+
"instrumenting_module_test_name",
1155+
"mysql",
1156+
enable_commenter=True,
1157+
connect_module=connect_module,
1158+
)
1159+
mock_cursor = mock.MagicMock()
1160+
mock_cursor._cnx._cmysql.get_client_info.side_effect = AttributeError(
1161+
"Primary method failed"
1162+
)
1163+
mock_cursor._connection._cmysql.get_client_info.return_value = "8.0.33"
1164+
mock_connection = db_integration.wrapped_connection(
1165+
mock_connect, {}, {}
1166+
)
1167+
cursor = mock_connection.cursor()
1168+
cursor._cnx = mock_cursor._cnx
1169+
cursor._connection = mock_cursor._connection
1170+
cursor.execute("SELECT 1;")
1171+
mock_cursor._cnx._cmysql.get_client_info.assert_called_once()
1172+
mock_cursor._connection._cmysql.get_client_info.assert_called_once()
1173+
self.assertEqual(
1174+
db_integration.commenter_data["mysql_client_version"], "8.0.33"
1175+
)
1176+
1177+
@mock.patch("opentelemetry.instrumentation.dbapi._logger")
1178+
def test_capture_mysql_version_fallback(self, mock_logger):
1179+
connect_module = mock.MagicMock()
1180+
connect_module.__name__ = "mysql.connector"
1181+
connect_module.__version__ = "2.2.9"
1182+
db_integration = dbapi.DatabaseApiIntegration(
1183+
"instrumenting_module_test_name",
1184+
"mysql",
1185+
enable_commenter=True,
1186+
connect_module=connect_module,
1187+
)
1188+
mock_cursor = mock.MagicMock()
1189+
mock_cursor._cnx._cmysql.get_client_info.side_effect = AttributeError(
1190+
"Primary method failed"
1191+
)
1192+
mock_cursor._connection._cmysql.get_client_info.side_effect = (
1193+
AttributeError("Fallback method failed")
1194+
)
1195+
mock_connection = db_integration.wrapped_connection(
1196+
mock_connect, {}, {}
1197+
)
1198+
cursor = mock_connection.cursor()
1199+
cursor._cnx = mock_cursor._cnx
1200+
cursor._connection = mock_cursor._connection
1201+
cursor.execute("SELECT 1;")
1202+
mock_cursor._cnx._cmysql.get_client_info.assert_called_once()
1203+
mock_cursor._connection._cmysql.get_client_info.assert_called_once()
1204+
mock_logger.error.assert_called_once()
1205+
self.assertEqual(
1206+
db_integration.commenter_data["mysql_client_version"], "unknown"
1207+
)
1208+
11261209

11271210
# pylint: disable=unused-argument
11281211
def mock_connect(*args, **kwargs):

0 commit comments

Comments
 (0)