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();
+ }
}