diff --git a/mysql/changelog.d/24178.fixed b/mysql/changelog.d/24178.fixed new file mode 100644 index 0000000000000..23269d78f189d --- /dev/null +++ b/mysql/changelog.d/24178.fixed @@ -0,0 +1 @@ +Fix MariaDB multi-channel replication reporting 0 channels by using SHOW ALL REPLICAS STATUS when no specific channel is configured. diff --git a/mysql/datadog_checks/mysql/mysql.py b/mysql/datadog_checks/mysql/mysql.py index 484ebca359fb0..5eca8abd9098a 100644 --- a/mysql/datadog_checks/mysql/mysql.py +++ b/mysql/datadog_checks/mysql/mysql.py @@ -1170,7 +1170,12 @@ def _get_replica_stats(self, db): for replica in replica_status: # MySQL <5.7 does not have Channel_Name. # For MySQL >=5.7 'Channel_Name' is set to an empty string by default - channel = self._config.replication_channel or replica.get('Channel_Name') or 'default' + channel = ( + self._config.replication_channel + or replica.get('Channel_Name') + or replica.get('Connection_name') + or 'default' + ) for key, value in replica.items(): if value is not None: replica_results[key]['channel:{0}'.format(channel)] = value diff --git a/mysql/datadog_checks/mysql/queries.py b/mysql/datadog_checks/mysql/queries.py index 76bd25bec4170..9c1d1e30e2c5d 100644 --- a/mysql/datadog_checks/mysql/queries.py +++ b/mysql/datadog_checks/mysql/queries.py @@ -288,13 +288,17 @@ def show_replica_status_query(version, is_mariadb: bool, channel: str = '') -> tuple[str, tuple[str, ...]]: if version.version_compatible((10, 5, 1)) or not is_mariadb and version.version_compatible((8, 0, 22)): - base_query = "SHOW REPLICA STATUS" + replica_keyword = "REPLICA" else: - base_query = "SHOW SLAVE STATUS" + replica_keyword = "SLAVE" + base_query = "SHOW {0} STATUS".format(replica_keyword) if channel and not is_mariadb: return ("{0} FOR CHANNEL %s".format(base_query), (channel,)) + elif is_mariadb and not channel: + # MariaDB uses Connection_name (not Channel_Name) to identify channels. + return ("SHOW ALL {0}S STATUS".format(replica_keyword), ()) else: - return ("{0}".format(base_query), ()) + return (base_query, ()) def get_indexes_query(version, is_mariadb, placeholders): diff --git a/mysql/tests/test_unit.py b/mysql/tests/test_unit.py index f99d0b6d93b46..9a601b0f68343 100644 --- a/mysql/tests/test_unit.py +++ b/mysql/tests/test_unit.py @@ -704,6 +704,20 @@ def test_collect_replication_metrics_returns_vars_when_has_replicas_connected(): assert results.get('Replicas_connected') == 2 +def test_get_replica_stats_tags_each_mariadb_connection(): + """Each MariaDB Connection_name maps to its own channel tag in _get_replica_stats.""" + mysql_check = MySql(common.CHECK_NAME, {}, instances=[{'server': 'localhost', 'user': 'datadog'}]) + mysql_check._config.replication_enabled = True + mysql_check._get_replica_replication_status = mock.MagicMock( + return_value=[ + {'Connection_name': 'conn_a', 'Seconds_Behind_Master': 1}, + {'Connection_name': 'conn_b', 'Seconds_Behind_Master': 2}, + ] + ) + results = mysql_check._get_replica_stats(mock.MagicMock()) + assert results['Seconds_Behind_Master'] == {'channel:conn_a': 1, 'channel:conn_b': 2} + + def test_source_with_zero_replicas_emits_warning_service_check(aggregator, instance_basic): """Test that a source with 0 connected replicas emits WARNING for replica-loss detection.""" mysql_check = MySql(common.CHECK_NAME, {}, instances=[instance_basic]) @@ -777,10 +791,28 @@ class TestShowReplicaStatusQuery: 'my-channel', 'SHOW REPLICA STATUS', (), - id='mariadb_ignores_channel', + id='mariadb_modern_with_channel', ), pytest.param( - '10.4.0-MariaDB', 'MariaDB', True, '', 'SHOW SLAVE STATUS', (), id='mariadb_legacy_no_channel' + '10.5.1-MariaDB', + 'MariaDB', + True, + '', + 'SHOW ALL REPLICAS STATUS', + (), + id='mariadb_modern_no_channel', + ), + pytest.param( + '10.4.0-MariaDB', 'MariaDB', True, '', 'SHOW ALL SLAVES STATUS', (), id='mariadb_legacy_no_channel' + ), + pytest.param( + '10.4.0-MariaDB', + 'MariaDB', + True, + 'my-channel', + 'SHOW SLAVE STATUS', + (), + id='mariadb_legacy_with_channel', ), ], )