From 281c301512576a39738025e5200be5697340d127 Mon Sep 17 00:00:00 2001 From: Nenad Noveljic <18366081+nenadnoveljic@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:25:11 +0200 Subject: [PATCH] linster --- .../datadog_checks/sqlserver/deadlocks.py | 30 ++++++++--------- sqlserver/datadog_checks/sqlserver/queries.py | 4 ++- sqlserver/tests/test_deadlocks.py | 32 +++++++++++++------ 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/sqlserver/datadog_checks/sqlserver/deadlocks.py b/sqlserver/datadog_checks/sqlserver/deadlocks.py index 7e1da376f3e45..2360ce41c4c31 100644 --- a/sqlserver/datadog_checks/sqlserver/deadlocks.py +++ b/sqlserver/datadog_checks/sqlserver/deadlocks.py @@ -28,6 +28,7 @@ PAYLOAD_QUERY_SIGNATURE = "query_signatures" PAYLOAD_XML = "xml" + def agent_check_getter(self): return self._check @@ -54,11 +55,10 @@ def __init__(self, check, config: SQLServerConfig): shutdown_callback=self._close_db_conn, ) self._conn_key_prefix = "dbm-deadlocks-" - + def _close_db_conn(self): pass - def obfuscate_no_except_wrapper(self, sql_text): try: sql_text = obfuscate_sql_with_metadata( @@ -93,12 +93,12 @@ def _obfuscate_xml(self, root): continue query_signatures.append({"spid": spid, "signature": compute_sql_signature(inputbuf.text)}) else: - self._log.error("spid not found in process element. Skipping query signature computation.") + self._log.error("spid not found in process element. Skipping query signature computation.") for frame in process.findall('.//frame'): if frame.text is not None: frame.text = self.obfuscate_no_except_wrapper(frame.text) return query_signatures - + def _query_deadlocks(self): with self._check.connection.open_managed_default_connection(key_prefix=self._conn_key_prefix): with self._check.connection.get_managed_cursor(key_prefix=self._conn_key_prefix) as cursor: @@ -109,12 +109,9 @@ def _query_deadlocks(self): self._max_deadlocks, self._last_deadlock_timestamp, ) - cursor.execute( - DEADLOCK_QUERY, (self._max_deadlocks, min(-60, self._last_deadlock_timestamp - time())) - ) + cursor.execute(DEADLOCK_QUERY, (self._max_deadlocks, min(-60, self._last_deadlock_timestamp - time()))) columns = [column[0] for column in cursor.description] return [dict(zip(columns, row)) for row in cursor.fetchall()] - def _create_deadlock_rows(self): db_rows = self._query_deadlocks() @@ -138,7 +135,7 @@ def _create_deadlock_rows(self): error = "An error occurred while obfuscating SQLServer deadlocks. The error: {}".format(e) self._log.error(error) continue - + total_number_of_characters += len(row) + len(query_signatures) if total_number_of_characters > self._deadlock_payload_max_bytes: self._log.warning( @@ -149,11 +146,13 @@ def _create_deadlock_rows(self): ) break - deadlock_events.append({ - PAYLOAD_TIMESTAMP: row[DEADLOCK_TIMESTAMP_ALIAS], - PAYLOAD_XML: ET.tostring(root, encoding='unicode'), - PAYLOAD_QUERY_SIGNATURE: query_signatures - }) + deadlock_events.append( + { + PAYLOAD_TIMESTAMP: row[DEADLOCK_TIMESTAMP_ALIAS], + PAYLOAD_XML: ET.tostring(root, encoding='unicode'), + PAYLOAD_QUERY_SIGNATURE: query_signatures, + } + ) self._last_deadlock_timestamp = time() return deadlock_events @@ -182,7 +181,6 @@ def _create_deadlock_event(self, deadlock_rows): "sqlserver_deadlocks": deadlock_rows, } return event - + def run_job(self): self.collect_deadlocks() - diff --git a/sqlserver/datadog_checks/sqlserver/queries.py b/sqlserver/datadog_checks/sqlserver/queries.py index cbcf580665b9a..48b27d812e87f 100644 --- a/sqlserver/datadog_checks/sqlserver/queries.py +++ b/sqlserver/datadog_checks/sqlserver/queries.py @@ -227,7 +227,9 @@ ) AS XML_Data CROSS APPLY Target_Data.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS XEventData(xdr) WHERE xdr.value('@timestamp', 'datetime') >= DATEADD(SECOND, ?, GETDATE()) -;""".format(**{"timestamp": DEADLOCK_TIMESTAMP_ALIAS, "xml": DEADLOCK_XML_ALIAS}) +;""".format( + **{"timestamp": DEADLOCK_TIMESTAMP_ALIAS, "xml": DEADLOCK_XML_ALIAS} +) def get_query_ao_availability_groups(sqlserver_major_version): diff --git a/sqlserver/tests/test_deadlocks.py b/sqlserver/tests/test_deadlocks.py index 448f2bac7ab59..5be07acc3e95c 100644 --- a/sqlserver/tests/test_deadlocks.py +++ b/sqlserver/tests/test_deadlocks.py @@ -13,7 +13,13 @@ from copy import copy, deepcopy from datadog_checks.sqlserver import SQLServer -from datadog_checks.sqlserver.deadlocks import Deadlocks, MAX_PAYLOAD_BYTES, PAYLOAD_QUERY_SIGNATURE, PAYLOAD_TIMESTAMP, PAYLOAD_XML +from datadog_checks.sqlserver.deadlocks import ( + Deadlocks, + MAX_PAYLOAD_BYTES, + PAYLOAD_QUERY_SIGNATURE, + PAYLOAD_TIMESTAMP, + PAYLOAD_XML, +) from datadog_checks.sqlserver.queries import DEADLOCK_TIMESTAMP_ALIAS, DEADLOCK_XML_ALIAS from mock import patch, MagicMock from threading import Event @@ -25,6 +31,7 @@ except ImportError: pyodbc = None + @pytest.fixture def dbm_instance(instance_docker): instance_docker['dbm'] = True @@ -39,6 +46,7 @@ def dbm_instance(instance_docker): instance_docker['deadlocks_collection'] = {'enabled': True, 'collection_interval': 0.1} return copy(instance_docker) + def run_check_and_return_deadlock_payloads(dd_run_check, check, aggregator): dd_run_check(check) dbm_activity = aggregator.get_event_platform_events("dbm-activity") @@ -58,6 +66,7 @@ def _get_conn_for_user(instance_docker, user, timeout=1, _autocommit=False): conn.timeout = timeout return conn + def _run_first_deadlock_query(conn, event1, event2): exception_text = "" try: @@ -103,7 +112,6 @@ def _create_deadlock(bob_conn, fred_conn): return "deadlock" in exception_1_text or "deadlock" in exception_2_text - @pytest.mark.integration @pytest.mark.usefixtures('dd_environment') def test_deadlocks(aggregator, dd_run_check, init_config, dbm_instance): @@ -163,12 +171,15 @@ def test_deadlocks(aggregator, dd_run_check, init_config, dbm_instance): logging.error("deadlock XML: %s", str(d)) raise e + DEADLOCKS_PLAN_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "deadlocks") + def _load_test_deadlocks_xml(filename): with open(os.path.join(DEADLOCKS_PLAN_DIR, filename), 'r') as f: return f.read() - + + @pytest.fixture def deadlocks_collection_instance(instance_docker): instance_docker['dbm'] = True @@ -184,11 +195,16 @@ def deadlocks_collection_instance(instance_docker): instance_docker['collect_settings'] = {'enabled': False} return copy(instance_docker) + def test__create_deadlock_rows(deadlocks_collection_instance): check = SQLServer(CHECK_NAME, {}, [deadlocks_collection_instance]) deadlocks_obj = check.deadlocks xml = _load_test_deadlocks_xml("sqlserver_deadlock_event.xml") - with patch.object(Deadlocks, '_query_deadlocks', return_value=[{DEADLOCK_TIMESTAMP_ALIAS: "2024-09-20T12:07:16.647000", DEADLOCK_XML_ALIAS: xml}]): + with patch.object( + Deadlocks, + '_query_deadlocks', + return_value=[{DEADLOCK_TIMESTAMP_ALIAS: "2024-09-20T12:07:16.647000", DEADLOCK_XML_ALIAS: xml}], + ): rows = deadlocks_obj._create_deadlock_rows() assert len(rows) == 1, "Should have created one deadlock row" row = rows[0] @@ -198,7 +214,8 @@ def test__create_deadlock_rows(deadlocks_collection_instance): first_mapping = query_signatures[0] assert "spid" in first_mapping, "Should have spid in query signatures" assert isinstance(first_mapping["spid"], int), "spid should be an int" - + + def test_deadlock_xml_bad_format(deadlocks_collection_instance): test_xml = """ @@ -289,9 +306,7 @@ def test_deadlock_calls_obfuscator(deadlocks_collection_instance): "" ) - with patch( - 'datadog_checks.sqlserver.deadlocks.Deadlocks.obfuscate_no_except_wrapper', return_value="obfuscated" - ): + with patch('datadog_checks.sqlserver.deadlocks.Deadlocks.obfuscate_no_except_wrapper', return_value="obfuscated"): check = SQLServer(CHECK_NAME, {}, [deadlocks_collection_instance]) deadlocks_obj = check.deadlocks root = ET.fromstring(test_xml) @@ -300,4 +315,3 @@ def test_deadlock_calls_obfuscator(deadlocks_collection_instance): result_string = result_string.replace('\t', '').replace('\n', '') result_string = re.sub(r'\s{2,}', ' ', result_string) assert expected_xml_string == result_string -