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

pvillard31 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 6d5d007b951 NIFI-16298 Expose Primary Node and Cluster Coordinator 
role as Prometheus metrics (#11628)
6d5d007b951 is described below

commit 6d5d007b951587aa044beeb9019d9fa82b563a77
Author: Alexander <[email protected]>
AuthorDate: Fri Sep 25 15:22:35 2026 +0200

    NIFI-16298 Expose Primary Node and Cluster Coordinator role as Prometheus 
metrics (#11628)
---
 .../prometheusutil/ClusterMetricsRegistry.java     | 12 ++++
 .../nifi/prometheusutil/PrometheusMetricsUtil.java |  5 +-
 .../apache/nifi/web/StandardNiFiServiceFacade.java |  3 +-
 .../nifi/web/controller/ControllerFacade.java      | 14 +++++
 .../org/apache/nifi/web/api/TestFlowResource.java  | 64 +++++++++++++++-------
 5 files changed, 76 insertions(+), 22 deletions(-)

diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/prometheusutil/ClusterMetricsRegistry.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/prometheusutil/ClusterMetricsRegistry.java
index 462b2328812..787b6e22bc5 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/prometheusutil/ClusterMetricsRegistry.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/prometheusutil/ClusterMetricsRegistry.java
@@ -48,5 +48,17 @@ public class ClusterMetricsRegistry extends 
AbstractMetricsRegistry {
                 .help("The total number of nodes in this cluster")
                 .labelNames("instance")
                 .register(registry));
+
+        nameToGaugeMap.put("IS_PRIMARY_NODE", Gauge.build()
+                .name("cluster_is_primary_node")
+                .help("Whether this NiFi instance is the Primary Node. Values 
are 0 or 1")
+                .labelNames("instance")
+                .register(registry));
+
+        nameToGaugeMap.put("IS_CLUSTER_COORDINATOR", Gauge.build()
+                .name("cluster_is_cluster_coordinator")
+                .help("Whether this NiFi instance is the Cluster Coordinator. 
Values are 0 or 1")
+                .labelNames("instance")
+                .register(registry));
     }
 }
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/prometheusutil/PrometheusMetricsUtil.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/prometheusutil/PrometheusMetricsUtil.java
index 60c7d4d223a..1d799a0ab69 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/prometheusutil/PrometheusMetricsUtil.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/prometheusutil/PrometheusMetricsUtil.java
@@ -500,12 +500,15 @@ public class PrometheusMetricsUtil {
     }
 
     public static CollectorRegistry createClusterMetrics(final 
ClusterMetricsRegistry clusterMetricsRegistry, final String instId, final 
boolean isClustered, final boolean isConnectedToCluster,
-                                                         final int 
connectedNodeCount, final int totalNodeCount) {
+                                                         final int 
connectedNodeCount, final int totalNodeCount,
+                                                         final boolean 
isPrimaryNode, final boolean isClusterCoordinator) {
         final String instanceId = StringUtils.isEmpty(instId) ? 
DEFAULT_LABEL_STRING : instId;
         clusterMetricsRegistry.setDataPoint(isClustered ? 1 : 0, 
"IS_CLUSTERED", instanceId);
         clusterMetricsRegistry.setDataPoint(isConnectedToCluster ? 1 : 0, 
"IS_CONNECTED_TO_CLUSTER", instanceId);
         clusterMetricsRegistry.setDataPoint(connectedNodeCount, 
"CONNECTED_NODE_COUNT", instanceId);
         clusterMetricsRegistry.setDataPoint(totalNodeCount, 
"TOTAL_NODE_COUNT", instanceId);
+        clusterMetricsRegistry.setDataPoint(isPrimaryNode ? 1 : 0, 
"IS_PRIMARY_NODE", instanceId);
+        clusterMetricsRegistry.setDataPoint(isClusterCoordinator ? 1 : 0, 
"IS_CLUSTER_COORDINATOR", instanceId);
 
         return clusterMetricsRegistry.getRegistry();
     }
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index 8e2236e34ce..ad76675bf18 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -8236,7 +8236,8 @@ public class StandardNiFiServiceFacade implements 
NiFiServiceFacade {
         }
         final boolean isClustered = clusterCoordinator != null;
         final boolean isConnectedToCluster = isClustered() && 
clusterCoordinator.isConnected();
-        PrometheusMetricsUtil.createClusterMetrics(clusterMetricsRegistry, 
instanceId, isClustered, isConnectedToCluster, connectedNodeCount, 
totalNodeCount);
+        PrometheusMetricsUtil.createClusterMetrics(clusterMetricsRegistry, 
instanceId, isClustered, isConnectedToCluster, connectedNodeCount, 
totalNodeCount,
+                controllerFacade.isPrimary(), 
controllerFacade.isClusterCoordinator());
         Collection<AbstractMetricsRegistry> metricsRegistries = Arrays.asList(
                 nifiMetricsRegistry,
                 jvmMetricsRegistry,
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
index e9a2436aa61..d33b4156dfc 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
@@ -494,6 +494,20 @@ public class ControllerFacade implements Authorizable {
         return flowController.isClustered();
     }
 
+    /**
+     * @return true if this node is the Primary Node
+     */
+    public boolean isPrimary() {
+        return flowController.isPrimary();
+    }
+
+    /**
+     * @return true if this node is the Cluster Coordinator
+     */
+    public boolean isClusterCoordinator() {
+        return flowController.isClusterCoordinator();
+    }
+
     /**
      * Gets the name of this controller.
      *
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestFlowResource.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestFlowResource.java
index 3841ed70afe..602dd311304 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestFlowResource.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestFlowResource.java
@@ -139,6 +139,12 @@ public class TestFlowResource {
     private static final int COMPONENT_TYPE_VALUE_INDEX = 1;
     private static final String CLUSTER_TYPE_LABEL = "cluster";
     private static final String CLUSTER_LABEL_KEY = "instance";
+    private static final String IS_CLUSTERED_LABEL_KEY = 
"cluster_is_clustered";
+    private static final String IS_CONNECTED_TO_CLUSTER_LABEL_KEY = 
"cluster_is_connected_to_cluster";
+    private static final String CONNECTED_NODE_COUNT_LABEL_KEY = 
"cluster_connected_node_count";
+    private static final String TOTAL_NODE_COUNT_LABEL_KEY = 
"cluster_total_node_count";
+    private static final String IS_PRIMARY_NODE_LABEL_KEY = 
"cluster_is_primary_node";
+    private static final String IS_CLUSTER_COORDINATOR_LABEL_KEY = 
"cluster_is_cluster_coordinator";
     private static final String SAMPLE_REGISTRY_ID = 
"0e87642a-7720-4799-a3bd-04db74b86e85";
     private static final String SAMPLE_BRANCH_ID_A = 
"c302f541-976e-4c51-952d-345516444e3d";
     private static final String SAMPLE_BUCKET_ID_A = 
"23da421d-a8da-4fa3-939e-658d8f35b972";
@@ -295,13 +301,20 @@ public class TestFlowResource {
         assertTrue(metrics.containsKey(ROOT_FIELD_NAME));
 
         final List<Sample> registryList = metrics.get(ROOT_FIELD_NAME);
-        assertEquals(13, registryList.size());
-
-        final Map<String, Long> result = getResult(registryList);
-        assertEquals(3L, result.get(SAMPLE_NAME_JVM));
-        assertEquals(4L, result.get(SAMPLE_LABEL_VALUES_PROCESS_GROUP));
-        assertEquals(2L, result.get(SAMPLE_LABEL_VALUES_ROOT_PROCESS_GROUP));
-        assertEquals(4L, result.get(CLUSTER_LABEL_KEY));
+        assertEquals(15, registryList.size());
+
+        final Map<String, Long> sampleCounts = getSampleCounts(registryList);
+        assertEquals(3L, sampleCounts.get(SAMPLE_NAME_JVM));
+        assertEquals(4L, sampleCounts.get(SAMPLE_LABEL_VALUES_PROCESS_GROUP));
+        assertEquals(2L, 
sampleCounts.get(SAMPLE_LABEL_VALUES_ROOT_PROCESS_GROUP));
+        assertEquals(6L, sampleCounts.get(CLUSTER_LABEL_KEY));
+
+        assertSample(registryList, IS_CLUSTERED_LABEL_KEY, 1.0);
+        assertSample(registryList, IS_CONNECTED_TO_CLUSTER_LABEL_KEY, 1.0);
+        assertSample(registryList, CONNECTED_NODE_COUNT_LABEL_KEY, 2.0);
+        assertSample(registryList, TOTAL_NODE_COUNT_LABEL_KEY, 3.0);
+        assertSample(registryList, IS_PRIMARY_NODE_LABEL_KEY, 1.0);
+        assertSample(registryList, IS_CLUSTER_COORDINATOR_LABEL_KEY, 0.0);
     }
 
     @Test
@@ -320,8 +333,8 @@ public class TestFlowResource {
         final List<Sample> registryList = metrics.get(ROOT_FIELD_NAME);
         assertEquals(3, registryList.size());
 
-        final Map<String, Long> result = getResult(registryList);
-        assertEquals(3L, result.get(SAMPLE_NAME_JVM));
+        final Map<String, Long> sampleCounts = getSampleCounts(registryList);
+        assertEquals(3L, sampleCounts.get(SAMPLE_NAME_JVM));
     }
 
     @Test
@@ -340,8 +353,8 @@ public class TestFlowResource {
         final List<Sample> registryList = metrics.get(ROOT_FIELD_NAME);
         assertEquals(2, registryList.size());
 
-        final Map<String, Long> result = getResult(registryList);
-        assertEquals(2L, result.get(SAMPLE_NAME_JVM));
+        final Map<String, Long> sampleCounts = getSampleCounts(registryList);
+        assertEquals(2L, sampleCounts.get(SAMPLE_NAME_JVM));
     }
 
     @Test
@@ -360,8 +373,8 @@ public class TestFlowResource {
         final List<Sample> registryList = metrics.get(ROOT_FIELD_NAME);
         assertEquals(2, registryList.size());
 
-        final Map<String, Long> result = getResult(registryList);
-        assertEquals(2L, result.get(SAMPLE_LABEL_VALUES_ROOT_PROCESS_GROUP));
+        final Map<String, Long> sampleCounts = getSampleCounts(registryList);
+        assertEquals(2L, 
sampleCounts.get(SAMPLE_LABEL_VALUES_ROOT_PROCESS_GROUP));
     }
 
     @Test
@@ -381,9 +394,9 @@ public class TestFlowResource {
         final List<Sample> registryList = metrics.get(ROOT_FIELD_NAME);
         assertEquals(5, registryList.size());
 
-        final Map<String, Long> result = getResult(registryList);
-        assertEquals(3L, result.get(SAMPLE_NAME_JVM));
-        assertEquals(2L, result.get(SAMPLE_LABEL_VALUES_ROOT_PROCESS_GROUP));
+        final Map<String, Long> sampleCounts = getSampleCounts(registryList);
+        assertEquals(3L, sampleCounts.get(SAMPLE_NAME_JVM));
+        assertEquals(2L, 
sampleCounts.get(SAMPLE_LABEL_VALUES_ROOT_PROCESS_GROUP));
     }
 
     @Test
@@ -1004,14 +1017,14 @@ public class TestFlowResource {
         return mapper.readValue(json, typeReference);
     }
 
-    private Map<String, Long> getResult(final List<Sample> registries) {
-        return registries.stream()
+    private Map<String, Long> getSampleCounts(final List<Sample> samples) {
+        return samples.stream()
                 .collect(Collectors.groupingBy(
-                        sample -> getResultKey(sample),
+                        sample -> getSampleKey(sample),
                         Collectors.counting()));
     }
 
-    private String getResultKey(final Sample sample) {
+    private String getSampleKey(final Sample sample) {
         if (sample.labelNames.contains(COMPONENT_TYPE_LABEL)) {
             return sample.labelValues.get(COMPONENT_TYPE_VALUE_INDEX);
         }
@@ -1021,6 +1034,15 @@ public class TestFlowResource {
         return SAMPLE_NAME_JVM;
     }
 
+    private void assertSample(final List<Sample> samples, final String 
sampleName, final double expectedValue) {
+        final Sample sample = samples.stream()
+                .filter(s -> sampleName.equals(s.name))
+                .findFirst()
+                .orElse(null);
+        assertNotNull(sample, String.format("Sample [%s] not found", 
sampleName));
+        assertEquals(expectedValue, sample.value);
+    }
+
     private static List<CollectorRegistry> getCollectorRegistriesForJson() {
         final List<CollectorRegistry> registryList = new ArrayList<>();
 
@@ -1087,6 +1109,8 @@ public class TestFlowResource {
         clusterMetricsRegistry.setDataPoint(1, "IS_CONNECTED_TO_CLUSTER", 
"B1Id");
         clusterMetricsRegistry.setDataPoint(2, "CONNECTED_NODE_COUNT", "B1Id");
         clusterMetricsRegistry.setDataPoint(3, "TOTAL_NODE_COUNT", "B1Id");
+        clusterMetricsRegistry.setDataPoint(1, "IS_PRIMARY_NODE", "B1Id");
+        clusterMetricsRegistry.setDataPoint(0, "IS_CLUSTER_COORDINATOR", 
"B1Id");
 
         return clusterMetricsRegistry.getRegistry();
     }

Reply via email to