Skip to content

Commit 370b3fa

Browse files
authored
[SQLServer] Filter query metrics by database_name if check is configured to a single non-master db (#17717)
* filter query metrics by database_name if monitoring is configured to single non-master db * add changelog * only filter unmonitored database on azure sql database
1 parent 976ca3b commit 370b3fa

File tree

3 files changed

+84
-1
lines changed

3 files changed

+84
-1
lines changed

sqlserver/changelog.d/17717.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Filter query metrics by database_name if check is configured to a single non-master db

sqlserver/datadog_checks/sqlserver/statements.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from datadog_checks.base.utils.serialization import json
2323
from datadog_checks.base.utils.tracking import tracked_method
2424
from datadog_checks.sqlserver.config import SQLServerConfig
25-
from datadog_checks.sqlserver.utils import extract_sql_comments_and_procedure_name
25+
from datadog_checks.sqlserver.utils import extract_sql_comments_and_procedure_name, is_azure_sql_database
2626

2727
try:
2828
import datadog_agent
@@ -304,10 +304,29 @@ def _load_raw_query_metrics_rows(self, cursor):
304304
self.log.debug("loaded sql server statement metrics len(rows)=%s", len(rows))
305305
return rows
306306

307+
def _should_include_query_metrics_row(self, row):
308+
if 'database_name' not in row:
309+
# Unaggregated query metrics row without a database name
310+
return True
311+
312+
engine_edition = self._check.static_info_cache.get(STATIC_INFO_ENGINE_EDITION, "")
313+
if is_azure_sql_database(engine_edition):
314+
configured_database = self._check.instance.get('database')
315+
if not configured_database or configured_database == 'master':
316+
# If no database configured or the configured database is master, include all rows
317+
return True
318+
if not row['database_name'] or str(row['database_name']).lower() != configured_database.lower():
319+
# If the row's database name does not match the configured database, exclude the row
320+
return False
321+
322+
return True
323+
307324
def _normalize_queries(self, rows):
308325
normalized_rows = []
309326

310327
for row in rows:
328+
if not self._should_include_query_metrics_row(row):
329+
continue
311330
# Attempt to obfuscate SQL statement with metadata
312331
procedure_statement = None
313332
try:

sqlserver/tests/test_statements.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
ENGINE_EDITION_ENTERPRISE,
2727
ENGINE_EDITION_EXPRESS,
2828
ENGINE_EDITION_PERSONAL,
29+
ENGINE_EDITION_SQL_DATABASE,
2930
ENGINE_EDITION_STANDARD,
31+
STATIC_INFO_ENGINE_EDITION,
3032
)
3133
from datadog_checks.sqlserver.statements import SQL_SERVER_QUERY_METRICS_COLUMNS, obfuscate_xml_plan
3234

@@ -1014,3 +1016,64 @@ def test_metrics_lookback_multiplier(instance_docker):
10141016

10151017
check.statement_metrics._load_raw_query_metrics_rows(mock_cursor)
10161018
mock_cursor.execute.assert_called_with(ANY, (6,))
1019+
1020+
1021+
@pytest.mark.integration
1022+
@pytest.mark.usefixtures('dd_environment')
1023+
@pytest.mark.parametrize(
1024+
"configured_database,engine_edition,filter_to_configured_database",
1025+
[
1026+
pytest.param(None, None, False, id="no_database_configured_not_azure_sql"), # should default to master
1027+
pytest.param(
1028+
"datadog_test", None, False, id="configured_database_datadog_test_not_azure_sql"
1029+
), # should not filter to configured database datadog_test
1030+
pytest.param(
1031+
"master", None, False, id="configured_database_master_not_azure_sql"
1032+
), # should use configured database master
1033+
pytest.param(
1034+
"datadog_test", ENGINE_EDITION_SQL_DATABASE, True, id="configured_database_datadog_test_azure_sql"
1035+
), # should filter to configured database datadog_test
1036+
],
1037+
)
1038+
def test_statement_with_metrics_azure_sql_filtered_to_configured_database(
1039+
aggregator,
1040+
dd_run_check,
1041+
dbm_instance,
1042+
bob_conn,
1043+
configured_database,
1044+
engine_edition,
1045+
filter_to_configured_database,
1046+
):
1047+
if configured_database:
1048+
dbm_instance['database'] = configured_database
1049+
check = SQLServer(CHECK_NAME, {}, [dbm_instance])
1050+
1051+
if engine_edition:
1052+
check.static_info_cache[STATIC_INFO_ENGINE_EDITION] = engine_edition
1053+
1054+
def _execute_queries():
1055+
bob_conn.execute_with_retries("SELECT * FROM ϑings", (), database="datadog_test")
1056+
bob_conn.execute_with_retries("SELECT count(*) from sys.databases", (), database="master")
1057+
1058+
dd_run_check(check)
1059+
_execute_queries()
1060+
dd_run_check(check)
1061+
aggregator.reset()
1062+
_execute_queries()
1063+
dd_run_check(check)
1064+
1065+
# dbm-metrics
1066+
dbm_metrics = aggregator.get_event_platform_events("dbm-metrics")
1067+
assert len(dbm_metrics) == 1, "should have collected exactly one dbm-metrics payload"
1068+
payload = dbm_metrics[0]
1069+
# metrics rows
1070+
sqlserver_rows = payload.get('sqlserver_rows', [])
1071+
assert sqlserver_rows, "should have collected some sqlserver query metrics rows"
1072+
if filter_to_configured_database:
1073+
assert all(
1074+
row['database_name'] == configured_database for row in sqlserver_rows
1075+
), "should have only collected metrics for configured database"
1076+
else:
1077+
database_names = {row['database_name'] for row in sqlserver_rows}
1078+
assert 'datadog_test' in database_names, "should have collected metrics for datadog_test databases"
1079+
assert 'master' in database_names, "should have collected metrics for master databases"

0 commit comments

Comments
 (0)