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

exceptionfactory 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 639a43c2ea NIFI-15250 Added Log Level Validator to LogMessage 
Processor (#10560)
639a43c2ea is described below

commit 639a43c2ea43a4d72d7f54892db22fcf645a50ec
Author: dan-s1 <[email protected]>
AuthorDate: Mon Nov 24 23:37:47 2025 -0500

    NIFI-15250 Added Log Level Validator to LogMessage Processor (#10560)
    
    Signed-off-by: David Handermann <[email protected]>
---
 .../nifi/processors/standard/LogMessage.java       | 28 +++++++++++-
 .../nifi/processors/standard/TestLogMessage.java   | 51 ++++++++++------------
 2 files changed, 50 insertions(+), 29 deletions(-)

diff --git 
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/LogMessage.java
 
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/LogMessage.java
index 35ac0a57fc..ccb9465c44 100644
--- 
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/LogMessage.java
+++ 
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/LogMessage.java
@@ -24,6 +24,8 @@ import org.apache.nifi.annotation.behavior.SupportsBatching;
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
 import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.ValidationResult;
+import org.apache.nifi.components.Validator;
 import org.apache.nifi.expression.ExpressionLanguageScope;
 import org.apache.nifi.flowfile.FlowFile;
 import org.apache.nifi.logging.ComponentLog;
@@ -39,6 +41,8 @@ import org.eclipse.jetty.util.StringUtil;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 @SideEffectFree
 @SupportsBatching(defaultDuration = DefaultRunDuration.TWENTY_FIVE_MILLIS)
@@ -47,11 +51,31 @@ import java.util.Set;
 @CapabilityDescription("Emits a log message at the specified log level")
 public class LogMessage extends AbstractProcessor {
 
+    private static final Pattern LOG_LEVEL_PATTERN = 
Pattern.compile("^(?i)(?:trace|debug|info|warn|error)$");
+    private static final Validator LOG_LEVEL_VALIDATOR = (subject, input, 
context) -> {
+        final boolean matches = LOG_LEVEL_PATTERN.matcher(input).matches();
+        if (matches || context.isExpressionLanguagePresent(input)) {
+            return (new ValidationResult.Builder())
+                    .subject(subject)
+                    .input(input)
+                    .valid(true)
+                    .build();
+        } else {
+            return (new ValidationResult.Builder())
+                    .subject(subject)
+                    .valid(false)
+                    .explanation(String.format("%s must be either trace, 
debug, info, warn or error", subject))
+                    .input(input)
+                    .build();
+        }
+    };
+
     public static final PropertyDescriptor LOG_LEVEL = new 
PropertyDescriptor.Builder()
             .name("Log Level")
             .required(true)
-            .description("The Log Level to use when logging the message: " + 
Arrays.toString(MessageLogLevel.values()))
-            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .description("The Log Level to use when logging the message: %s 
(case-insensitive)"
+                    
.formatted(Arrays.stream(MessageLogLevel.values()).map(Enum::name).collect(Collectors.joining(",
 "))))
+            .addValidator(LOG_LEVEL_VALIDATOR)
             .defaultValue(MessageLogLevel.info.toString())
             
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
             .build();
diff --git 
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestLogMessage.java
 
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestLogMessage.java
index dd0905cbd1..e172d45189 100644
--- 
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestLogMessage.java
+++ 
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestLogMessage.java
@@ -17,7 +17,6 @@
 
 package org.apache.nifi.processors.standard;
 
-import org.apache.nifi.logging.ComponentLog;
 import org.apache.nifi.reporting.InitializationException;
 import org.apache.nifi.util.MockComponentLog;
 import org.apache.nifi.util.MockFlowFile;
@@ -26,49 +25,33 @@ import org.apache.nifi.util.TestRunners;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
 
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class TestLogMessage {
 
-    private TestableLogMessage testableLogMessage;
     private TestRunner runner;
 
-    private static class TestableLogMessage extends LogMessage {
-
-        MockComponentLog getMockComponentLog() {
-            ComponentLog mockLog = getLogger();
-
-            if (!(mockLog instanceof MockComponentLog)) {
-                throw new IllegalStateException("Logger is expected to be 
MockComponentLog, but was: " +
-                        mockLog.getClass());
-            }
-
-            return (MockComponentLog) mockLog;
-        }
-
-
-    }
-
     @BeforeEach
-    public void before() throws InitializationException {
-        testableLogMessage = new TestableLogMessage();
-        runner = TestRunners.newTestRunner(testableLogMessage);
-
+    void before() throws InitializationException {
+        runner = TestRunners.newTestRunner(LogMessage.class);
     }
 
     @AfterEach
-    public void after() throws InitializationException {
+    void after() throws InitializationException {
         runner.shutdown();
     }
 
     @Test
-    public void testInfoMessageLogged() {
+    void testInfoMessageLogged() {
 
         runner.setProperty(LogMessage.LOG_MESSAGE, "This should help the 
operator to follow the flow: ${foobar}");
         runner.setProperty(LogMessage.LOG_LEVEL, 
LogMessage.MessageLogLevel.info.toString());
@@ -81,8 +64,9 @@ public class TestLogMessage {
         List<MockFlowFile> successFlowFiles = 
runner.getFlowFilesForRelationship(LogMessage.REL_SUCCESS);
         assertEquals(1, successFlowFiles.size());
 
-        MockComponentLog mockComponentLog = 
testableLogMessage.getMockComponentLog();
+        MockComponentLog mockComponentLog = runner.getLogger();
 
+        assertFalse(mockComponentLog.getInfoMessages().isEmpty());
         assertTrue(mockComponentLog.getTraceMessages().isEmpty());
         assertTrue(mockComponentLog.getDebugMessages().isEmpty());
         assertTrue(mockComponentLog.getWarnMessages().isEmpty());
@@ -90,7 +74,7 @@ public class TestLogMessage {
     }
 
     @Test
-    public void testInfoMessageWithPrefixLogged() {
+    void testInfoMessageWithPrefixLogged() {
 
         runner.setProperty(LogMessage.LOG_PREFIX, "FOOBAR>>>");
         runner.setProperty(LogMessage.LOG_MESSAGE, "This should help the 
operator to follow the flow: ${foobar}");
@@ -105,12 +89,25 @@ public class TestLogMessage {
         List<MockFlowFile> successFlowFiles = 
runner.getFlowFilesForRelationship(LogMessage.REL_SUCCESS);
         assertEquals(1, successFlowFiles.size());
 
-        MockComponentLog mockComponentLog = 
testableLogMessage.getMockComponentLog();
+        MockComponentLog mockComponentLog = runner.getLogger();
 
+        assertFalse(mockComponentLog.getInfoMessages().isEmpty());
         assertTrue(mockComponentLog.getTraceMessages().isEmpty());
         assertTrue(mockComponentLog.getDebugMessages().isEmpty());
         assertTrue(mockComponentLog.getWarnMessages().isEmpty());
         assertTrue(mockComponentLog.getErrorMessages().isEmpty());
     }
 
+    @Test
+    void testInvalidLogLevel() {
+        runner.setProperty(LogMessage.LOG_LEVEL, "whatever");
+        runner.assertNotValid();
+    }
+
+    @ParameterizedTest
+    @EnumSource(LogMessage.MessageLogLevel.class)
+    void testLogLevelCaseInsensitivity(LogMessage.MessageLogLevel logLevel) {
+        runner.setProperty(LogMessage.LOG_LEVEL, 
logLevel.name().toUpperCase());
+        runner.assertValid();
+    }
 }

Reply via email to