Skip to content

Commit

Permalink
linster
Browse files Browse the repository at this point in the history
  • Loading branch information
nenadnoveljic committed Sep 23, 2024
1 parent 4a2ca6b commit 281c301
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 26 deletions.
30 changes: 14 additions & 16 deletions sqlserver/datadog_checks/sqlserver/deadlocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
PAYLOAD_QUERY_SIGNATURE = "query_signatures"
PAYLOAD_XML = "xml"


def agent_check_getter(self):
return self._check

Expand All @@ -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(
Expand Down Expand Up @@ -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:
Expand All @@ -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()
Expand All @@ -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(
Expand All @@ -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

Expand Down Expand Up @@ -182,7 +181,6 @@ def _create_deadlock_event(self, deadlock_rows):
"sqlserver_deadlocks": deadlock_rows,
}
return event

def run_job(self):
self.collect_deadlocks()

4 changes: 3 additions & 1 deletion sqlserver/datadog_checks/sqlserver/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
32 changes: 23 additions & 9 deletions sqlserver/tests/test_deadlocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -25,6 +31,7 @@
except ImportError:
pyodbc = None


@pytest.fixture
def dbm_instance(instance_docker):
instance_docker['dbm'] = True
Expand All @@ -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")
Expand All @@ -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:
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand All @@ -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]
Expand All @@ -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 = """
<event name="xml_deadlock_report" package="sqlserver" timestamp="2024-08-20T08:30:35.762Z">
Expand Down Expand Up @@ -289,9 +306,7 @@ def test_deadlock_calls_obfuscator(deadlocks_collection_instance):
"</event>"
)

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)
Expand All @@ -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

0 comments on commit 281c301

Please sign in to comment.