From f527ddfbfe96957fb5d96b19396df64167abcef7 Mon Sep 17 00:00:00 2001 From: Allen Zhou Date: Mon, 2 Dec 2024 12:18:13 -0500 Subject: [PATCH] DBMON-4720: Make all sql server database metrics configurable (#19111) * Deprecate usage of instance_config in favor of config in database_metrics * Remove reminder comments to myself * Applied linter suggertions and added changelog * default for database_instance_collection_interval should be a number * Update 19111.deprecated * remove unused imports * Update sqlserver/changelog.d/19111.deprecated Co-authored-by: Zhengda Lu * Make all database metrics configurable and update configuration structure * sync default config files and linter * fix failing tests * sync config files * change nested options in config to objects * Update descriptions of database metrics configurations * Linter fix * sync config files * Add hidden tag to database_metrics * sync configs * Make only newly exposed configurations hidden --------- Co-authored-by: Zhengda Lu --- sqlserver/assets/configuration/spec.yaml | 353 +++++++++++------- sqlserver/changelog.d/19111.added | 1 + sqlserver/datadog_checks/sqlserver/config.py | 93 ++++- .../sqlserver/config_models/defaults.py | 62 +-- .../sqlserver/config_models/instance.py | 179 ++++++++- sqlserver/datadog_checks/sqlserver/const.py | 2 + .../sqlserver/data/conf.yaml.example | 212 +++++------ .../sqlserver/database_metrics/ao_metrics.py | 3 +- .../availability_groups_metrics.py | 6 +- .../availability_replicas_metrics.py | 10 +- .../sqlserver/database_metrics/base.py | 2 - .../database_agent_metrics.py | 4 +- .../database_backup_metrics.py | 16 +- .../database_files_metrics.py | 12 +- .../database_replication_stats_metrics.py | 8 +- .../database_stats_metrics.py | 12 +- .../db_fragmentation_metrics.py | 16 +- .../sqlserver/database_metrics/fci_metrics.py | 5 +- .../database_metrics/file_stats_metrics.py | 6 + .../database_metrics/index_usage_metrics.py | 14 +- .../database_metrics/master_files_metrics.py | 4 +- .../database_metrics/os_schedulers_metrics.py | 4 +- .../database_metrics/os_tasks_metrics.py | 4 +- .../primary_log_shipping_metrics.py | 7 +- .../secondary_log_shipping_metrics.py | 7 +- .../database_metrics/server_state_metrics.py | 8 + .../tempdb_file_space_usage_metrics.py | 5 +- .../database_metrics/xe_session_metrics.py | 4 +- .../datadog_checks/sqlserver/sqlserver.py | 1 - sqlserver/tests/conftest.py | 28 +- sqlserver/tests/test_database_metrics.py | 332 ++++++++++------ 31 files changed, 880 insertions(+), 540 deletions(-) create mode 100644 sqlserver/changelog.d/19111.added diff --git a/sqlserver/assets/configuration/spec.yaml b/sqlserver/assets/configuration/spec.yaml index 4fde7367ce475..6594c7f51011f 100644 --- a/sqlserver/assets/configuration/spec.yaml +++ b/sqlserver/assets/configuration/spec.yaml @@ -129,12 +129,230 @@ files: type: boolean example: false display_default: true - - name: include_ao_metrics + - name: database_metrics description: | - Include AlwaysOn availability group metrics. - value: - type: boolean - example: false + Configure the collection of database metrics + options: + - name: ao_metrics + description: | + Configure collection of AlwaysOn availability group metrics. + + When the `ao_metrics.enabled` is True, use `ao_metrics.availability_group` to specify the + resource group id of a specific availability group that you would like to monitor. + If no availability group is specified, then we will collect AlwaysOn metrics for all + availability groups on the current replica. + + Primary replicas may emit metrics for remote secondary replicas + in the same availability group. If `ao_metrics.only_emit_local` is set to true, + the primary replica will only emit information local to itself. + + If `ao_metrics.ao_database` is set, AlwaysOn metrics are only emitted for the selected `ao_database`. + value: + type: object + properties: + - name: enabled + type: boolean + example: false + - name: availability_group + type: string + - name: only_emit_local + type: boolean + example: false + - name: ao_database + type: string + - name: db_backup_metrics + description: | + Configure collection of database backup metrics. + Use `db_backup_metrics.collection_interval` to set the interval (in seconds) for the collection of + database backup metrics. Defaults to 300 seconds (5 minutes). If you intend on updating this value, + it is strongly recommended to use a consistent value throughout all SQL Server agent deployments. + hidden: true + value: + type: object + properties: + - name: enabled + type: boolean + example: true + - name: collection_interval + type: integer + example: 300 + display_default: 300 + - name: db_files_metrics + description: | + Configure collection of database files metrics. + hidden: true + value: + type: object + properties: + - name: enabled + type: boolean + example: true + - name: db_stats_metrics + description: | + Configure collection of database stats metrics + hidden: true + value: + type: object + properties: + - name: enabled + type: boolean + example: true + - name: db_fragmentation_metrics + description: | + Configure collection of database fragmentation metrics. + Note these queries can be resource intensive on large datasets. Recommend to limit these via + autodiscovery or specific database instances. + + Use `db_fragmentation_metrics.enabled_tempdb` to enable collection of database index fragmentation statistics + in tempdb database from the `sys.dm_db_index_physical_stats` DMF. + By default, we do not collect index fragmentation statistics in the tempdb database, as those queries + might cause blocking. This configuration parameter allows enabling the collection of this metric. + This parameter is ignored if the 'enabled' option for 'db_fragmentation_metrics' is set to false. + + Use `db_fragmentation_metrics.collection_interval` to set the interval (in seconds) for the collection of + database fragmentation metrics from the `sys.dm_db_index_physical_stats` DMF. + Defaults to 300 seconds (5 minutes). If you intend on updating this value, it is strongly recommended + to use a consistent value throughout all SQL Server agent deployments. + value: + type: object + properties: + - name: enabled + type: boolean + example: false + - name: enabled_tempdb + type: boolean + example: false + - name: collection_interval + type: integer + example: 300 + display_default: 300 + - name: fci_metrics + description: | + Configure collection of failover Cluster Instance metrics. Note that these metrics + requires a SQLServer set up with Failover Clustering enabled. + value: + type: object + properties: + - name: enabled + type: boolean + example: false + - name: file_stats_metrics + description: | + Configure collection of file stats metrics. + hidden: true + value: + type: object + properties: + - name: enabled + type: boolean + example: true + - name: index_usage_metrics + description: | + Configure collection of user table index usage statistics from the `sys.dm_db_index_usage_stats` DMV. + Because the `sys.dm_db_index_usage_stats` view is scoped to the current database, enable + `database_autodiscovery` or set `database`. + + Use `index_usage_metrics.enabled_tempdb` to enable collection of user table index usage statistics in tempdb + database from the `sys.dm_db_index_usage_stats` DMV. + By default, we do not collect index usage statistics in the tempdb database, as those queries + might cause blocking. This configuration parameter allows enabling the collection of this metric. + This parameter is ignored if 'index_usage_metrics.enabled' is set to false. + + Use `index_usage_metrics.collection_interval` to set the interval (in seconds) for the collection of index + usage statistics from the `sys.dm_db_index_usage_stats` DMV. + Defaults to 300 seconds (5 minutes). If you intend on updating this value, it is strongly recommended + to use a consistent value throughout all SQL Server agent deployments. + value: + type: object + properties: + - name: enabled + type: boolean + example: false + - name: enabled_tempdb + type: boolean + example: false + - name: collection_interval + type: integer + example: 300 + display_default: 300 + - name: instance_metrics + description: | + Configure collection of server-level instance metrics. When setting up multiple instances for + different databases on the same host these metrics will be duplicated unless this option is turned off. + value: + type: object + properties: + - name: enabled + type: boolean + example: true + - name: master_files_metrics + description: | + Configure collection of database file size and state from `sys.master_files` + value: + type: object + properties: + - name: enabled + type: boolean + example: false + - name: primary_log_shipping_metrics + description: | + Configure collection of metrics for a log shipping setup. Required to run against the + primary instance in a transaction log shipping configuration. Note that + the Datadog user needs to be present in msdb and must be added to the db_datareader role. + value: + type: object + properties: + - name: enabled + type: boolean + example: false + - name: secondary_log_shipping_metrics + description: | + Configure collection of metrics for a log shipping setup. Required to run against the + secondary instance in a transaction log shipping configuration. Note that + the Datadog user needs to be present in msdb and must be added to the db_datareader role. + value: + type: object + properties: + - name: enabled + type: boolean + example: false + - name: server_state_metrics + description: | + Configure collection of server state metrics + hidden: true + value: + type: object + properties: + - name: enabled + type: boolean + example: true + - name: task_scheduler_metrics + description: | + Configure collection of additional Task and Scheduler metrics. + value: + type: object + properties: + - name: enabled + type: boolean + example: false + - name: tempdb_file_space_usage_metrics + description: | + Configure collection of tempdb file space usage metrics for how space is used in tempdb data files. + value: + type: object + properties: + - name: enabled + type: boolean + example: false + - name: xe_metrics + description: | + Configure collection of extended events (XE) metrics. + value: + type: object + properties: + - name: enabled + type: boolean + example: false - name: agent_jobs description: Configure collection of agent jobs events and metrics options: @@ -157,116 +375,6 @@ files: value: type: integer example: 10000 - - name: availability_group - description: | - When `include_ao_metrics` is enabled, you can provide the resource - group id of a specific availability group that you would like to monitor. - If no availability group is specified, then we will collect AlwaysOn metrics - for all availability groups on the current replica. - value: - type: string - - name: only_emit_local - description: | - Primary replicas may emit metrics for remote secondary replicas - in the same availability group. If this option is set to true, - the primary replica will only emit information local to itself. - value: - type: boolean - example: false - - name: ao_database - description: | - AlwaysOn metrics are only emitted for the selected `ao_database` if not empty. - value: - type: string - - name: include_master_files_metrics - description: | - Include database file size and state from `sys.master_files`. - value: - type: boolean - example: false - - name: include_fci_metrics - description: | - Include Failover Cluster Instance metrics. Note that these metrics - requires a SQLServer set up with Failover Clustering enabled. - value: - type: boolean - example: false - - name: include_primary_log_shipping_metrics - description: | - Include log_shipping_primary metrics for a log shipping setup. Required to run - against the primary instance in a transaction log shipping configuration. Note that - the Datadog user needs to be present in msdb and must be added to the db_datareader role. - value: - type: boolean - example: false - - name: include_secondary_log_shipping_metrics - description: | - Include log_shipping_secondary metrics for a log shipping setup. Required to run - against a secondary instance in a transaction log shipping configuration. Note that - the Datadog user needs to be present in msdb and must be added to the db_datareader role. - value: - type: boolean - example: false - - name: include_instance_metrics - description: | - Include server-level instance metrics. When setting up multiple instances for - different databases on the same host these metrics will be duplicated unless this option is turned off. - value: - type: boolean - example: true - - name: include_task_scheduler_metrics - description: Include additional Task and Scheduler metrics. - value: - type: boolean - example: false - - name: include_db_fragmentation_metrics - description: | - Include database fragmentation metrics. Note these queries can be resource intensive on large datasets. - Recommend to limit these via autodiscovery or specific database instances. - value: - type: boolean - example: false - - name: include_db_fragmentation_metrics_tempdb - description: | - Configure the collection of database index fragmentation statistics in tempdb database from the - `sys.dm_db_index_physical_stats` DMF. - - By default, we do not collect index fragmentation statistics in the tempdb database, as those queries - might cause blocking. This configuration parameter allows enabling the collection of this metric. - This parameter is ignored if 'include_db_fragmentation_metrics' is set to false. - value: - type: boolean - example: false - - name: include_index_usage_metrics - description: | - Configure the collection of user table index usage statistics from the `sys.dm_db_index_usage_stats` DMV. - - Because the `sys.dm_db_index_usage_stats` view is scoped to the current database, enable - `database_autodiscovery` or set `database`. - value: - type: boolean - example: true - - name: include_index_usage_metrics_tempdb - description: | - Configure the collection of user table index usage statistics in tempdb database from the - `sys.dm_db_index_usage_stats` DMV. - - By default, we do not collect index usage statistics in the tempdb database, as those queries - might cause blocking. This configuration parameter allows enabling the collection of this metric. - This parameter is ignored if 'include_index_usage_metrics' is set to false. - value: - type: boolean - example: false - - name: index_usage_metrics_interval - description: | - Configure the interval (in seconds) for the collection of index usage statistics from the - `sys.dm_db_index_usage_stats` DMV. - Defaults to 300 seconds (5 minutes). If you intend on updating this value, it is strongly recommended - to use a consistent value throughout all SQL Server agent deployments. - value: - type: integer - example: 300 - display_default: 300 - name: db_fragmentation_object_names description: | Fragmentation metrics normally emit metrics for all objects within a database. @@ -276,19 +384,6 @@ files: type: array items: type: string - - name: include_tempdb_file_space_usage_metrics - description: | - Include tempdb file space usage metrics for how space is used in tempdb data files. - value: - type: boolean - example: true - - name: include_xe_metrics - description: | - Include extended events (XE) metrics. The collection of XE metrics is automatically enabled - when `deadlocks_collection` is enabled. - value: - type: boolean - example: true - name: adoprovider description: | Choose the ADO provider. Note that the (default) provider @@ -764,7 +859,7 @@ files: value: type: number example: 1800 - display_default: false + display_default: 300 - name: schemas_collection description: | Available for Agent 7.56 and newer. diff --git a/sqlserver/changelog.d/19111.added b/sqlserver/changelog.d/19111.added new file mode 100644 index 0000000000000..c3ae6706f8277 --- /dev/null +++ b/sqlserver/changelog.d/19111.added @@ -0,0 +1 @@ +Update configuration structure and allow configuration of all database metrics \ No newline at end of file diff --git a/sqlserver/datadog_checks/sqlserver/config.py b/sqlserver/datadog_checks/sqlserver/config.py index 92508a44e5721..bcbbb9be07b66 100644 --- a/sqlserver/datadog_checks/sqlserver/config.py +++ b/sqlserver/datadog_checks/sqlserver/config.py @@ -10,6 +10,7 @@ from datadog_checks.base.utils.db.utils import get_agent_host_tags from datadog_checks.sqlserver.const import ( DEFAULT_AUTODISCOVERY_INTERVAL, + DEFAULT_LONG_METRICS_COLLECTION_INTERVAL, PROC_CHAR_LIMIT, ) @@ -28,17 +29,14 @@ def __init__(self, init_config, instance, log): self.autodiscovery_db_service_check: bool = is_affirmative(instance.get('autodiscovery_db_service_check', True)) self.min_collection_interval: int = instance.get('min_collection_interval', 15) self.autodiscovery_interval: int = instance.get('autodiscovery_interval', DEFAULT_AUTODISCOVERY_INTERVAL) + self.database_instance_collection_interval: int = instance.get( + 'database_instance_collection_interval', DEFAULT_LONG_METRICS_COLLECTION_INTERVAL + ) self._include_patterns = self._compile_valid_patterns(self.autodiscovery_include) self._exclude_patterns = self._compile_valid_patterns(self.autodiscovery_exclude) self.proc: str = instance.get('stored_procedure') self.custom_metrics: list[dict] = init_config.get('custom_metrics', []) or [] - self.include_index_usage_metrics_tempdb: bool = is_affirmative( - instance.get('include_index_usage_metrics_tempdb', False) - ) - self.include_db_fragmentation_metrics_tempdb: bool = is_affirmative( - instance.get('include_db_fragmentation_metrics_tempdb', False) - ) self.ignore_missing_database = is_affirmative(instance.get("ignore_missing_database", False)) if self.ignore_missing_database: self.log.warning( @@ -48,6 +46,7 @@ def __init__(self, init_config, instance, log): # DBM self.dbm_enabled: bool = is_affirmative(instance.get('dbm', False)) + self.database_metrics_config: dict = self._build_database_metrics_configs(instance) self.statement_metrics_config: dict = instance.get('query_metrics', {}) or {} self.agent_jobs_config: dict = instance.get('agent_jobs', {}) or {} self.procedure_metrics_config: dict = instance.get('procedure_metrics', {}) or {} @@ -110,10 +109,10 @@ def __init__(self, init_config, instance, log): ) self.log_unobfuscated_queries: bool = is_affirmative(instance.get('log_unobfuscated_queries', False)) self.log_unobfuscated_plans: bool = is_affirmative(instance.get('log_unobfuscated_plans', False)) - self.database_instance_collection_interval: int = instance.get('database_instance_collection_interval', 300) self.stored_procedure_characters_limit: int = instance.get('stored_procedure_characters_limit', PROC_CHAR_LIMIT) self.connection_host: str = instance['host'] self.service = instance.get('service') or init_config.get('service') or '' + self.db_fragmentation_object_names = instance.get('db_fragmentation_object_names', []) or [] def _compile_valid_patterns(self, patterns: list[str]) -> re.Pattern: valid_patterns = [] @@ -170,3 +169,83 @@ def _should_propagate_agent_tags(instance, init_config) -> bool: return init_config_propagate_agent_tags # if neither the instance nor the init_config has set the value, return False return False + + def _build_database_metrics_configs(self, instance): + # Set defaults for database metrics + configurable_metrics = { + "ao_metrics": {'enabled': False, 'availability_group': None, 'ao_database': None, 'only_emit_local': False}, + "db_backup_metrics": {'enabled': True, 'collection_interval': DEFAULT_LONG_METRICS_COLLECTION_INTERVAL}, + "db_files_metrics": {'enabled': True}, + "db_stats_metrics": {'enabled': True}, + "db_fragmentation_metrics": { + 'enabled': False, + 'enabled_tempdb': False, + 'collection_interval': DEFAULT_LONG_METRICS_COLLECTION_INTERVAL, + }, + "fci_metrics": {'enabled': False}, + "file_stats_metrics": {'enabled': True}, + "index_usage_metrics": { + 'enabled': True, + 'collection_interval': DEFAULT_LONG_METRICS_COLLECTION_INTERVAL, + 'enabled_tempdb': False, + }, + "instance_metrics": {'enabled': True}, + "master_files_metrics": {'enabled': False}, + "primary_log_shipping_metrics": {'enabled': False}, + "secondary_log_shipping_metrics": {'enabled': False}, + "server_state_metrics": {'enabled': True}, + "task_scheduler_metrics": {'enabled': False}, + "tempdb_file_space_usage_metrics": {'enabled': True}, + "xe_metrics": {'enabled': False}, + } + # Check if the instance has any configuration for the metrics in legacy structure + legacy_configuration_metrics = { + "include_ao_metrics": "ao_metrics", + "include_master_files_metrics": "master_files_metrics", + "include_fci_metrics": "fci_metrics", + "include_primary_log_shipping_metrics": "primary_log_shipping_metrics", + "include_secondary_log_shipping_metrics": "secondary_log_shipping_metrics", + "include_instance_metrics": "instance_metrics", + "include_task_scheduler_metrics": "task_scheduler_metrics", + "include_db_fragmentation_metrics": "db_fragmentation_metrics", + "include_index_usage_metrics": "index_usage_metrics", + "include_tempdb_file_space_usage_metrics": "tempdb_file_space_usage_metrics", + "include_xe_metrics": "xe_metrics", + } + for metric, config_key in legacy_configuration_metrics.items(): + if instance.get(metric) is not None: + configurable_metrics[config_key]['enabled'] = instance[metric] + # Manual look ups for legacy configuration structure + configurable_metrics['ao_metrics']['availability_group'] = instance.get( + 'availability_group', configurable_metrics['ao_metrics']['availability_group'] + ) + configurable_metrics['ao_metrics']['ao_database'] = instance.get( + 'ao_database', configurable_metrics['ao_metrics']['ao_database'] + ) + configurable_metrics['ao_metrics']['only_emit_local'] = instance.get( + 'only_emit_local', configurable_metrics['ao_metrics']['only_emit_local'] + ) + configurable_metrics['db_backup_metrics']['collection_interval'] = instance.get( + 'database_backup_metrics_interval', configurable_metrics['db_backup_metrics']['collection_interval'] + ) + configurable_metrics['db_fragmentation_metrics']['enabled_tempdb'] = instance.get( + 'include_db_fragmentation_metrics_tempdb', + configurable_metrics['db_fragmentation_metrics']['enabled_tempdb'], + ) + configurable_metrics['db_fragmentation_metrics']['collection_interval'] = instance.get( + 'db_fragmentation_metrics_interval', configurable_metrics['db_fragmentation_metrics']['collection_interval'] + ) + configurable_metrics['index_usage_metrics']['enabled_tempdb'] = instance.get( + 'include_index_usage_metrics_tempdb', configurable_metrics['index_usage_metrics']['enabled_tempdb'] + ) + configurable_metrics['index_usage_metrics']['collection_interval'] = instance.get( + 'index_usage_stats_interval', configurable_metrics['index_usage_metrics']['collection_interval'] + ) + # Check if the instance has any configuration for the metrics + database_metrics = instance.get('database_metrics', {}) + for metric, config in configurable_metrics.items(): + metric_config = database_metrics.get(metric, {}) + for key, value in metric_config.items(): + if value is not None: + config[key] = value + return configurable_metrics diff --git a/sqlserver/datadog_checks/sqlserver/config_models/defaults.py b/sqlserver/datadog_checks/sqlserver/config_models/defaults.py index 8dfc29b5ddfa7..1c6fcda461355 100644 --- a/sqlserver/datadog_checks/sqlserver/config_models/defaults.py +++ b/sqlserver/datadog_checks/sqlserver/config_models/defaults.py @@ -41,7 +41,7 @@ def instance_database_autodiscovery_interval(): def instance_database_instance_collection_interval(): - return False + return 300 def instance_dbm(): @@ -64,62 +64,6 @@ def instance_ignore_missing_database(): return False -def instance_include_ao_metrics(): - return False - - -def instance_include_db_fragmentation_metrics(): - return False - - -def instance_include_db_fragmentation_metrics_tempdb(): - return False - - -def instance_include_fci_metrics(): - return False - - -def instance_include_index_usage_metrics(): - return True - - -def instance_include_index_usage_metrics_tempdb(): - return False - - -def instance_include_instance_metrics(): - return True - - -def instance_include_master_files_metrics(): - return False - - -def instance_include_primary_log_shipping_metrics(): - return False - - -def instance_include_secondary_log_shipping_metrics(): - return False - - -def instance_include_task_scheduler_metrics(): - return False - - -def instance_include_tempdb_file_space_usage_metrics(): - return True - - -def instance_include_xe_metrics(): - return True - - -def instance_index_usage_metrics_interval(): - return 300 - - def instance_log_unobfuscated_plans(): return False @@ -136,10 +80,6 @@ def instance_only_custom_queries(): return False -def instance_only_emit_local(): - return False - - def instance_proc_only_if_database(): return 'master' diff --git a/sqlserver/datadog_checks/sqlserver/config_models/instance.py b/sqlserver/datadog_checks/sqlserver/config_models/instance.py index ad93d2bdb6f48..1f83cbd0ccc1d 100644 --- a/sqlserver/datadog_checks/sqlserver/config_models/instance.py +++ b/sqlserver/datadog_checks/sqlserver/config_models/instance.py @@ -12,7 +12,7 @@ from types import MappingProxyType from typing import Any, Optional -from pydantic import BaseModel, ConfigDict, field_validator, model_validator +from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator from datadog_checks.base.utils.functions import identity from datadog_checks.base.utils.models import validation @@ -69,6 +69,165 @@ class CustomQuery(BaseModel): tags: Optional[tuple[str, ...]] = None +class AoMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + ao_database: Optional[str] = None + availability_group: Optional[str] = None + enabled: Optional[bool] = Field(None, examples=[False]) + only_emit_local: Optional[bool] = Field(None, examples=[False]) + + +class DbBackupMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + collection_interval: Optional[int] = Field(None, examples=[300]) + enabled: Optional[bool] = Field(None, examples=[True]) + + +class DbFilesMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[True]) + + +class DbFragmentationMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + collection_interval: Optional[int] = Field(None, examples=[300]) + enabled: Optional[bool] = Field(None, examples=[False]) + enabled_tempdb: Optional[bool] = Field(None, examples=[False]) + + +class DbStatsMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[True]) + + +class FciMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[False]) + + +class FileStatsMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[True]) + + +class IndexUsageMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + collection_interval: Optional[int] = Field(None, examples=[300]) + enabled: Optional[bool] = Field(None, examples=[False]) + enabled_tempdb: Optional[bool] = Field(None, examples=[False]) + + +class InstanceMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[True]) + + +class MasterFilesMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[False]) + + +class PrimaryLogShippingMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[False]) + + +class SecondaryLogShippingMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[False]) + + +class ServerStateMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[True]) + + +class TaskSchedulerMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[False]) + + +class TempdbFileSpaceUsageMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[False]) + + +class XeMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + enabled: Optional[bool] = Field(None, examples=[False]) + + +class DatabaseMetrics(BaseModel): + model_config = ConfigDict( + arbitrary_types_allowed=True, + frozen=True, + ) + ao_metrics: Optional[AoMetrics] = None + db_backup_metrics: Optional[DbBackupMetrics] = None + db_files_metrics: Optional[DbFilesMetrics] = None + db_fragmentation_metrics: Optional[DbFragmentationMetrics] = None + db_stats_metrics: Optional[DbStatsMetrics] = None + fci_metrics: Optional[FciMetrics] = None + file_stats_metrics: Optional[FileStatsMetrics] = None + index_usage_metrics: Optional[IndexUsageMetrics] = None + instance_metrics: Optional[InstanceMetrics] = None + master_files_metrics: Optional[MasterFilesMetrics] = None + primary_log_shipping_metrics: Optional[PrimaryLogShippingMetrics] = None + secondary_log_shipping_metrics: Optional[SecondaryLogShippingMetrics] = None + server_state_metrics: Optional[ServerStateMetrics] = None + task_scheduler_metrics: Optional[TaskSchedulerMetrics] = None + tempdb_file_space_usage_metrics: Optional[TempdbFileSpaceUsageMetrics] = None + xe_metrics: Optional[XeMetrics] = None + + class DeadlocksCollection(BaseModel): model_config = ConfigDict( arbitrary_types_allowed=True, @@ -179,11 +338,9 @@ class InstanceConfig(BaseModel): ) adoprovider: Optional[str] = None agent_jobs: Optional[AgentJobs] = None - ao_database: Optional[str] = None autodiscovery_db_service_check: Optional[bool] = None autodiscovery_exclude: Optional[tuple[str, ...]] = None autodiscovery_include: Optional[tuple[str, ...]] = None - availability_group: Optional[str] = None aws: Optional[Aws] = None azure: Optional[Azure] = None collect_settings: Optional[CollectSettings] = None @@ -195,6 +352,7 @@ class InstanceConfig(BaseModel): database_autodiscovery: Optional[bool] = None database_autodiscovery_interval: Optional[int] = None database_instance_collection_interval: Optional[float] = None + database_metrics: Optional[DatabaseMetrics] = None db_fragmentation_object_names: Optional[tuple[str, ...]] = None dbm: Optional[bool] = None deadlocks_collection: Optional[DeadlocksCollection] = None @@ -205,20 +363,6 @@ class InstanceConfig(BaseModel): gcp: Optional[Gcp] = None host: str ignore_missing_database: Optional[bool] = None - include_ao_metrics: Optional[bool] = None - include_db_fragmentation_metrics: Optional[bool] = None - include_db_fragmentation_metrics_tempdb: Optional[bool] = None - include_fci_metrics: Optional[bool] = None - include_index_usage_metrics: Optional[bool] = None - include_index_usage_metrics_tempdb: Optional[bool] = None - include_instance_metrics: Optional[bool] = None - include_master_files_metrics: Optional[bool] = None - include_primary_log_shipping_metrics: Optional[bool] = None - include_secondary_log_shipping_metrics: Optional[bool] = None - include_task_scheduler_metrics: Optional[bool] = None - include_tempdb_file_space_usage_metrics: Optional[bool] = None - include_xe_metrics: Optional[bool] = None - index_usage_metrics_interval: Optional[int] = None log_unobfuscated_plans: Optional[bool] = None log_unobfuscated_queries: Optional[bool] = None managed_identity: Optional[ManagedIdentity] = None @@ -226,7 +370,6 @@ class InstanceConfig(BaseModel): min_collection_interval: Optional[float] = None obfuscator_options: Optional[ObfuscatorOptions] = None only_custom_queries: Optional[bool] = None - only_emit_local: Optional[bool] = None password: Optional[str] = None proc_only_if: Optional[str] = None proc_only_if_database: Optional[str] = None diff --git a/sqlserver/datadog_checks/sqlserver/const.py b/sqlserver/datadog_checks/sqlserver/const.py index 7fc1cf86a659e..5d29c54041040 100644 --- a/sqlserver/datadog_checks/sqlserver/const.py +++ b/sqlserver/datadog_checks/sqlserver/const.py @@ -271,3 +271,5 @@ PROC_CHAR_LIMIT = 500 DEFAULT_SCHEMAS_COLLECTION_INTERVAL = 600 + +DEFAULT_LONG_METRICS_COLLECTION_INTERVAL = 300 diff --git a/sqlserver/datadog_checks/sqlserver/data/conf.yaml.example b/sqlserver/datadog_checks/sqlserver/data/conf.yaml.example index 5418c1b76b220..bcd78b58b33c3 100644 --- a/sqlserver/datadog_checks/sqlserver/data/conf.yaml.example +++ b/sqlserver/datadog_checks/sqlserver/data/conf.yaml.example @@ -127,10 +127,107 @@ instances: # autodiscovery_db_service_check: false - ## @param include_ao_metrics - boolean - optional - default: false - ## Include AlwaysOn availability group metrics. + ## Configure the collection of database metrics # - # include_ao_metrics: false + # database_metrics: + + ## @param ao_metrics - mapping - optional + ## Configure collection of AlwaysOn availability group metrics. + ## + ## When the `ao_metrics.enabled` is True, use `ao_metrics.availability_group` to specify the + ## resource group id of a specific availability group that you would like to monitor. + ## If no availability group is specified, then we will collect AlwaysOn metrics for all + ## availability groups on the current replica. + ## + ## Primary replicas may emit metrics for remote secondary replicas + ## in the same availability group. If `ao_metrics.only_emit_local` is set to true, + ## the primary replica will only emit information local to itself. + ## + ## If `ao_metrics.ao_database` is set, AlwaysOn metrics are only emitted for the selected `ao_database`. + # + # ao_metrics: {} + + ## @param db_fragmentation_metrics - mapping - optional + ## Configure collection of database fragmentation metrics. + ## Note these queries can be resource intensive on large datasets. Recommend to limit these via + ## autodiscovery or specific database instances. + ## + ## Use `db_fragmentation_metrics.enabled_tempdb` to enable collection of database index fragmentation statistics + ## in tempdb database from the `sys.dm_db_index_physical_stats` DMF. + ## By default, we do not collect index fragmentation statistics in the tempdb database, as those queries + ## might cause blocking. This configuration parameter allows enabling the collection of this metric. + ## This parameter is ignored if the 'enabled' option for 'db_fragmentation_metrics' is set to false. + ## + ## Use `db_fragmentation_metrics.collection_interval` to set the interval (in seconds) for the collection of + ## database fragmentation metrics from the `sys.dm_db_index_physical_stats` DMF. + ## Defaults to 300 seconds (5 minutes). If you intend on updating this value, it is strongly recommended + ## to use a consistent value throughout all SQL Server agent deployments. + # + # db_fragmentation_metrics: {} + + ## @param fci_metrics - mapping - optional + ## Configure collection of failover Cluster Instance metrics. Note that these metrics + ## requires a SQLServer set up with Failover Clustering enabled. + # + # fci_metrics: {} + + ## @param index_usage_metrics - mapping - optional + ## Configure collection of user table index usage statistics from the `sys.dm_db_index_usage_stats` DMV. + ## Because the `sys.dm_db_index_usage_stats` view is scoped to the current database, enable + ## `database_autodiscovery` or set `database`. + ## + ## Use `index_usage_metrics.enabled_tempdb` to enable collection of user table index usage statistics in tempdb + ## database from the `sys.dm_db_index_usage_stats` DMV. + ## By default, we do not collect index usage statistics in the tempdb database, as those queries + ## might cause blocking. This configuration parameter allows enabling the collection of this metric. + ## This parameter is ignored if 'index_usage_metrics.enabled' is set to false. + ## + ## Use `index_usage_metrics.collection_interval` to set the interval (in seconds) for the collection of index + ## usage statistics from the `sys.dm_db_index_usage_stats` DMV. + ## Defaults to 300 seconds (5 minutes). If you intend on updating this value, it is strongly recommended + ## to use a consistent value throughout all SQL Server agent deployments. + # + # index_usage_metrics: {} + + ## @param instance_metrics - mapping - optional + ## Configure collection of server-level instance metrics. When setting up multiple instances for + ## different databases on the same host these metrics will be duplicated unless this option is turned off. + # + # instance_metrics: {} + + ## @param master_files_metrics - mapping - optional + ## Configure collection of database file size and state from `sys.master_files` + # + # master_files_metrics: {} + + ## @param primary_log_shipping_metrics - mapping - optional + ## Configure collection of metrics for a log shipping setup. Required to run against the + ## primary instance in a transaction log shipping configuration. Note that + ## the Datadog user needs to be present in msdb and must be added to the db_datareader role. + # + # primary_log_shipping_metrics: {} + + ## @param secondary_log_shipping_metrics - mapping - optional + ## Configure collection of metrics for a log shipping setup. Required to run against the + ## secondary instance in a transaction log shipping configuration. Note that + ## the Datadog user needs to be present in msdb and must be added to the db_datareader role. + # + # secondary_log_shipping_metrics: {} + + ## @param task_scheduler_metrics - mapping - optional + ## Configure collection of additional Task and Scheduler metrics. + # + # task_scheduler_metrics: {} + + ## @param tempdb_file_space_usage_metrics - mapping - optional + ## Configure collection of tempdb file space usage metrics for how space is used in tempdb data files. + # + # tempdb_file_space_usage_metrics: {} + + ## @param xe_metrics - mapping - optional + ## Configure collection of extended events (XE) metrics. + # + # xe_metrics: {} ## Configure collection of agent jobs events and metrics # @@ -152,104 +249,6 @@ instances: # # history_row_limit: 10000 - ## @param availability_group - string - optional - ## When `include_ao_metrics` is enabled, you can provide the resource - ## group id of a specific availability group that you would like to monitor. - ## If no availability group is specified, then we will collect AlwaysOn metrics - ## for all availability groups on the current replica. - # - # availability_group: - - ## @param only_emit_local - boolean - optional - default: false - ## Primary replicas may emit metrics for remote secondary replicas - ## in the same availability group. If this option is set to true, - ## the primary replica will only emit information local to itself. - # - # only_emit_local: false - - ## @param ao_database - string - optional - ## AlwaysOn metrics are only emitted for the selected `ao_database` if not empty. - # - # ao_database: - - ## @param include_master_files_metrics - boolean - optional - default: false - ## Include database file size and state from `sys.master_files`. - # - # include_master_files_metrics: false - - ## @param include_fci_metrics - boolean - optional - default: false - ## Include Failover Cluster Instance metrics. Note that these metrics - ## requires a SQLServer set up with Failover Clustering enabled. - # - # include_fci_metrics: false - - ## @param include_primary_log_shipping_metrics - boolean - optional - default: false - ## Include log_shipping_primary metrics for a log shipping setup. Required to run - ## against the primary instance in a transaction log shipping configuration. Note that - ## the Datadog user needs to be present in msdb and must be added to the db_datareader role. - # - # include_primary_log_shipping_metrics: false - - ## @param include_secondary_log_shipping_metrics - boolean - optional - default: false - ## Include log_shipping_secondary metrics for a log shipping setup. Required to run - ## against a secondary instance in a transaction log shipping configuration. Note that - ## the Datadog user needs to be present in msdb and must be added to the db_datareader role. - # - # include_secondary_log_shipping_metrics: false - - ## @param include_instance_metrics - boolean - optional - default: true - ## Include server-level instance metrics. When setting up multiple instances for - ## different databases on the same host these metrics will be duplicated unless this option is turned off. - # - # include_instance_metrics: true - - ## @param include_task_scheduler_metrics - boolean - optional - default: false - ## Include additional Task and Scheduler metrics. - # - # include_task_scheduler_metrics: false - - ## @param include_db_fragmentation_metrics - boolean - optional - default: false - ## Include database fragmentation metrics. Note these queries can be resource intensive on large datasets. - ## Recommend to limit these via autodiscovery or specific database instances. - # - # include_db_fragmentation_metrics: false - - ## @param include_db_fragmentation_metrics_tempdb - boolean - optional - default: false - ## Configure the collection of database index fragmentation statistics in tempdb database from the - ## `sys.dm_db_index_physical_stats` DMF. - ## - ## By default, we do not collect index fragmentation statistics in the tempdb database, as those queries - ## might cause blocking. This configuration parameter allows enabling the collection of this metric. - ## This parameter is ignored if 'include_db_fragmentation_metrics' is set to false. - # - # include_db_fragmentation_metrics_tempdb: false - - ## @param include_index_usage_metrics - boolean - optional - default: true - ## Configure the collection of user table index usage statistics from the `sys.dm_db_index_usage_stats` DMV. - ## - ## Because the `sys.dm_db_index_usage_stats` view is scoped to the current database, enable - ## `database_autodiscovery` or set `database`. - # - # include_index_usage_metrics: true - - ## @param include_index_usage_metrics_tempdb - boolean - optional - default: false - ## Configure the collection of user table index usage statistics in tempdb database from the - ## `sys.dm_db_index_usage_stats` DMV. - ## - ## By default, we do not collect index usage statistics in the tempdb database, as those queries - ## might cause blocking. This configuration parameter allows enabling the collection of this metric. - ## This parameter is ignored if 'include_index_usage_metrics' is set to false. - # - # include_index_usage_metrics_tempdb: false - - ## @param index_usage_metrics_interval - integer - optional - default: 300 - ## Configure the interval (in seconds) for the collection of index usage statistics from the - ## `sys.dm_db_index_usage_stats` DMV. - ## Defaults to 300 seconds (5 minutes). If you intend on updating this value, it is strongly recommended - ## to use a consistent value throughout all SQL Server agent deployments. - # - # index_usage_metrics_interval: 300 - ## @param db_fragmentation_object_names - list of strings - optional ## Fragmentation metrics normally emit metrics for all objects within a database. ## This option allows you to specify database object names to query for fragmentation metrics. @@ -257,17 +256,6 @@ instances: # # db_fragmentation_object_names: [] - ## @param include_tempdb_file_space_usage_metrics - boolean - optional - default: true - ## Include tempdb file space usage metrics for how space is used in tempdb data files. - # - # include_tempdb_file_space_usage_metrics: true - - ## @param include_xe_metrics - boolean - optional - default: true - ## Include extended events (XE) metrics. The collection of XE metrics is automatically enabled - ## when `deadlocks_collection` is enabled. - # - # include_xe_metrics: true - ## @param adoprovider - string - optional - default: SQLOLEDB ## Choose the ADO provider. Note that the (default) provider ## SQLOLEDB is being deprecated. To use the newer MSOLEDBSQL diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/ao_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/ao_metrics.py index 31b3238ba8752..8e83034bda518 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/ao_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/ao_metrics.py @@ -4,7 +4,6 @@ from typing import List -from datadog_checks.base.config import is_affirmative from datadog_checks.sqlserver.utils import is_azure_database from .base import SqlserverDatabaseMetricsBase @@ -61,7 +60,7 @@ class SqlserverAoMetrics(SqlserverDatabaseMetricsBase): @property def include_ao_metrics(self) -> bool: - return is_affirmative(self.instance_config.get('include_ao_metrics', False)) + return self.config.database_metrics_config["ao_metrics"]["enabled"] @property def enabled(self) -> bool: diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/availability_groups_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/availability_groups_metrics.py index c3c7937f65c2b..ed3558c3d3a1c 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/availability_groups_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/availability_groups_metrics.py @@ -2,8 +2,6 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) -from datadog_checks.base.config import is_affirmative - from .base import SqlserverDatabaseMetricsBase AVAILABILITY_GROUPS_METRICS_QUERY = { @@ -38,11 +36,11 @@ class SqlserverAvailabilityGroupsMetrics(SqlserverDatabaseMetricsBase): # https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-hadr-availability-group-states-transact-sql?view=sql-server-ver15 @property def include_ao_metrics(self) -> bool: - return is_affirmative(self.instance_config.get('include_ao_metrics', False)) + return self.config.database_metrics_config["ao_metrics"]["enabled"] @property def availability_group(self): - return self.instance_config.get('availability_group') + return self.config.database_metrics_config["ao_metrics"]["availability_group"] @property def enabled(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/availability_replicas_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/availability_replicas_metrics.py index 95b0c9041108c..69bccb89af457 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/availability_replicas_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/availability_replicas_metrics.py @@ -2,8 +2,6 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) -from datadog_checks.base.config import is_affirmative - from .base import SqlserverDatabaseMetricsBase AVAILABILITY_REPLICAS_METRICS_QUERY = { @@ -49,19 +47,19 @@ class SqlserverAvailabilityReplicasMetrics(SqlserverDatabaseMetricsBase): # https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-availability-replicas-transact-sql?view=sql-server-ver15 @property def include_ao_metrics(self) -> bool: - return is_affirmative(self.instance_config.get('include_ao_metrics', False)) + return self.config.database_metrics_config["ao_metrics"]["enabled"] @property def availability_group(self): - return self.instance_config.get('availability_group') + return self.config.database_metrics_config["ao_metrics"]["availability_group"] @property def only_emit_local(self): - return is_affirmative(self.instance_config.get('only_emit_local', False)) + return self.config.database_metrics_config["ao_metrics"]["only_emit_local"] @property def ao_database(self): - return self.instance_config.get('ao_database') + return self.config.database_metrics_config["ao_metrics"]["ao_database"] @property def enabled(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/base.py b/sqlserver/datadog_checks/sqlserver/database_metrics/base.py index bc61f01c71491..013c68d9703e7 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/base.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/base.py @@ -15,7 +15,6 @@ class SqlserverDatabaseMetricsBase: def __init__( self, config, - instance_config, new_query_executor, server_static_info, execute_query_handler, @@ -23,7 +22,6 @@ def __init__( databases=None, ): self.config: SQLServerConfig = config - self.instance_config: dict = instance_config # TODO: Remove instance_config and use self.config self.server_static_info: dict = server_static_info self.new_query_executor: Callable[ [List[dict], Callable, Optional[List[str]], Optional[bool]], QueryExecutor diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/database_agent_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/database_agent_metrics.py index 6d99655392eaf..0c2491b0b056f 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/database_agent_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/database_agent_metrics.py @@ -110,7 +110,7 @@ class SqlserverAgentMetrics(SqlserverDatabaseMetricsBase): def include_agent_metrics(self) -> bool: if not self.config.dbm_enabled: return False - agent_jobs_config = self.instance_config.get('agent_jobs', {}) + agent_jobs_config = self.config.agent_jobs_config if agent_jobs_config: return is_affirmative(agent_jobs_config.get('enabled', False)) return False @@ -128,7 +128,7 @@ def collection_interval(self) -> int: Returns the interval in seconds at which to collect index usage metrics. Note: The index usage metrics query can be expensive, so it is recommended to set a higher interval. ''' - agent_jobs_config = self.instance_config.get('agent_jobs', {}) + agent_jobs_config = self.config.agent_jobs_config if agent_jobs_config: return int(agent_jobs_config.get('collection_interval', 15)) return 15 # 15 seconds diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/database_backup_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/database_backup_metrics.py index e82cd65963204..21be687d112b1 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/database_backup_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/database_backup_metrics.py @@ -30,26 +30,23 @@ class SqlserverDatabaseBackupMetrics(SqlserverDatabaseMetricsBase): # Contains a row for each backup set. A backup set # contains the backup from a single, successful backup operation. # https://docs.microsoft.com/en-us/sql/relational-databases/system-tables/backupset-transact-sql?view=sql-server-ver15 + @property + def include_database_backup_metrics(self) -> bool: + return self.config.database_metrics_config["db_backup_metrics"]["enabled"] + @property def enabled(self): - if is_azure_sql_database(self.engine_edition): + if not self.include_database_backup_metrics or is_azure_sql_database(self.engine_edition): return False return True - @property - def _default_collection_interval(self) -> int: - ''' - Returns the default interval in seconds at which to collect database backup metrics. - ''' - return 5 * 60 # 5 minutes - @property def collection_interval(self) -> int: ''' Returns the interval in seconds at which to collect database backup metrics. Note: The database backup metrics query can be expensive, so it is recommended to set a higher interval. ''' - return int(self.instance_config.get('database_backup_metrics_interval', self._default_collection_interval)) + return self.config.database_metrics_config["db_backup_metrics"]["collection_interval"] @property def queries(self): @@ -63,6 +60,7 @@ def __repr__(self) -> str: return ( f"{self.__class__.__name__}(" f"enabled={self.enabled}, " + f"include_database_backup_metrics={self.include_database_backup_metrics}), " f"engine_edition={self.engine_edition}, " f"collection_interval={self.collection_interval})" ) diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/database_files_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/database_files_metrics.py index 0786ebd5e999c..5dd458bfd6005 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/database_files_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/database_files_metrics.py @@ -46,8 +46,14 @@ class SqlserverDatabaseFilesMetrics(SqlserverDatabaseMetricsBase): # https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-database-files-transact-sql + @property + def include_database_files_metrics(self) -> bool: + return self.config.database_metrics_config["db_files_metrics"]["enabled"] + @property def enabled(self): + if not self.include_database_files_metrics: + return False return True @property @@ -55,7 +61,11 @@ def queries(self): return [DATABASE_FILES_METRICS_QUERY] def __repr__(self) -> str: - return f"{self.__class__.__name__}(" f"enabled={self.enabled})" + return ( + f"{self.__class__.__name__}(" + f"enabled={self.enabled}, " + f"include_database_files_metrics={self.include_database_files_metrics})" + ) def _build_query_executors(self): executors = [] diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/database_replication_stats_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/database_replication_stats_metrics.py index e1233e353cf83..cbc5503855c80 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/database_replication_stats_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/database_replication_stats_metrics.py @@ -2,8 +2,6 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) -from datadog_checks.base.config import is_affirmative - from .base import SqlserverDatabaseMetricsBase DATABASE_REPLICATION_STATS_METRICS_QUERY = { @@ -34,15 +32,15 @@ class SqlserverDatabaseReplicationStatsMetrics(SqlserverDatabaseMetricsBase): # https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-hadr-database-replica-states-transact-sql?view=sql-server-ver15 @property def include_ao_metrics(self) -> bool: - return is_affirmative(self.instance_config.get('include_ao_metrics', False)) + return self.config.database_metrics_config["ao_metrics"]["enabled"] @property def availability_group(self): - return self.instance_config.get('availability_group') + return self.config.database_metrics_config["ao_metrics"]["availability_group"] @property def only_emit_local(self): - return is_affirmative(self.instance_config.get('only_emit_local', False)) + return self.config.database_metrics_config["ao_metrics"]["only_emit_local"] @property def enabled(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/database_stats_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/database_stats_metrics.py index d8024f4deb929..3c34a16004f81 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/database_stats_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/database_stats_metrics.py @@ -33,8 +33,14 @@ class SqlserverDatabaseStatsMetrics(SqlserverDatabaseMetricsBase): # https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-databases-transact-sql?view=sql-server-ver15 + @property + def include_database_stats_metrics(self) -> bool: + return self.config.database_metrics_config["db_stats_metrics"]["enabled"] + @property def enabled(self): + if not self.include_database_stats_metrics: + return False return True @property @@ -42,4 +48,8 @@ def queries(self): return [DATABASE_STATS_METRICS_QUERY] def __repr__(self) -> str: - return f"{self.__class__.__name__}(" f"enabled={self.enabled}" + return ( + f"{self.__class__.__name__}(" + f"enabled={self.enabled}, " + f"include_database_stats_metrics={self.include_database_stats_metrics})" + ) diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/db_fragmentation_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/db_fragmentation_metrics.py index 2b05f9378d37c..1411449ac5e21 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/db_fragmentation_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/db_fragmentation_metrics.py @@ -5,7 +5,6 @@ import copy import functools -from datadog_checks.base.config import is_affirmative from datadog_checks.base.errors import ConfigurationError from .base import SqlserverDatabaseMetricsBase @@ -52,15 +51,15 @@ class SqlserverDBFragmentationMetrics(SqlserverDatabaseMetricsBase): # https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-db-index-physical-stats-transact-sql?view=sql-server-ver15 @property def include_db_fragmentation_metrics(self): - return is_affirmative(self.instance_config.get('include_db_fragmentation_metrics', False)) + return self.config.database_metrics_config["db_fragmentation_metrics"]["enabled"] @property def include_db_fragmentation_metrics_tempdb(self): - return is_affirmative(self.instance_config.get('include_db_fragmentation_metrics_tempdb', False)) + return self.config.database_metrics_config["db_fragmentation_metrics"]["enabled_tempdb"] @property def db_fragmentation_object_names(self): - return self.instance_config.get('db_fragmentation_object_names', []) or [] + return self.config.db_fragmentation_object_names @property def enabled(self): @@ -68,20 +67,13 @@ def enabled(self): return False return True - @property - def _default_collection_interval(self) -> int: - ''' - Returns the default interval in seconds at which to collect database index fragmentation metrics. - ''' - return 5 * 60 # 5 minutes - @property def collection_interval(self) -> int: ''' Returns the interval in seconds at which to collect database index fragmentation metrics. Note: The index fragmentation metrics query can be expensive, so it is recommended to set a higher interval. ''' - return int(self.instance_config.get('db_fragmentation_metrics_interval', self._default_collection_interval)) + return self.config.database_metrics_config["db_fragmentation_metrics"]["collection_interval"] @property def databases(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/fci_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/fci_metrics.py index 81bbf485509d3..5bd821d07b8de 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/fci_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/fci_metrics.py @@ -2,7 +2,6 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) -from datadog_checks.base.config import is_affirmative from datadog_checks.sqlserver.const import ( ENGINE_EDITION_AZURE_MANAGED_INSTANCE, ) @@ -37,8 +36,8 @@ class SqlserverFciMetrics(SqlserverDatabaseMetricsBase): @property - def include_fci_metrics(self): - return is_affirmative(self.instance_config.get('include_fci_metrics', False)) + def include_fci_metrics(self) -> bool: + return self.config.database_metrics_config["fci_metrics"]["enabled"] @property def enabled(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/file_stats_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/file_stats_metrics.py index 79e0877769d7a..85b3a0d25c26d 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/file_stats_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/file_stats_metrics.py @@ -9,8 +9,14 @@ class SqlserverFileStatsMetrics(SqlserverDatabaseMetricsBase): + @property + def include_file_stats_metrics(self) -> bool: + return self.config.database_metrics_config["file_stats_metrics"]["enabled"] + @property def enabled(self): + if not self.include_file_stats_metrics: + return False if not self.major_version and not is_azure_database(self.engine_edition): return False return True diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/index_usage_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/index_usage_metrics.py index 34c9b24e8d668..d91a935c19133 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/index_usage_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/index_usage_metrics.py @@ -4,7 +4,6 @@ import functools -from datadog_checks.base.config import is_affirmative from datadog_checks.base.errors import ConfigurationError from .base import SqlserverDatabaseMetricsBase @@ -45,18 +44,11 @@ class SqlserverIndexUsageMetrics(SqlserverDatabaseMetricsBase): @property def include_index_usage_metrics(self) -> bool: - return is_affirmative(self.instance_config.get('include_index_usage_metrics', True)) + return self.config.database_metrics_config["index_usage_metrics"]["enabled"] @property def include_index_usage_metrics_tempdb(self) -> bool: - return is_affirmative(self.instance_config.get('include_index_usage_metrics_tempdb', False)) - - @property - def _default_collection_interval(self) -> int: - ''' - Returns the default interval in seconds at which to collect index usage metrics. - ''' - return 5 * 60 # 5 minutes + return self.config.database_metrics_config["index_usage_metrics"]["enabled_tempdb"] @property def collection_interval(self) -> int: @@ -64,7 +56,7 @@ def collection_interval(self) -> int: Returns the interval in seconds at which to collect index usage metrics. Note: The index usage metrics query can be expensive, so it is recommended to set a higher interval. ''' - return int(self.instance_config.get('index_usage_stats_interval', self._default_collection_interval)) + return self.config.database_metrics_config["index_usage_metrics"]["collection_interval"] @property def databases(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/master_files_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/master_files_metrics.py index a3ebf5edd89ef..2dd429807c0dc 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/master_files_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/master_files_metrics.py @@ -2,8 +2,6 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) -from datadog_checks.base.config import is_affirmative - from .base import SqlserverDatabaseMetricsBase MASTER_FILES_METRICS_QUERY = { @@ -48,7 +46,7 @@ class SqlserverMasterFilesMetrics(SqlserverDatabaseMetricsBase): # https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-master-files-transact-sql @property def include_master_files_metrics(self): - return is_affirmative(self.instance_config.get('include_master_files_metrics', False)) + return self.config.database_metrics_config["master_files_metrics"]["enabled"] @property def enabled(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/os_schedulers_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/os_schedulers_metrics.py index c1dcfd8092652..0363040d455f2 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/os_schedulers_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/os_schedulers_metrics.py @@ -2,8 +2,6 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) -from datadog_checks.base.config import is_affirmative - from .base import SqlserverDatabaseMetricsBase OS_SCHEDULERS_METRICS_QUERY = { @@ -34,7 +32,7 @@ class SqlserverOsSchedulersMetrics(SqlserverDatabaseMetricsBase): # https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-schedulers-transact-sql @property def include_task_scheduler_metrics(self): - return is_affirmative(self.instance_config.get('include_task_scheduler_metrics', False)) + return self.config.database_metrics_config["task_scheduler_metrics"]["enabled"] @property def enabled(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/os_tasks_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/os_tasks_metrics.py index 036ef35e36bd8..2fa631c28e7d7 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/os_tasks_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/os_tasks_metrics.py @@ -2,8 +2,6 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) -from datadog_checks.base.config import is_affirmative - from .base import SqlserverDatabaseMetricsBase OS_TASKS_METRICS_QUERY = { @@ -30,7 +28,7 @@ class SqlserverOsTasksMetrics(SqlserverDatabaseMetricsBase): # https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-tasks-transact-sql @property def include_task_scheduler_metrics(self): - return is_affirmative(self.instance_config.get('include_task_scheduler_metrics', False)) + return self.config.database_metrics_config["task_scheduler_metrics"]["enabled"] @property def enabled(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/primary_log_shipping_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/primary_log_shipping_metrics.py index 66724c1bacb09..709c8e48f2146 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/primary_log_shipping_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/primary_log_shipping_metrics.py @@ -2,9 +2,6 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) - -from datadog_checks.base.config import is_affirmative - from .base import SqlserverDatabaseMetricsBase QUERY_LOG_SHIPPING_PRIMARY = { @@ -29,8 +26,8 @@ class SqlserverPrimaryLogShippingMetrics(SqlserverDatabaseMetricsBase): @property - def include_primary_log_shipping_metrics(self): - return is_affirmative(self.instance_config.get('include_primary_log_shipping_metrics', False)) + def include_primary_log_shipping_metrics(self) -> bool: + return self.config.database_metrics_config["primary_log_shipping_metrics"]["enabled"] @property def enabled(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/secondary_log_shipping_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/secondary_log_shipping_metrics.py index daa4476058b2d..4fe6fb3db106d 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/secondary_log_shipping_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/secondary_log_shipping_metrics.py @@ -2,9 +2,6 @@ # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) - -from datadog_checks.base.config import is_affirmative - from .base import SqlserverDatabaseMetricsBase QUERY_LOG_SHIPPING_SECONDARY = { @@ -37,8 +34,8 @@ class SqlserverSecondaryLogShippingMetrics(SqlserverDatabaseMetricsBase): @property - def include_secondary_log_shipping_metrics(self): - return is_affirmative(self.instance_config.get('include_secondary_log_shipping_metrics', False)) + def include_secondary_log_shipping_metrics(self) -> bool: + return self.config.database_metrics_config['secondary_log_shipping_metrics']['enabled'] @property def enabled(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/server_state_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/server_state_metrics.py index 536b67f0be4ae..7d437637e3056 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/server_state_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/server_state_metrics.py @@ -30,10 +30,17 @@ class SqlserverServerStateMetrics(SqlserverDatabaseMetricsBase): + @property + def include_server_state_metrics(self) -> bool: + return self.config.database_metrics_config['server_state_metrics']['enabled'] + @property def enabled(self): # Server state queries require VIEW SERVER STATE permissions, which some managed database # versions do not support. + + if not self.include_server_state_metrics: + return False if self.engine_edition in [ENGINE_EDITION_SQL_DATABASE]: return False return True @@ -46,6 +53,7 @@ def __repr__(self) -> str: return ( f"{self.__class__.__name__}(" f"enabled={self.enabled}, " + f"include_server_state_metrics={self.include_server_state_metrics}, " f"major_version={self.major_version}, " f"engine_edition={self.engine_edition})" ) diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/tempdb_file_space_usage_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/tempdb_file_space_usage_metrics.py index 6d926c0c2f74f..5e18c1838679c 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/tempdb_file_space_usage_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/tempdb_file_space_usage_metrics.py @@ -4,7 +4,6 @@ import functools -from datadog_checks.base.config import is_affirmative from datadog_checks.sqlserver.utils import is_azure_sql_database from .base import SqlserverDatabaseMetricsBase @@ -32,8 +31,8 @@ class SqlserverTempDBFileSpaceUsageMetrics(SqlserverDatabaseMetricsBase): @property - def include_tempdb_file_space_usage_metrics(self): - return is_affirmative(self.instance_config.get('include_tempdb_file_space_usage_metrics', True)) + def include_tempdb_file_space_usage_metrics(self) -> bool: + return self.config.database_metrics_config['tempdb_file_space_usage_metrics']['enabled'] @property def enabled(self): diff --git a/sqlserver/datadog_checks/sqlserver/database_metrics/xe_session_metrics.py b/sqlserver/datadog_checks/sqlserver/database_metrics/xe_session_metrics.py index 5f5d57bbe938e..99cacc6fcda5b 100644 --- a/sqlserver/datadog_checks/sqlserver/database_metrics/xe_session_metrics.py +++ b/sqlserver/datadog_checks/sqlserver/database_metrics/xe_session_metrics.py @@ -44,8 +44,8 @@ class SQLServerXESessionMetrics(SqlserverDatabaseMetricsBase): @property def enabled(self): - self.deadlocks_config: dict = self.instance_config.get('deadlocks_collection', {}) or {} - return is_affirmative(self.instance_config.get("include_xe_metrics", False)) or is_affirmative( + self.deadlocks_config: dict = self.config.deadlocks_config + return self.config.database_metrics_config["xe_metrics"]["enabled"] or is_affirmative( self.deadlocks_config.get('enabled', False) ) diff --git a/sqlserver/datadog_checks/sqlserver/sqlserver.py b/sqlserver/datadog_checks/sqlserver/sqlserver.py index 6016f5fa6f95f..67189e3145c4d 100644 --- a/sqlserver/datadog_checks/sqlserver/sqlserver.py +++ b/sqlserver/datadog_checks/sqlserver/sqlserver.py @@ -757,7 +757,6 @@ def check(self, _): def _new_database_metric_executor(self, database_metric_class, db_names=None): return database_metric_class( config=self._config, - instance_config=self.instance, new_query_executor=self._new_query_executor, server_static_info=self.static_info_cache, execute_query_handler=self.execute_query_raw, diff --git a/sqlserver/tests/conftest.py b/sqlserver/tests/conftest.py index b0985ea6a8414..bfe6dd7fdf71f 100644 --- a/sqlserver/tests/conftest.py +++ b/sqlserver/tests/conftest.py @@ -99,11 +99,23 @@ def instance_minimal_defaults(): def instance_docker(instance_docker_defaults): instance_docker_defaults.update( { - 'include_task_scheduler_metrics': True, - 'include_db_fragmentation_metrics': True, - 'include_fci_metrics': True, - 'include_ao_metrics': False, - 'include_master_files_metrics': True, + 'database_metrics': { + 'ao_metrics': { + 'enabled': False, + }, + 'task_scheduler_metrics': { + 'enabled': True, + }, + 'db_fragmentation_metrics': { + 'enabled': True, + }, + 'fci_metrics': { + 'enabled': True, + }, + 'master_files_metrics': { + 'enabled': True, + }, + }, 'disable_generic_tags': True, } ) @@ -233,21 +245,21 @@ def instance_e2e(instance_docker): @pytest.fixture def instance_ao_docker_primary(instance_docker): - instance_docker['include_ao_metrics'] = True + instance_docker['database_metrics']['ao_metrics']['enabled'] = True return instance_docker @pytest.fixture def instance_ao_docker_primary_local_only(instance_ao_docker_primary): instance = deepcopy(instance_ao_docker_primary) - instance['only_emit_local'] = True + instance['database_metrics']['ao_metrics']['only_emit_local'] = True return instance @pytest.fixture def instance_ao_docker_primary_non_existing_ag(instance_ao_docker_primary): instance = deepcopy(instance_ao_docker_primary) - instance['availability_group'] = 'AG2' + instance['database_metrics']['ao_metrics']['availability_group'] = 'AG2' return instance diff --git a/sqlserver/tests/test_database_metrics.py b/sqlserver/tests/test_database_metrics.py index 0330ebbe36a1e..7203196159b4b 100644 --- a/sqlserver/tests/test_database_metrics.py +++ b/sqlserver/tests/test_database_metrics.py @@ -52,13 +52,18 @@ @pytest.mark.integration @pytest.mark.usefixtures('dd_environment') +@pytest.mark.parametrize('include_file_stats_metrics', [True, False]) def test_sqlserver_file_stats_metrics( aggregator, dd_run_check, init_config, instance_docker_metrics, + include_file_stats_metrics, ): instance_docker_metrics['database_autodiscovery'] = True + instance_docker_metrics['database_metrics'] = { + 'file_stats_metrics': {'enabled': include_file_stats_metrics}, + } mocked_results = [ ('master', 'ONLINE', 'master', '/xx/master.mdf', 89, 0, 0, 73, 16, 3153920, 933888, 59, 98, 4194304), @@ -78,7 +83,6 @@ def execute_query_handler_mocked(query, db=None): file_stats_metrics = SqlserverFileStatsMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -88,18 +92,21 @@ def execute_query_handler_mocked(query, db=None): dd_run_check(sqlserver_check) - tags = sqlserver_check._config.tags - for result in mocked_results: - db, state, logical_name, file_location, *metric_values = result - metrics = zip(file_stats_metrics.metric_names()[0], metric_values) - expected_tags = [ - f'db:{db}', - f'state:{state}', - f'logical_name:{logical_name}', - f'file_location:{file_location}', - ] + tags - for metric_name, metric_value in metrics: - aggregator.assert_metric(metric_name, value=metric_value, tags=expected_tags) + if not include_file_stats_metrics: + assert file_stats_metrics.enabled is False + else: + tags = sqlserver_check._config.tags + for result in mocked_results: + db, state, logical_name, file_location, *metric_values = result + metrics = zip(file_stats_metrics.metric_names()[0], metric_values) + expected_tags = [ + f'db:{db}', + f'state:{state}', + f'logical_name:{logical_name}', + f'file_location:{file_location}', + ] + tags + for metric_name, metric_value in metrics: + aggregator.assert_metric(metric_name, value=metric_value, tags=expected_tags) @pytest.mark.integration @@ -113,7 +120,9 @@ def test_sqlserver_ao_metrics( include_ao_metrics, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_ao_metrics'] = include_ao_metrics + instance_docker_metrics['database_metrics'] = { + 'ao_metrics': {'enabled': include_ao_metrics}, + } # Mocked results mocked_ao_availability_groups = [ @@ -155,7 +164,6 @@ def test_sqlserver_ao_metrics( ao_metrics = SqlserverAoMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -254,9 +262,11 @@ def test_sqlserver_availability_groups_metrics( mocked_results, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_ao_metrics'] = include_ao_metrics + instance_docker_metrics['database_metrics'] = { + 'ao_metrics': {'enabled': include_ao_metrics}, + } if availability_group: - instance_docker_metrics['availability_group'] = availability_group + instance_docker_metrics['database_metrics']['ao_metrics']['availability_group'] = availability_group sqlserver_check = SQLServer(CHECK_NAME, init_config, [instance_docker_metrics]) @@ -265,7 +275,6 @@ def execute_query_handler_mocked(query, db=None): availability_groups_metrics = SqlserverAvailabilityGroupsMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -342,11 +351,13 @@ def test_sqlserver_database_replication_stats_metrics( mocked_results, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_ao_metrics'] = include_ao_metrics + instance_docker_metrics['database_metrics'] = { + 'ao_metrics': {'enabled': include_ao_metrics}, + } if availability_group: - instance_docker_metrics['availability_group'] = availability_group + instance_docker_metrics['database_metrics']['ao_metrics']['availability_group'] = availability_group if only_emit_local: - instance_docker_metrics['only_emit_local'] = only_emit_local + instance_docker_metrics['database_metrics']['ao_metrics']['only_emit_local'] = only_emit_local sqlserver_check = SQLServer(CHECK_NAME, init_config, [instance_docker_metrics]) @@ -355,7 +366,6 @@ def execute_query_handler_mocked(query, db=None): database_replication_stats_metrics = SqlserverDatabaseReplicationStatsMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -475,13 +485,15 @@ def test_sqlserver_availability_replicas_metrics( mocked_results, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_ao_metrics'] = include_ao_metrics + instance_docker_metrics['database_metrics'] = { + 'ao_metrics': {'enabled': include_ao_metrics}, + } if availability_group: - instance_docker_metrics['availability_group'] = availability_group + instance_docker_metrics['database_metrics']['ao_metrics']['availability_group'] = availability_group if only_emit_local: - instance_docker_metrics['only_emit_local'] = only_emit_local + instance_docker_metrics['database_metrics']['ao_metrics']['only_emit_local'] = only_emit_local if ao_database: - instance_docker_metrics['ao_database'] = ao_database + instance_docker_metrics['database_metrics']['ao_metrics']['ao_database'] = ao_database sqlserver_check = SQLServer(CHECK_NAME, init_config, [instance_docker_metrics]) @@ -490,7 +502,6 @@ def execute_query_handler_mocked(query, db=None): availability_replicas_metrics = SqlserverAvailabilityReplicasMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -548,7 +559,9 @@ def test_sqlserver_fci_metrics( include_fci_metrics, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_fci_metrics'] = include_fci_metrics + instance_docker_metrics['database_metrics'] = { + 'fci_metrics': {'enabled': include_fci_metrics}, + } mocked_results = [ ('node1', 'up', 'cluster1', 0, 1), @@ -561,7 +574,6 @@ def execute_query_handler_mocked(query, db=None): fci_metrics = SqlserverFciMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -598,8 +610,9 @@ def test_sqlserver_primary_log_shipping_metrics( include_primary_log_shipping_metrics, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_primary_log_shipping_metrics'] = include_primary_log_shipping_metrics - + instance_docker_metrics['database_metrics'] = { + 'primary_log_shipping_metrics': {'enabled': include_primary_log_shipping_metrics}, + } mocked_results = [('97E29D89-2FA0-44FF-9EF7-65DA75FE0E3E', 'EC2AMAZ-Q0NCNV5', 'MyDummyDB', 500, 3600)] sqlserver_check = SQLServer(CHECK_NAME, init_config, [instance_docker_metrics]) @@ -609,7 +622,6 @@ def execute_query_handler_mocked(query, db=None): primary_log_shipping_metrics = SqlserverPrimaryLogShippingMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -646,8 +658,9 @@ def test_sqlserver_secondary_log_shipping_metrics( include_secondary_log_shipping_metrics, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_secondary_log_shipping_metrics'] = include_secondary_log_shipping_metrics - + instance_docker_metrics['database_metrics'] = { + 'secondary_log_shipping_metrics': {'enabled': include_secondary_log_shipping_metrics}, + } mocked_results = [ ( r'EC2AMAZ-Q0NCNV5\MYSECONDARY', @@ -669,7 +682,6 @@ def execute_query_handler_mocked(query, db=None): primary_log_shipping_metrics = SqlserverSecondaryLogShippingMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -699,13 +711,14 @@ def execute_query_handler_mocked(query, db=None): @pytest.mark.integration @pytest.mark.usefixtures('dd_environment') +@pytest.mark.parametrize('include_server_state_metrics', [True, False]) def test_sqlserver_server_state_metrics( - aggregator, - dd_run_check, - init_config, - instance_docker_metrics, + aggregator, dd_run_check, init_config, instance_docker_metrics, include_server_state_metrics ): instance_docker_metrics['database_autodiscovery'] = True + instance_docker_metrics['database_metrics'] = { + 'server_state_metrics': {'enabled': include_server_state_metrics}, + } mocked_results = [(1000, 4, 8589934592, 17179869184, 4294967296, 8589934592)] @@ -716,7 +729,6 @@ def execute_query_handler_mocked(query, db=None): server_state_metrics = SqlserverServerStateMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -726,11 +738,14 @@ def execute_query_handler_mocked(query, db=None): dd_run_check(sqlserver_check) - tags = sqlserver_check._config.tags - for result in mocked_results: - metrics = zip(server_state_metrics.metric_names()[0], result) - for metric_name, metric_value in metrics: - aggregator.assert_metric(metric_name, value=metric_value, tags=tags) + if not include_server_state_metrics: + assert server_state_metrics.enabled is False + else: + tags = sqlserver_check._config.tags + for result in mocked_results: + metrics = zip(server_state_metrics.metric_names()[0], result) + for metric_name, metric_value in metrics: + aggregator.assert_metric(metric_name, value=metric_value, tags=tags) @pytest.mark.integration @@ -744,8 +759,9 @@ def test_sqlserver_tempdb_file_space_usage_metrics( include_tempdb_file_space_usage_metrics, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_tempdb_file_space_usage_metrics'] = include_tempdb_file_space_usage_metrics - + instance_docker_metrics['database_metrics'] = { + 'tempdb_file_space_usage_metrics': {'enabled': include_tempdb_file_space_usage_metrics} + } mocked_results = [ [(2, Decimal('5.375000'), Decimal('0.000000'), Decimal('0.000000'), Decimal('1.312500'), Decimal('1.312500'))] ] @@ -757,7 +773,6 @@ def execute_query_handler_mocked(query, db=None): tempdb_file_space_usage_metrics = SqlserverTempDBFileSpaceUsageMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -798,10 +813,16 @@ def test_sqlserver_index_usage_metrics( index_usage_stats_interval, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_index_usage_metrics'] = include_index_usage_metrics - instance_docker_metrics['include_index_usage_metrics_tempdb'] = include_index_usage_metrics_tempdb + instance_docker_metrics['database_metrics'] = { + 'index_usage_metrics': { + 'enabled': include_index_usage_metrics, + 'enabled_tempdb': include_index_usage_metrics_tempdb, + }, + } if index_usage_stats_interval: - instance_docker_metrics['index_usage_stats_interval'] = index_usage_stats_interval + instance_docker_metrics['database_metrics']['index_usage_metrics'][ + 'collection_interval' + ] = index_usage_stats_interval mocked_results_non_tempdb = [ [ @@ -830,14 +851,13 @@ def test_sqlserver_index_usage_metrics( index_usage_metrics = SqlserverIndexUsageMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, databases=AUTODISCOVERY_DBS + ['tempdb'], ) - expected_collection_interval = index_usage_stats_interval or index_usage_metrics._default_collection_interval + expected_collection_interval = index_usage_stats_interval or index_usage_metrics.collection_interval assert index_usage_metrics.queries[0]['collection_interval'] == expected_collection_interval sqlserver_check._database_metrics = [index_usage_metrics] @@ -888,11 +908,17 @@ def test_sqlserver_db_fragmentation_metrics( db_fragmentation_metrics_interval, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_db_fragmentation_metrics'] = include_db_fragmentation_metrics - instance_docker_metrics['include_db_fragmentation_metrics_tempdb'] = include_db_fragmentation_metrics_tempdb + instance_docker_metrics['database_metrics'] = { + 'db_fragmentation_metrics': { + 'enabled': include_db_fragmentation_metrics, + 'enabled_tempdb': include_db_fragmentation_metrics_tempdb, + }, + } if db_fragmentation_metrics_interval: - instance_docker_metrics['db_fragmentation_metrics_interval'] = db_fragmentation_metrics_interval - + instance_docker_metrics['database_metrics']['db_fragmentation_metrics'][ + 'collection_interval' + ] = db_fragmentation_metrics_interval + print(instance_docker_metrics) mocked_results = [ [ ('master', 'spt_fallback_db', 0, None, 0, 0.0, 0, 0.0), @@ -934,7 +960,6 @@ def test_sqlserver_db_fragmentation_metrics( db_fragmentation_metrics = SqlserverDBFragmentationMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -944,9 +969,7 @@ def test_sqlserver_db_fragmentation_metrics( if db_fragmentation_object_names: assert db_fragmentation_metrics.db_fragmentation_object_names == db_fragmentation_object_names - expected_collection_interval = ( - db_fragmentation_metrics_interval or db_fragmentation_metrics._default_collection_interval - ) + expected_collection_interval = db_fragmentation_metrics_interval or db_fragmentation_metrics.collection_interval assert db_fragmentation_metrics.queries[0]['collection_interval'] == expected_collection_interval sqlserver_check._database_metrics = [db_fragmentation_metrics] @@ -995,7 +1018,9 @@ def test_sqlserver_os_schedulers_metrics( include_task_scheduler_metrics, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_task_scheduler_metrics'] = include_task_scheduler_metrics + instance_docker_metrics['database_metrics'] = { + 'task_scheduler_metrics': {'enabled': include_task_scheduler_metrics}, + } mocked_results = [ (0, 0, 4, 6, 4, 0, 0), @@ -1024,7 +1049,6 @@ def execute_query_handler_mocked(query, db=None): os_schedulers_metrics = SqlserverOsSchedulersMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -1060,8 +1084,9 @@ def test_sqlserver_os_tasks_metrics( include_task_scheduler_metrics, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_task_scheduler_metrics'] = include_task_scheduler_metrics - + instance_docker_metrics['database_metrics'] = { + 'task_scheduler_metrics': {'enabled': include_task_scheduler_metrics}, + } mocked_results = [ (0, 40, 0, 0, 0), (9, 46, 0, 0, 0), @@ -1089,7 +1114,6 @@ def execute_query_handler_mocked(query, db=None): os_tasks_metrics = SqlserverOsTasksMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -1124,8 +1148,9 @@ def test_sqlserver_master_files_metrics( include_master_files_metrics, ): instance_docker_metrics['database_autodiscovery'] = True - instance_docker_metrics['include_master_files_metrics'] = include_master_files_metrics - + instance_docker_metrics['database_metrics'] = { + 'master_files_metrics': {'enabled': include_master_files_metrics}, + } mocked_results = [ ('master', 'master', 1, 'data', '/var/opt/mssql/data/master.mdf', 'ONLINE', 4096, 0), ('master', 'master', 2, 'transaction_log', '/var/opt/mssql/data/mastlog.ldf', 'ONLINE', 512, 0), @@ -1155,7 +1180,6 @@ def execute_query_handler_mocked(query, db=None): master_files_metrics = SqlserverMasterFilesMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -1187,13 +1211,18 @@ def execute_query_handler_mocked(query, db=None): @pytest.mark.integration @pytest.mark.usefixtures('dd_environment') +@pytest.mark.parametrize('include_database_files_metrics', [True, False]) def test_sqlserver_database_files_metrics( aggregator, dd_run_check, init_config, instance_docker_metrics, + include_database_files_metrics, ): instance_docker_metrics['database_autodiscovery'] = True + instance_docker_metrics['database_metrics'] = { + 'db_files_metrics': {'enabled': include_database_files_metrics}, + } mocked_results = [ [ @@ -1226,7 +1255,6 @@ def test_sqlserver_database_files_metrics( database_files_metrics = SqlserverDatabaseFilesMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -1237,35 +1265,43 @@ def test_sqlserver_database_files_metrics( dd_run_check(sqlserver_check) - tags = sqlserver_check._config.tags - for db, result in zip(AUTODISCOVERY_DBS, mocked_results): - for row in result: - file_id, file_type, file_location, file_name, database_files_state_desc, size, space_used, state = row - size *= 8 # size is in pages, 1 page = 8 KB - space_used *= 8 # space_used is in pages, 1 page = 8 KB - metrics = zip(database_files_metrics.metric_names()[0], [state, size, space_used]) - expected_tags = [ - f'db:{db}', - f'database:{db}', - f'file_id:{file_id}', - f'file_type:{file_type}', - f'file_location:{file_location}', - f'file_name:{file_name}', - f'database_files_state_desc:{database_files_state_desc}', - ] + tags - for metric_name, metric_value in metrics: - aggregator.assert_metric(metric_name, value=metric_value, tags=expected_tags) + if not include_database_files_metrics: + assert database_files_metrics.enabled is False + else: + tags = sqlserver_check._config.tags + for db, result in zip(AUTODISCOVERY_DBS, mocked_results): + for row in result: + file_id, file_type, file_location, file_name, database_files_state_desc, size, space_used, state = row + size *= 8 # size is in pages, 1 page = 8 KB + space_used *= 8 # space_used is in pages, 1 page = 8 KB + metrics = zip(database_files_metrics.metric_names()[0], [state, size, space_used]) + expected_tags = [ + f'db:{db}', + f'database:{db}', + f'file_id:{file_id}', + f'file_type:{file_type}', + f'file_location:{file_location}', + f'file_name:{file_name}', + f'database_files_state_desc:{database_files_state_desc}', + ] + tags + for metric_name, metric_value in metrics: + aggregator.assert_metric(metric_name, value=metric_value, tags=expected_tags) @pytest.mark.integration @pytest.mark.usefixtures('dd_environment') +@pytest.mark.parametrize('include_database_files_metrics', [True, False]) def test_sqlserver_database_stats_metrics( aggregator, dd_run_check, init_config, instance_docker_metrics, + include_database_files_metrics, ): instance_docker_metrics['database_autodiscovery'] = True + instance_docker_metrics['database_metrics'] = { + 'db_stats_metrics': {'enabled': include_database_files_metrics}, + } mocked_results = [ ('master', 'master', 'ONLINE', 'SIMPLE', 0, False, False, False), @@ -1282,7 +1318,6 @@ def execute_query_handler_mocked(query, db=None): database_stats_metrics = SqlserverDatabaseStatsMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, @@ -1292,33 +1327,43 @@ def execute_query_handler_mocked(query, db=None): dd_run_check(sqlserver_check) - tags = sqlserver_check._config.tags - for result in mocked_results: - db, database, database_state_desc, database_recovery_model_desc, *metric_values = result - metrics = zip(database_stats_metrics.metric_names()[0], metric_values) - expected_tags = [ - f'db:{db}', - f'database:{database}', - f'database_state_desc:{database_state_desc}', - f'database_recovery_model_desc:{database_recovery_model_desc}', - ] + tags - for metric_name, metric_value in metrics: - aggregator.assert_metric(metric_name, value=metric_value, tags=expected_tags) + if not include_database_files_metrics: + assert database_stats_metrics.enabled is False + else: + tags = sqlserver_check._config.tags + for result in mocked_results: + db, database, database_state_desc, database_recovery_model_desc, *metric_values = result + metrics = zip(database_stats_metrics.metric_names()[0], metric_values) + expected_tags = [ + f'db:{db}', + f'database:{database}', + f'database_state_desc:{database_state_desc}', + f'database_recovery_model_desc:{database_recovery_model_desc}', + ] + tags + for metric_name, metric_value in metrics: + aggregator.assert_metric(metric_name, value=metric_value, tags=expected_tags) @pytest.mark.integration @pytest.mark.usefixtures('dd_environment') @pytest.mark.parametrize('database_backup_metrics_interval', [None, 600]) +@pytest.mark.parametrize('include_database_backup_metrics', [True, False]) def test_sqlserver_database_backup_metrics( aggregator, dd_run_check, init_config, instance_docker_metrics, database_backup_metrics_interval, + include_database_backup_metrics, ): instance_docker_metrics['database_autodiscovery'] = True + instance_docker_metrics['database_metrics'] = { + 'db_backup_metrics': {'enabled': include_database_backup_metrics}, + } if database_backup_metrics_interval: - instance_docker_metrics['database_backup_metrics_interval'] = database_backup_metrics_interval + instance_docker_metrics['database_metrics']['db_backup_metrics'][ + 'collection_interval' + ] = database_backup_metrics_interval mocked_results = [ ('master', 'master', 0), @@ -1335,36 +1380,36 @@ def execute_query_handler_mocked(query, db=None): database_backup_metrics = SqlserverDatabaseBackupMetrics( config=sqlserver_check._config, - instance_config=instance_docker_metrics, new_query_executor=sqlserver_check._new_query_executor, server_static_info=STATIC_SERVER_INFO, execute_query_handler=execute_query_handler_mocked, ) - expected_collection_interval = ( - database_backup_metrics_interval or database_backup_metrics._default_collection_interval - ) + expected_collection_interval = database_backup_metrics_interval or database_backup_metrics.collection_interval assert database_backup_metrics.queries[0]['collection_interval'] == expected_collection_interval sqlserver_check._database_metrics = [database_backup_metrics] dd_run_check(sqlserver_check) - tags = sqlserver_check._config.tags - for result in mocked_results: - db, database, *metric_values = result - metrics = zip(database_backup_metrics.metric_names()[0], metric_values) - expected_tags = [ - f'db:{db}', - f'database:{database}', - ] + tags - for metric_name, metric_value in metrics: - aggregator.assert_metric(metric_name, value=metric_value, tags=expected_tags) - - # database_backup_metrics should not be collected because the collection interval is not reached - aggregator.reset() - dd_run_check(sqlserver_check) - for metric_name in database_backup_metrics.metric_names()[0]: - aggregator.assert_metric(metric_name, count=0) + if not include_database_backup_metrics: + assert database_backup_metrics.enabled is False + else: + tags = sqlserver_check._config.tags + for result in mocked_results: + db, database, *metric_values = result + metrics = zip(database_backup_metrics.metric_names()[0], metric_values) + expected_tags = [ + f'db:{db}', + f'database:{database}', + ] + tags + for metric_name, metric_value in metrics: + aggregator.assert_metric(metric_name, value=metric_value, tags=expected_tags) + + # database_backup_metrics should not be collected because the collection interval is not reached + aggregator.reset() + dd_run_check(sqlserver_check) + for metric_name in database_backup_metrics.metric_names()[0]: + aggregator.assert_metric(metric_name, count=0) @pytest.mark.integration @@ -1391,3 +1436,46 @@ def test_sqlserver_xe_session_metrics( expected_tags = sqlserver_check._config.tags expected_tags.append('session_name:datadog') aggregator.assert_metric("sqlserver.xe.session_status", value=1, tags=expected_tags) + + +@pytest.mark.integration +@pytest.mark.usefixtures('dd_environment') +def test_sqlserver_database_metrics_defaults( + aggregator, + dd_run_check, + init_config, + instance_docker_metrics, +): + include_defaults = { + SqlserverAoMetrics: False, + SqlserverAvailabilityGroupsMetrics: False, + SqlserverAvailabilityReplicasMetrics: False, + SqlserverDatabaseBackupMetrics: True, + SqlserverDatabaseFilesMetrics: True, + SqlserverDatabaseReplicationStatsMetrics: False, + SqlserverDatabaseStatsMetrics: True, + SqlserverDBFragmentationMetrics: False, + SqlserverFciMetrics: False, + SqlserverFileStatsMetrics: True, + SqlserverIndexUsageMetrics: True, + SqlserverMasterFilesMetrics: False, + SqlserverOsSchedulersMetrics: False, + SqlserverOsTasksMetrics: False, + SqlserverPrimaryLogShippingMetrics: False, + SqlserverSecondaryLogShippingMetrics: False, + SqlserverServerStateMetrics: True, + SqlserverTempDBFileSpaceUsageMetrics: True, + } + instance_docker_metrics['database_autodiscovery'] = True + + sqlserver_check = SQLServer(CHECK_NAME, init_config, [instance_docker_metrics]) + + for metric, enabled in include_defaults.items(): + database_metrics = metric( + config=sqlserver_check._config, + new_query_executor=sqlserver_check._new_query_executor, + server_static_info=STATIC_SERVER_INFO, + execute_query_handler=None, + databases=AUTODISCOVERY_DBS, + ) + assert database_metrics.enabled == enabled