diff --git a/mysql/changelog.d/18950.added b/mysql/changelog.d/18950.added new file mode 100644 index 0000000000000..e5959091a608d --- /dev/null +++ b/mysql/changelog.d/18950.added @@ -0,0 +1 @@ +Added the `dbms_flavor` tag to MySQL integration metrics and events to identify the database type. This tag indicates whether the database is MySQL or MariaDB. diff --git a/mysql/datadog_checks/mysql/mysql.py b/mysql/datadog_checks/mysql/mysql.py index f204306da6b32..b81ff947229d2 100644 --- a/mysql/datadog_checks/mysql/mysql.py +++ b/mysql/datadog_checks/mysql/mysql.py @@ -202,6 +202,12 @@ def set_resource_tags(self): ) ) + def set_version_tags(self): + if not self.version or not self.version.flavor: + return + + self.tags.append('dbms_flavor:{}'.format(self.version.flavor.lower())) + def _check_database_configuration(self, db): self._check_performance_schema_enabled(db) self._check_events_wait_current_enabled(db) @@ -274,7 +280,6 @@ def check(self, _): if self.instance.get('pass'): self._log_deprecation('_config_renamed', 'pass', 'password') - tags = list(self.tags) self._set_qcache_stats() try: with self._connect() as db: @@ -283,11 +288,12 @@ def check(self, _): # Update tag set with relevant information if self._get_is_aurora(db): aurora_tags = self._get_runtime_aurora_tags(db) - self.tags = tags + aurora_tags + self.tags = list(set(self.tags) | set(aurora_tags)) self._non_internal_tags = self._set_database_instance_tags(aurora_tags) # version collection self.version = get_version(db) + self.set_version_tags() self._send_metadata() self._send_database_instance_metadata() @@ -299,6 +305,7 @@ def check(self, _): self.check_userstat_enabled(db) # Metric collection + tags = copy.deepcopy(self.tags) if not self._config.only_custom_queries: self._collect_metrics(db, tags=tags) self._collect_system_metrics(self._config.host, db, tags) @@ -676,7 +683,7 @@ def _collect_group_replica_metrics(self, db, results): self.service_check( self.GROUP_REPLICATION_SERVICE_CHECK_NAME, status=status, - tags=self._service_check_tags() + additional_tags, + tags=self.service_check_tags + additional_tags, ) metrics_to_fetch = SQL_GROUP_REPLICATION_METRICS_8_0_2 if above_802 else SQL_GROUP_REPLICATION_METRICS diff --git a/mysql/tests/tags.py b/mysql/tests/tags.py index 71f9e91279a36..0543af7c2bbdf 100644 --- a/mysql/tests/tags.py +++ b/mysql/tests/tags.py @@ -9,6 +9,7 @@ 'tag1:value1', 'tag2:value2', DATABASE_INSTANCE_RESOURCE_TAG.format(hostname='stubbed.hostname'), + 'dbms_flavor:{}'.format(common.MYSQL_FLAVOR.lower()), ] SC_TAGS = [ 'port:' + str(common.PORT), diff --git a/mysql/tests/test_metadata.py b/mysql/tests/test_metadata.py index 11479c4e8b5ce..b60f1d08bd428 100644 --- a/mysql/tests/test_metadata.py +++ b/mysql/tests/test_metadata.py @@ -676,6 +676,7 @@ def test_collect_schemas(aggregator, dd_run_check, dbm_instance): assert schema_event.get("dbms_version") is not None assert (schema_event.get("flavor") == "MariaDB") or (schema_event.get("flavor") == "MySQL") assert sorted(schema_event["tags"]) == [ + 'dbms_flavor:{}'.format(common.MYSQL_FLAVOR.lower()), 'dd.internal.resource:database_instance:stubbed.hostname', 'port:13306', 'tag1:value1', diff --git a/mysql/tests/test_mysql.py b/mysql/tests/test_mysql.py index f2baef2e86ec6..e732801b59b3e 100644 --- a/mysql/tests/test_mysql.py +++ b/mysql/tests/test_mysql.py @@ -3,7 +3,6 @@ # Licensed under a 3-clause BSD style license (see LICENSE) import copy import logging -from os import environ import mock import pytest @@ -118,7 +117,7 @@ def test_e2e(dd_agent_check, dd_default_hostname, instance_complex): _assert_complex_config( aggregator, tags.SC_TAGS + [tags.DATABASE_INSTANCE_RESOURCE_TAG.format(hostname=dd_default_hostname)], - tags.METRIC_TAGS, + tags.METRIC_TAGS + ['dbms_flavor:{}'.format(MYSQL_FLAVOR.lower())], hostname=dd_default_hostname, e2e=True, ) @@ -313,7 +312,7 @@ def test_complex_config_replica(aggregator, dd_run_check, instance_complex): + variables.REPLICATION_OPERATION_TIME_METRICS ) - if MYSQL_VERSION_PARSED >= parse_version('5.6') and environ.get('MYSQL_FLAVOR') != 'mariadb': + if MYSQL_VERSION_PARSED >= parse_version('5.6') and MYSQL_FLAVOR != 'mariadb': testable_metrics.extend(variables.PERFORMANCE_VARS + variables.COMMON_PERFORMANCE_VARS) operation_time_metrics.extend( variables.COMMON_PERFORMANCE_OPERATION_TIME_METRICS + variables.PERFORMANCE_OPERATION_TIME_METRICS diff --git a/mysql/tests/test_query_activity.py b/mysql/tests/test_query_activity.py index 01695b84e2e2c..5189f4b23be6e 100644 --- a/mysql/tests/test_query_activity.py +++ b/mysql/tests/test_query_activity.py @@ -10,7 +10,6 @@ from contextlib import closing from copy import copy from datetime import datetime -from os import environ from threading import Event import mock @@ -23,7 +22,7 @@ from datadog_checks.mysql.activity import MySQLActivity from datadog_checks.mysql.util import StatementTruncationState -from .common import CHECK_NAME, HOST, MYSQL_VERSION_PARSED, PORT +from .common import CHECK_NAME, HOST, MYSQL_FLAVOR, MYSQL_VERSION_PARSED, PORT ACTIVITY_JSON_PLANS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "activity") @@ -59,7 +58,7 @@ def dbm_instance(instance_complex): 'SELECT id, name FROM testdb.users FOR UPDATE', ( '4d09873d44c33af7' - if MYSQL_VERSION_PARSED > parse_version('5.7') and environ.get('MYSQL_FLAVOR') != 'mariadb' + if MYSQL_VERSION_PARSED > parse_version('5.7') and MYSQL_FLAVOR != 'mariadb' else 'aca1be410fbadb61' ), StatementTruncationState.not_truncated.value, @@ -70,7 +69,7 @@ def dbm_instance(instance_complex): ), ( '4a12d7afe06cf40' - if environ.get('MYSQL_FLAVOR') == 'mariadb' + if MYSQL_FLAVOR == 'mariadb' else ('da7d6b1e9deb88e' if MYSQL_VERSION_PARSED > parse_version('5.7') else '63bd1fd025c7f7fb') ), StatementTruncationState.truncated.value, @@ -113,7 +112,12 @@ def _run_blocking(conn): assert activity['dbm_type'] == 'activity' assert activity['ddsource'] == 'mysql' assert activity['ddagentversion'], "missing agent version" - assert set(activity['ddtags']) == {'tag1:value1', 'tag2:value2', 'port:13306'} + assert set(activity['ddtags']) == { + 'tag1:value1', + 'tag2:value2', + 'port:13306', + 'dbms_flavor:{}'.format(MYSQL_FLAVOR.lower()), + } assert type(activity['collection_interval']) in (float, int), "invalid collection_interval" assert activity['mysql_activity'], "should have at least one activity row" @@ -132,8 +136,7 @@ def _run_blocking(conn): # sql text length limits expected_sql_text = ( query[:1021] + '...' - if len(query) > 1024 - and (MYSQL_VERSION_PARSED == parse_version('5.6') or environ.get('MYSQL_FLAVOR') == 'mariadb') + if len(query) > 1024 and (MYSQL_VERSION_PARSED == parse_version('5.6') or MYSQL_FLAVOR == 'mariadb') else query[:4093] + '...' if len(query) > 4096 else query ) assert blocked_row['sql_text'] == expected_sql_text @@ -193,7 +196,7 @@ def test_activity_metadata(aggregator, dd_run_check, dbm_instance, datadog_agent """ query_signature = ( '4d09873d44c33af7' - if MYSQL_VERSION_PARSED > parse_version('5.7') and environ.get('MYSQL_FLAVOR') != 'mariadb' + if MYSQL_VERSION_PARSED > parse_version('5.7') and MYSQL_FLAVOR != 'mariadb' else 'e7f7cb251194df29' ) @@ -525,6 +528,7 @@ def _expected_dbm_job_err_tags(dbm_instance): 'job:query-activity', 'port:{}'.format(PORT), 'dd.internal.resource:database_instance:stubbed.hostname', + 'dbms_flavor:{}'.format(MYSQL_FLAVOR.lower()), ] @@ -539,7 +543,7 @@ def test_if_deadlock_metric_is_collected(aggregator, dd_run_check, dbm_instance) @pytest.mark.skipif( - environ.get('MYSQL_FLAVOR') == 'mariadb' or MYSQL_VERSION_PARSED < parse_version('8.0'), + MYSQL_FLAVOR == 'mariadb' or MYSQL_VERSION_PARSED < parse_version('8.0'), reason='Deadock count is not updated in MariaDB or older MySQL versions', ) @pytest.mark.integration diff --git a/mysql/tests/test_statements.py b/mysql/tests/test_statements.py index 7fdbfb87ca5a8..0f667e164c2af 100644 --- a/mysql/tests/test_statements.py +++ b/mysql/tests/test_statements.py @@ -20,7 +20,7 @@ from datadog_checks.mysql.statement_samples import StatementTruncationState from . import common -from .common import MYSQL_VERSION_PARSED +from .common import MYSQL_FLAVOR, MYSQL_VERSION_PARSED logger = logging.getLogger(__name__) @@ -853,7 +853,11 @@ def test_async_job_cancel(aggregator, dd_run_check, dbm_instance): def _expected_dbm_instance_tags(dbm_instance): - return dbm_instance.get('tags', []) + ['server:{}'.format(common.HOST), 'port:{}'.format(common.PORT)] + return dbm_instance.get('tags', []) + [ + 'server:{}'.format(common.HOST), + 'port:{}'.format(common.PORT), + 'dbms_flavor:{}'.format(MYSQL_FLAVOR.lower()), + ] # the inactive job metrics are emitted from the main integrations @@ -863,6 +867,7 @@ def _expected_dbm_job_err_tags(dbm_instance): 'port:{}'.format(common.PORT), 'server:{}'.format(common.HOST), 'dd.internal.resource:database_instance:stubbed.hostname', + 'dbms_flavor:{}'.format(common.MYSQL_FLAVOR.lower()), ]