This is an automated email from the ASF dual-hosted git repository.

adoroszlai pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new 6ef19acbbc2 HDDS-15552. Ratis events should not be published as 
metrics (#10523)
6ef19acbbc2 is described below

commit 6ef19acbbc288080748d87c140c9d8a84d94bdbc
Author: Wei-Chiu Chuang <[email protected]>
AuthorDate: Mon Jul 6 23:40:16 2026 -0700

    HDDS-15552. Ratis events should not be published as metrics (#10523)
---
 .../container/placement/metrics/SCMMetrics.java    |  4 +-
 .../apache/hadoop/hdds/scm/server/SCMMXBean.java   |  2 +
 .../hdds/scm/server/StorageContainerManager.java   |  5 ++
 .../src/main/resources/webapps/scm/scm.js          |  4 +-
 hadoop-ozone/dist/src/main/compose/ozone/test.sh   |  2 +
 .../src/main/smoketest/prometheus/prometheus.robot | 29 +++++++++
 .../main/smoketest/prometheus/prometheus_check.py  | 76 ++++++++++++++++++++++
 .../org/apache/hadoop/hdds/scm/TestSCMMXBean.java  |  3 +
 .../java/org/apache/hadoop/ozone/om/OMMXBean.java  |  2 +
 .../java/org/apache/hadoop/ozone/om/OMMetrics.java |  4 +-
 .../org/apache/hadoop/ozone/om/OzoneManager.java   |  5 ++
 .../resources/webapps/ozoneManager/ozoneManager.js |  4 +-
 12 files changed, 134 insertions(+), 6 deletions(-)

diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/placement/metrics/SCMMetrics.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/placement/metrics/SCMMetrics.java
index d5dab7800c4..b746f7eaea1 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/placement/metrics/SCMMetrics.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/placement/metrics/SCMMetrics.java
@@ -180,7 +180,9 @@ public void addRatisEvent(String event) {
     }
   }
 
-  @Metric("Ratis state machine events")
+  // Ratis state machine events are multi-line logs, which should not be
+  // published as time-series metrics to metrics systems like Prometheus.
+  // Instead, they are exposed via JMX / MXBean endpoints.
   public String getRatisEvents() {
     synchronized (ratisEvents) {
       return String.join("\n", ratisEvents);
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMMXBean.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMMXBean.java
index 947484864e4..0fcc4625387 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMMXBean.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMMXBean.java
@@ -82,4 +82,6 @@ public interface SCMMXBean extends ServiceRuntimeInfo {
    * @return the SCM hostname for the datanode.
    */
   String getHostname();
+
+  String getRatisEvents();
 }
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
index 59a04d6a9a5..13e297b9cae 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
@@ -2243,6 +2243,11 @@ public String getHostname() {
     return scmHostName;
   }
 
+  @Override
+  public String getRatisEvents() {
+    return metrics != null ? metrics.getRatisEvents() : "";
+  }
+
   public Collection<String> getScmAdminUsernames() {
     return scmAdmins.getAdminUsernames();
   }
diff --git a/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js 
b/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js
index 27ecc7f8155..73ecda3d49c 100644
--- a/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js
+++ b/hadoop-hdds/server-scm/src/main/resources/webapps/scm/scm.js
@@ -30,10 +30,10 @@
         templateUrl: 'ratis-events.html',
         controller: function ($http) {
             var ctrl = this;
-            
$http.get("jmx?qry=Hadoop:service=StorageContainerManager,name=SCMMetrics")
+            
$http.get("jmx?qry=Hadoop:service=StorageContainerManager,name=StorageContainerManagerInfo,component=ServerRuntime")
                 .then(function (result) {
                     var metrics = result.data.beans[0];
-                  var rawEvents = metrics['tag.RatisEvents'] ? 
metrics['tag.RatisEvents'].split('\n') : [];
+                    var rawEvents = (metrics && metrics['RatisEvents']) ? 
metrics['RatisEvents'].split('\n') : [];
                     ctrl.events = rawEvents.map(function(e) {
                         var parts = e.split('|');
                         return {
diff --git a/hadoop-ozone/dist/src/main/compose/ozone/test.sh 
b/hadoop-ozone/dist/src/main/compose/ozone/test.sh
index 800f1c41f28..980d1487f80 100755
--- a/hadoop-ozone/dist/src/main/compose/ozone/test.sh
+++ b/hadoop-ozone/dist/src/main/compose/ozone/test.sh
@@ -24,6 +24,7 @@ export COMPOSE_DIR
 
 export SECURITY_ENABLED=false
 export OZONE_REPLICATION_FACTOR=3
+export COMPOSE_FILE=docker-compose.yaml:monitoring.yaml
 
 # shellcheck source=/dev/null
 source "$COMPOSE_DIR/../testlib.sh"
@@ -40,6 +41,7 @@ execute_robot_test scm gdpr
 execute_robot_test scm security/ozone-secure-token.robot
 
 execute_robot_test scm recon
+execute_robot_test scm prometheus
 
 execute_robot_test scm om-ratis
 
diff --git a/hadoop-ozone/dist/src/main/smoketest/prometheus/prometheus.robot 
b/hadoop-ozone/dist/src/main/smoketest/prometheus/prometheus.robot
new file mode 100644
index 00000000000..11cc7d6031a
--- /dev/null
+++ b/hadoop-ozone/dist/src/main/smoketest/prometheus/prometheus.robot
@@ -0,0 +1,29 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+*** Settings ***
+Documentation       Test Prometheus monitoring integration
+Library             OperatingSystem
+Library             BuiltIn
+Resource            ../commonlib.robot
+
+*** Test Cases ***
+Verify Prometheus targets are healthy
+    Wait Until Keyword Succeeds     90sec      10sec        Check Prometheus 
Targets Health
+
+*** Keywords ***
+Check Prometheus Targets Health
+    ${result} =         Execute     python3 
${OZONE_DIR}/smoketest/prometheus/prometheus_check.py
+    Should Contain      ${result}   Successfully verified
diff --git 
a/hadoop-ozone/dist/src/main/smoketest/prometheus/prometheus_check.py 
b/hadoop-ozone/dist/src/main/smoketest/prometheus/prometheus_check.py
new file mode 100644
index 00000000000..6fe85be8341
--- /dev/null
+++ b/hadoop-ozone/dist/src/main/smoketest/prometheus/prometheus_check.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import urllib.request
+import json
+import sys
+import socket
+
+def is_running(host, port):
+    try:
+        with socket.create_connection((host, int(port)), timeout=2):
+            return True
+    except Exception:
+        return False
+
+def main():
+    try:
+        res = urllib.request.urlopen("http://prometheus:9090/api/v1/targets";)
+        data = json.loads(res.read().decode())
+        targets = data.get("data", {}).get("activeTargets", [])
+        if not targets:
+            print("No active targets found in Prometheus")
+            sys.exit(1)
+            
+        failed = False
+        checked = 0
+        for t in targets:
+            url = t.get("scrapeUrl", "")
+            # scrapeUrl is like "http://scm:9876/prom";
+            try:
+                host_port = url.split("//")[1].split("/")[0]
+                if ":" in host_port:
+                    host, port = host_port.split(":")
+                else:
+                    host = host_port
+                    port = 80
+            except Exception:
+                continue
+                
+            if is_running(host, port):
+                checked += 1
+                health = t.get("health", "")
+                print(f"Target {host}:{port} is running. Prometheus health: 
{health}")
+                if health != "up":
+                    print(f"Error: Target {host}:{port} is running but 
Prometheus health is '{health}'. Last error: {t.get('lastError')}")
+                    failed = True
+            else:
+                print(f"Target {host}:{port} is not running. Skipping check.")
+                
+        if checked == 0:
+            print("Error: No running targets were checked!")
+            sys.exit(1)
+            
+        if failed:
+            sys.exit(1)
+            
+        print(f"Successfully verified {checked} running targets.")
+    except Exception as e:
+        print(f"Exception during health check: {e}")
+        sys.exit(1)
+
+if __name__ == "__main__":
+    main()
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/TestSCMMXBean.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/TestSCMMXBean.java
index bde82b2ab95..f2ae925dcbd 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/TestSCMMXBean.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/TestSCMMXBean.java
@@ -86,6 +86,9 @@ public void testSCMMXBean() throws Exception {
     double containerThreshold = (double) mbs.getAttribute(bean,
         "SafeModeCurrentContainerThreshold");
     assertEquals(scm.getCurrentContainerThreshold(), containerThreshold, 0);
+
+    String ratisEvents = (String) mbs.getAttribute(bean, "RatisEvents");
+    assertEquals(scm.getMetrics().getRatisEvents(), ratisEvents);
   }
 
   @Test
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMXBean.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMXBean.java
index 0e7488ae191..3d418ef8c83 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMXBean.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMXBean.java
@@ -41,4 +41,6 @@ public interface OMMXBean extends ServiceRuntimeInfo {
    * @return the OM hostname for the datanode.
    */
   String getHostname();
+
+  String getRatisEvents();
 }
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
index dc67f3c00d5..7725f7835ac 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
@@ -1627,7 +1627,9 @@ public void addRatisEvent(String event) {
     }
   }
 
-  @Metric("Ratis state machine events")
+  // Ratis state machine events are multi-line logs, which should not be
+  // published as time-series metrics to metrics systems like Prometheus.
+  // Instead, they are exposed via JMX / MXBean endpoints.
   public String getRatisEvents() {
     synchronized (ratisEvents) {
       return String.join("\n", ratisEvents);
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
index db7717c81ea..1910d92e969 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
@@ -3309,6 +3309,11 @@ public String getHostname() {
     return omHostName;
   }
 
+  @Override
+  public String getRatisEvents() {
+    return metrics != null ? metrics.getRatisEvents() : "";
+  }
+
   @VisibleForTesting
   public OzoneManagerHttpServer getHttpServer() {
     return httpServer;
diff --git 
a/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/ozoneManager.js
 
b/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/ozoneManager.js
index 313c79a3f08..2f501fc98d5 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/ozoneManager.js
+++ 
b/hadoop-ozone/ozone-manager/src/main/resources/webapps/ozoneManager/ozoneManager.js
@@ -173,10 +173,10 @@
         templateUrl: 'ratis-events.html',
         controller: function ($http) {
             var ctrl = this;
-            $http.get("jmx?qry=Hadoop:service=OzoneManager,name=OMMetrics")
+            
$http.get("jmx?qry=Hadoop:service=OzoneManager,name=OzoneManagerInfo,component=ServerRuntime")
                 .then(function (result) {
                     var metrics = result.data.beans[0];
-                    var rawEvents = metrics['tag.RatisEvents'] ? 
metrics['tag.RatisEvents'].split('\n') : [];
+                    var rawEvents = (metrics && metrics['RatisEvents']) ? 
metrics['RatisEvents'].split('\n') : [];
                     ctrl.events = rawEvents.map(function(e) {
                         var parts = e.split('|');
                         return {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to