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 a5bc2d3cea9 NIFI-16139 Added Source and Destination to Connection 
Status Events (#11468)
a5bc2d3cea9 is described below

commit a5bc2d3cea95e834511365534ffac09f41d3c345
Author: David Handermann <[email protected]>
AuthorDate: Fri Jul 24 08:59:08 2026 -0500

    NIFI-16139 Added Source and Destination to Connection Status Events (#11468)
---
 .../controller/metrics/ConnectionStatusEvent.java  | 14 ++++++++
 .../repository/StandardProcessSession.java         | 30 +++++++++++++++-
 .../metrics/ConnectionStatusEventBuilder.java      | 20 +++++++++--
 .../metrics/StandardConnectionStatusEvent.java     | 12 +++++++
 .../repository/StandardProcessSessionTest.java     | 42 +++++++++++++++++++---
 5 files changed, 110 insertions(+), 8 deletions(-)

diff --git 
a/nifi-framework-api/src/main/java/org/apache/nifi/controller/metrics/ConnectionStatusEvent.java
 
b/nifi-framework-api/src/main/java/org/apache/nifi/controller/metrics/ConnectionStatusEvent.java
index d372489d59f..b1ed777b0e8 100644
--- 
a/nifi-framework-api/src/main/java/org/apache/nifi/controller/metrics/ConnectionStatusEvent.java
+++ 
b/nifi-framework-api/src/main/java/org/apache/nifi/controller/metrics/ConnectionStatusEvent.java
@@ -30,6 +30,20 @@ public interface ConnectionStatusEvent {
      */
     ComponentMetricContext getComponentMetricContext();
 
+    /**
+     * Get Component Metric Context describing the Source Component for the 
Connection
+     *
+     * @return Source Component Metric Context
+     */
+    ComponentMetricContext getSourceComponentMetricContext();
+
+    /**
+     * Get Component Metric Context describing the Destination Component for 
the Connection
+     *
+     * @return Destination Component Metric Context
+     */
+    ComponentMetricContext getDestinationComponentMetricContext();
+
     /**
      * Get configured Back Pressure Bytes Threshold
      *
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/StandardProcessSession.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/StandardProcessSession.java
index 28e200d25c5..baa398ec827 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/StandardProcessSession.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/StandardProcessSession.java
@@ -52,6 +52,7 @@ import org.apache.nifi.controller.status.FlowFileAvailability;
 import org.apache.nifi.controller.status.LoadBalanceStatus;
 import org.apache.nifi.flowfile.FlowFile;
 import org.apache.nifi.flowfile.attributes.CoreAttributes;
+import org.apache.nifi.groups.ProcessGroup;
 import org.apache.nifi.processor.DataUnit;
 import org.apache.nifi.processor.FlowFileFilter;
 import org.apache.nifi.processor.ProcessSession;
@@ -824,7 +825,19 @@ public class StandardProcessSession implements 
ProcessSession, ProvenanceEventEn
     private void recordConnectionStatusEvents(final Checkpoint checkpoint) {
         // Check enabled status to avoid building objects and calling methods 
when not used
         if (context.isRecordConnectionStatusEventEnabled()) {
+            final Map<String, ComponentMetricContext> 
connectableMetricContexts = new HashMap<>();
+
             for (final Connection connection : 
checkpoint.processedConnections.values()) {
+                final Connectable source = connection.getSource();
+                final ComponentMetricContext sourceContext = 
connectableMetricContexts.computeIfAbsent(source.getIdentifier(),
+                    id -> getComponentMetricContext(source)
+                );
+
+                final Connectable destination = connection.getDestination();
+                final ComponentMetricContext destinationContext = 
connectableMetricContexts.computeIfAbsent(destination.getIdentifier(),
+                        id -> getComponentMetricContext(destination)
+                );
+
                 final ComponentMetricContext connectionMetricContext = 
checkpoint.connectionMetricContexts.get(connection.getIdentifier());
                 final FlowFileQueue flowFileQueue = 
connection.getFlowFileQueue();
                 final QueueSize queueSize = flowFileQueue.size();
@@ -832,7 +845,11 @@ public class StandardProcessSession implements 
ProcessSession, ProvenanceEventEn
                 final LoadBalanceStatus loadBalanceStatus = 
getLoadBalanceStatus(flowFileQueue);
                 final FlowFileAvailability flowFileAvailability = 
flowFileQueue.getFlowFileAvailability();
 
-                final ConnectionStatusEvent connectionStatusEvent = 
ConnectionStatusEventBuilder.forComponent(connectionMetricContext)
+                final ConnectionStatusEvent connectionStatusEvent = 
ConnectionStatusEventBuilder.forComponent(
+                        connectionMetricContext,
+                        sourceContext,
+                        destinationContext
+                        )
                         .backPressureBytesThreshold(backPressureBytesThreshold)
                         
.backPressureObjectThreshold(flowFileQueue.getBackPressureObjectThreshold())
                         .queuedBytes(queueSize.getByteCount())
@@ -845,6 +862,17 @@ public class StandardProcessSession implements 
ProcessSession, ProvenanceEventEn
         }
     }
 
+    private ComponentMetricContext getComponentMetricContext(final Connectable 
connectable) {
+        final ProcessGroup processGroup = connectable.getProcessGroup();
+        final Map<String, String> attributes = processGroup == null ? Map.of() 
: processGroup.getLoggingAttributes();
+        return new ComponentMetricContext(
+                connectable.getIdentifier(),
+                connectable.getName(),
+                connectable.getComponentType(),
+                attributes
+        );
+    }
+
     private LoadBalanceStatus getLoadBalanceStatus(final FlowFileQueue 
flowFileQueue) {
         final LoadBalanceStatus loadBalanceStatus;
 
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/metrics/ConnectionStatusEventBuilder.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/metrics/ConnectionStatusEventBuilder.java
index 8c48a5e8e1a..515f1de4c8c 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/metrics/ConnectionStatusEventBuilder.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/metrics/ConnectionStatusEventBuilder.java
@@ -29,6 +29,8 @@ import java.util.Objects;
 public class ConnectionStatusEventBuilder {
 
     private final ComponentMetricContext componentMetricContext;
+    private final ComponentMetricContext sourceComponentMetricContext;
+    private final ComponentMetricContext destinationMetricContext;
 
     private long backPressureBytesThreshold;
     private long backPressureObjectThreshold;
@@ -37,12 +39,22 @@ public class ConnectionStatusEventBuilder {
     private LoadBalanceStatus loadBalanceStatus = 
LoadBalanceStatus.LOAD_BALANCE_NOT_CONFIGURED;
     private FlowFileAvailability flowFileAvailability = 
FlowFileAvailability.ACTIVE_QUEUE_EMPTY;
 
-    private ConnectionStatusEventBuilder(final ComponentMetricContext 
componentMetricContext) {
+    private ConnectionStatusEventBuilder(
+            final ComponentMetricContext componentMetricContext,
+            final ComponentMetricContext sourceComponentMetricContext,
+            final ComponentMetricContext destinationMetricContext
+    ) {
         this.componentMetricContext = 
Objects.requireNonNull(componentMetricContext, "Component Metric Context 
required");
+        this.sourceComponentMetricContext = 
Objects.requireNonNull(sourceComponentMetricContext, "Source Component Metric 
Context required");
+        this.destinationMetricContext = 
Objects.requireNonNull(destinationMetricContext, "Destination Component Metric 
Context required");
     }
 
-    public static ConnectionStatusEventBuilder forComponent(final 
ComponentMetricContext componentMetricContext) {
-        return new ConnectionStatusEventBuilder(componentMetricContext);
+    public static ConnectionStatusEventBuilder forComponent(
+            final ComponentMetricContext componentMetricContext,
+            final ComponentMetricContext sourceComponentMetricContext,
+            final ComponentMetricContext destinationMetricContext
+    ) {
+        return new ConnectionStatusEventBuilder(componentMetricContext, 
sourceComponentMetricContext, destinationMetricContext);
     }
 
     public ConnectionStatusEventBuilder backPressureBytesThreshold(final long 
backPressureBytesThreshold) {
@@ -78,6 +90,8 @@ public class ConnectionStatusEventBuilder {
     public ConnectionStatusEvent build() {
         return new StandardConnectionStatusEvent(
                 componentMetricContext,
+                sourceComponentMetricContext,
+                destinationMetricContext,
                 backPressureBytesThreshold,
                 backPressureObjectThreshold,
                 queuedBytes,
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/metrics/StandardConnectionStatusEvent.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/metrics/StandardConnectionStatusEvent.java
index 4f4b32a20a8..008bc295ddb 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/metrics/StandardConnectionStatusEvent.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/metrics/StandardConnectionStatusEvent.java
@@ -26,6 +26,8 @@ import org.apache.nifi.controller.status.LoadBalanceStatus;
  */
 record StandardConnectionStatusEvent(
         ComponentMetricContext componentMetricContext,
+        ComponentMetricContext sourceComponentMetricContext,
+        ComponentMetricContext destinationComponentMetricContext,
         long backPressureBytesThreshold,
         long backPressureObjectThreshold,
         long queuedBytes,
@@ -39,6 +41,16 @@ record StandardConnectionStatusEvent(
         return componentMetricContext;
     }
 
+    @Override
+    public ComponentMetricContext getSourceComponentMetricContext() {
+        return sourceComponentMetricContext;
+    }
+
+    @Override
+    public ComponentMetricContext getDestinationComponentMetricContext() {
+        return destinationComponentMetricContext;
+    }
+
     @Override
     public long getBackPressureBytesThreshold() {
         return backPressureBytesThreshold;
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/controller/repository/StandardProcessSessionTest.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/controller/repository/StandardProcessSessionTest.java
index 79ce3f98a0f..1516507e894 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/controller/repository/StandardProcessSessionTest.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/controller/repository/StandardProcessSessionTest.java
@@ -94,6 +94,11 @@ class StandardProcessSessionTest {
     private static final String BACK_PRESSURE_DATA_SIZE_THRESHOLD = "1 MB";
     private static final long BACK_PRESSURE_BYTES_THRESHOLD = 1048576;
 
+    private static final String SOURCE_CONNECTABLE_ID = "source-id";
+    private static final String SOURCE_CONNECTABLE_NAME = "source-name";
+    private static final String DESTINATION_CONNECTABLE_ID = "destination-id";
+    private static final String DESTINATION_CONNECTABLE_NAME = 
"destination-name";
+
     @Mock
     RepositoryContext repositoryContext;
 
@@ -181,7 +186,7 @@ class StandardProcessSessionTest {
         
when(repositoryContext.getContentRepository()).thenReturn(contentRepository);
         
when(repositoryContext.isRecordConnectionStatusEventEnabled()).thenReturn(true);
 
-        final Connection connection = mock(Connection.class);
+        final Connection connection = getConnection();
         
when(repositoryContext.getPollableConnections()).thenReturn(List.of(connection));
         final FlowFileRecord flowFileRecord = mock(FlowFileRecord.class);
         when(connection.poll(anySet())).thenReturn(flowFileRecord);
@@ -192,7 +197,7 @@ class StandardProcessSessionTest {
         final FlowFile flowFile = session.get();
         assertNotNull(flowFile);
 
-        final Connection outputConnection = mock(Connection.class);
+        final Connection outputConnection = getConnection();
         
when(outputConnection.getIdentifier()).thenReturn(OUTPUT_CONNECTION_ID);
         final FlowFileQueue outputFlowFileQueue = mock(FlowFileQueue.class);
         
when(outputFlowFileQueue.getBackPressureDataSizeThreshold()).thenReturn(BACK_PRESSURE_DATA_SIZE_THRESHOLD);
@@ -227,10 +232,12 @@ class StandardProcessSessionTest {
         assertEquals(objectCount, firstConnectionStatusEvent.getQueuedCount());
         assertEquals(byteCount, firstConnectionStatusEvent.getQueuedBytes());
         assertEquals(LoadBalanceStatus.LOAD_BALANCE_INACTIVE, 
firstConnectionStatusEvent.getLoadBalanceStatus());
+        assertSourceDestinationFound(firstConnectionStatusEvent);
 
         final ConnectionStatusEvent secondConnectionStatusEvent = 
events.getLast();
         final ComponentMetricContext secondComponentMetricContext = 
secondConnectionStatusEvent.getComponentMetricContext();
         assertEquals(OUTPUT_CONNECTION_ID, secondComponentMetricContext.id());
+        assertSourceDestinationFound(secondConnectionStatusEvent);
     }
 
     @Test
@@ -239,7 +246,7 @@ class StandardProcessSessionTest {
         
when(repositoryContext.getContentRepository()).thenReturn(contentRepository);
         
when(repositoryContext.isRecordConnectionStatusEventEnabled()).thenReturn(true);
 
-        final Connection connection = mock(Connection.class);
+        final Connection connection = getConnection();
         
when(repositoryContext.getPollableConnections()).thenReturn(List.of(connection));
         final FlowFileRecord flowFileRecord = mock(FlowFileRecord.class);
         when(connection.poll(anySet())).thenReturn(flowFileRecord);
@@ -272,7 +279,7 @@ class StandardProcessSessionTest {
         
when(repositoryContext.getContentRepository()).thenReturn(contentRepository);
         
when(repositoryContext.isRecordConnectionStatusEventEnabled()).thenReturn(true);
 
-        final Connection connection = mock(Connection.class);
+        final Connection connection = getConnection();
         
when(repositoryContext.getPollableConnections()).thenReturn(List.of(connection));
         final FlowFileRecord flowFileRecord = mock(FlowFileRecord.class);
         when(connection.poll(anySet())).thenReturn(flowFileRecord);
@@ -308,6 +315,7 @@ class StandardProcessSessionTest {
         assertEquals(byteCount, connectionStatusEvent.getQueuedBytes());
         assertEquals(LoadBalanceStatus.LOAD_BALANCE_NOT_CONFIGURED, 
connectionStatusEvent.getLoadBalanceStatus());
         assertEquals(FlowFileAvailability.FLOWFILE_AVAILABLE, 
connectionStatusEvent.getFlowFileAvailability());
+        assertSourceDestinationFound(connectionStatusEvent);
     }
 
     @Test
@@ -408,6 +416,16 @@ class StandardProcessSessionTest {
         assertEquals(bytesWritten, processSessionEvent.getBytesWritten(), 
"Process Session Bytes written not matched");
     }
 
+    private void assertSourceDestinationFound(final ConnectionStatusEvent 
connectionStatusEvent) {
+        final ComponentMetricContext source = 
connectionStatusEvent.getSourceComponentMetricContext();
+        assertEquals(SOURCE_CONNECTABLE_ID, source.id());
+        assertEquals(SOURCE_CONNECTABLE_NAME, source.name());
+
+        final ComponentMetricContext destination = 
connectionStatusEvent.getDestinationComponentMetricContext();
+        assertEquals(DESTINATION_CONNECTABLE_ID, destination.id());
+        assertEquals(DESTINATION_CONNECTABLE_NAME, destination.name());
+    }
+
     private void setRepositoryContext() {
         
when(repositoryContext.getProvenanceRepository()).thenReturn(provenanceRepository);
         
when(repositoryContext.getFlowFileRepository()).thenReturn(flowFileRepository);
@@ -420,4 +438,20 @@ class StandardProcessSessionTest {
         destination.toFile().deleteOnExit();
         return destination;
     }
+
+    private Connection getConnection() {
+        final Connection connection = mock(Connection.class);
+
+        final Connectable source = mock(Connectable.class);
+        when(source.getIdentifier()).thenReturn(SOURCE_CONNECTABLE_ID);
+        when(source.getName()).thenReturn(SOURCE_CONNECTABLE_NAME);
+        when(connection.getSource()).thenReturn(source);
+
+        final Connectable destination = mock(Connectable.class);
+        
when(destination.getIdentifier()).thenReturn(DESTINATION_CONNECTABLE_ID);
+        when(destination.getName()).thenReturn(DESTINATION_CONNECTABLE_NAME);
+        when(connection.getDestination()).thenReturn(destination);
+
+        return connection;
+    }
 }

Reply via email to