From f59d4a7e69133edc9d635e6c7e9d07b508a536ac Mon Sep 17 00:00:00 2001 From: Nenad Noveljic <18366081+nenadnoveljic@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:26:13 +0100 Subject: [PATCH] Take the signature of the top statement on the stack for deadlock payload (#19142) * relnote * relnote * rename the changelog file * linter --- sqlserver/changelog.d/19142.fixed | 1 + .../datadog_checks/sqlserver/deadlocks.py | 43 ++++++++++++------- 2 files changed, 28 insertions(+), 16 deletions(-) create mode 100644 sqlserver/changelog.d/19142.fixed diff --git a/sqlserver/changelog.d/19142.fixed b/sqlserver/changelog.d/19142.fixed new file mode 100644 index 0000000000000..e04ecf292d982 --- /dev/null +++ b/sqlserver/changelog.d/19142.fixed @@ -0,0 +1 @@ +Fix poor query signature correlation for deadlocks. diff --git a/sqlserver/datadog_checks/sqlserver/deadlocks.py b/sqlserver/datadog_checks/sqlserver/deadlocks.py index f66766d392b57..6c6d6d0cca8c3 100644 --- a/sqlserver/datadog_checks/sqlserver/deadlocks.py +++ b/sqlserver/datadog_checks/sqlserver/deadlocks.py @@ -34,6 +34,7 @@ PAYLOAD_XML = "xml" NO_XE_SESSION_ERROR = f"No XE session `{XE_SESSION_DATADOG}` found" +OBFUSCATION_ERROR = "ERROR: failed to obfuscate" def agent_check_getter(self): @@ -74,7 +75,7 @@ def obfuscate_no_except_wrapper(self, sql_text): sql_text, self._config.obfuscator_options, replace_null_character=True )['query'] except Exception as e: - sql_text = "ERROR: failed to obfuscate" + sql_text = OBFUSCATION_ERROR error_text = "Failed to obfuscate sql text within a deadlock" if self._config.log_unobfuscated_queries: error_text += "=[%s]" % sql_text @@ -88,24 +89,34 @@ def _obfuscate_xml(self, root): raise Exception("process-list element not found. The deadlock XML is in an unexpected format.") query_signatures = [] for process in process_list.findall('process'): + spid = process.get('spid') + if spid is not None: + try: + spid = int(spid) + except ValueError: + self._log.error("spid not an integer. Skipping query signature computation.") + continue + if spid in query_signatures: + continue + else: + self._log.error("spid not found in process element. Skipping query signature computation.") + + # Setting `signature` for the first function on the stack + signature = None + for frame in process.findall('.//frame'): + if frame.text is not None and frame.text != "unknown": + frame.text = self.obfuscate_no_except_wrapper(frame.text) + if signature is not None and frame.text != OBFUSCATION_ERROR: + signature = compute_sql_signature(frame.text) + for inputbuf in process.findall('.//inputbuf'): if inputbuf.text is not None: inputbuf.text = self.obfuscate_no_except_wrapper(inputbuf.text) - spid = process.get('spid') - if spid is not None: - try: - spid = int(spid) - except ValueError: - self._log.error("spid not an integer. Skipping query signature computation.") - continue - if spid in query_signatures: - 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.") - for frame in process.findall('.//frame'): - if frame.text is not None: - frame.text = self.obfuscate_no_except_wrapper(frame.text) + if signature is None and inputbuf.text != OBFUSCATION_ERROR: + signature = compute_sql_signature(inputbuf.text) + + query_signatures.append({"spid": spid, "signature": signature}) + return query_signatures def _get_lookback_seconds(self):