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

showuon pushed a commit to branch 4.0
in repository https://gitbox.apache.org/repos/asf/kafka.git


The following commit(s) were added to refs/heads/4.0 by this push:
     new 4844bc3067c KAFKA-18984: Reset interval.ms By Using 
kafka-client-metrics.sh (#19213)
4844bc3067c is described below

commit 4844bc3067c579b88c75350366f1f57c0d1f5bec
Author: Parker Chang <parkerhiphop...@gmail.com>
AuthorDate: Mon Mar 24 18:53:49 2025 +0800

    KAFKA-18984: Reset interval.ms By Using kafka-client-metrics.sh (#19213)
    
    kafka-client-metrics.sh cannot reset the interval using `--interval=`.
    
    Reviewers: Andrew Schofield <aschofi...@confluent.io>
---
 .../apache/kafka/tools/ClientMetricsCommand.java   | 29 ++++++++++----
 .../kafka/tools/ClientMetricsCommandTest.java      | 46 ++++++++++++++++++++++
 2 files changed, 67 insertions(+), 8 deletions(-)

diff --git 
a/tools/src/main/java/org/apache/kafka/tools/ClientMetricsCommand.java 
b/tools/src/main/java/org/apache/kafka/tools/ClientMetricsCommand.java
index 58c187ba50a..abe305068af 100644
--- a/tools/src/main/java/org/apache/kafka/tools/ClientMetricsCommand.java
+++ b/tools/src/main/java/org/apache/kafka/tools/ClientMetricsCommand.java
@@ -119,7 +119,7 @@ public class ClientMetricsCommand {
             String entityName = opts.hasGenerateNameOption() ? 
Uuid.randomUuid().toString() : opts.name().get();
 
             Map<String, String> configsToBeSet = new HashMap<>();
-            opts.interval().map(intervalVal -> 
configsToBeSet.put("interval.ms", intervalVal.toString()));
+            opts.interval().map(intervalVal -> 
configsToBeSet.put("interval.ms", intervalVal));
             opts.metrics().map(metricslist -> configsToBeSet.put("metrics", 
String.join(",", metricslist)));
             opts.match().map(matchlist -> configsToBeSet.put("match", 
String.join(",", matchlist)));
 
@@ -210,7 +210,7 @@ public class ClientMetricsCommand {
 
         private final OptionSpecBuilder generateNameOpt;
 
-        private final ArgumentAcceptingOptionSpec<Integer> intervalOpt;
+        private final ArgumentAcceptingOptionSpec<String> intervalOpt;
 
         private final ArgumentAcceptingOptionSpec<String> matchOpt;
 
@@ -237,24 +237,25 @@ public class ClientMetricsCommand {
                 .describedAs("name")
                 .ofType(String.class);
             generateNameOpt = parser.accepts("generate-name", "Generate a UUID 
to use as the name.");
-            intervalOpt = parser.accepts("interval", "The metrics push 
interval in milliseconds.")
+            String nl = System.lineSeparator();
+
+            intervalOpt = parser.accepts("interval", "The metrics push 
interval in milliseconds." + nl + "Leave empty to reset the interval.")
                 .withRequiredArg()
                 .describedAs("push interval")
-                .ofType(java.lang.Integer.class);
+                .ofType(String.class);
 
-            String nl = System.lineSeparator();
 
             String[] matchSelectors = new String[] {
                 "client_id", "client_instance_id", "client_software_name",
                 "client_software_version", "client_source_address", 
"client_source_port"
             };
             String matchSelectorNames = 
Arrays.stream(matchSelectors).map(config -> "\t" + 
config).collect(Collectors.joining(nl));
-            matchOpt = parser.accepts("match",  "Matching selector 
'k1=v1,k2=v2'. The following is a list of valid selector names: " + nl + 
matchSelectorNames)
+            matchOpt = parser.accepts("match", "Matching selector 
'k1=v1,k2=v2'. The following is a list of valid selector names: " + nl + 
matchSelectorNames)
                 .withRequiredArg()
                 .describedAs("k1=v1,k2=v2")
                 .ofType(String.class)
                 .withValuesSeparatedBy(',');
-            metricsOpt = parser.accepts("metrics",  "Telemetry metric name 
prefixes 'm1,m2'.")
+            metricsOpt = parser.accepts("metrics", "Telemetry metric name 
prefixes 'm1,m2'.")
                 .withRequiredArg()
                 .describedAs("m1,m2")
                 .ofType(String.class)
@@ -329,7 +330,7 @@ public class ClientMetricsCommand {
             return valuesAsOption(metricsOpt);
         }
 
-        public Optional<Integer> interval() {
+        public Optional<String> interval() {
             return valueAsOption(intervalOpt);
         }
 
@@ -362,6 +363,18 @@ public class ClientMetricsCommand {
             if (has(alterOpt)) {
                 if ((isNamePresent && has(generateNameOpt)) || (!isNamePresent 
&& !has(generateNameOpt)))
                     throw new IllegalArgumentException("One of --name or 
--generate-name must be specified with --alter.");
+
+                interval().ifPresent(intervalStr -> {
+                    if (!intervalStr.isEmpty()) {
+                        try {
+                            Integer.parseInt(intervalStr);
+                        } catch (NumberFormatException e) {
+                            throw new IllegalArgumentException(
+                                    "Invalid interval value. Enter an integer, 
or leave empty to reset.");
+                        }
+                    }
+
+                });
             }
 
             if (has(deleteOpt) && !isNamePresent)
diff --git 
a/tools/src/test/java/org/apache/kafka/tools/ClientMetricsCommandTest.java 
b/tools/src/test/java/org/apache/kafka/tools/ClientMetricsCommandTest.java
index 804c70fd07c..c58748bf3c0 100644
--- a/tools/src/test/java/org/apache/kafka/tools/ClientMetricsCommandTest.java
+++ b/tools/src/test/java/org/apache/kafka/tools/ClientMetricsCommandTest.java
@@ -19,6 +19,7 @@ package org.apache.kafka.tools;
 
 import org.apache.kafka.clients.admin.Admin;
 import org.apache.kafka.clients.admin.AdminClientTestUtils;
+import org.apache.kafka.clients.admin.AlterConfigOp;
 import org.apache.kafka.clients.admin.AlterConfigsResult;
 import org.apache.kafka.clients.admin.Config;
 import org.apache.kafka.clients.admin.ConfigEntry;
@@ -29,11 +30,15 @@ import org.apache.kafka.common.protocol.Errors;
 import org.apache.kafka.common.utils.Exit;
 
 import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
 
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Map;
 import java.util.concurrent.ExecutionException;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
@@ -114,6 +119,14 @@ public class ClientMetricsCommandTest {
 
     }
 
+    @Test
+    public void testOptionsAlterInvalidInterval() {
+        Exception exception = assertThrows(IllegalArgumentException.class, () 
-> new ClientMetricsCommand.ClientMetricsCommandOptions(
+            new String[]{"--bootstrap-server", bootstrapServer, "--alter", 
"--name", clientMetricsName,
+                "--interval", "abc"}));
+        assertEquals("Invalid interval value. Enter an integer, or leave empty 
to reset.", exception.getMessage());
+    }
+
     @Test
     public void testAlter() {
         Admin adminClient = mock(Admin.class);
@@ -156,6 +169,39 @@ public class ClientMetricsCommandTest {
         assertTrue(capturedOutput.contains("Altered client metrics config"));
     }
 
+    @Test
+    public void testAlterResetConfigs() {
+        Admin adminClient = mock(Admin.class);
+        ClientMetricsCommand.ClientMetricsService service = new 
ClientMetricsCommand.ClientMetricsService(adminClient);
+
+        AlterConfigsResult result = 
AdminClientTestUtils.alterConfigsResult(new 
ConfigResource(ConfigResource.Type.CLIENT_METRICS, clientMetricsName));
+        @SuppressWarnings("unchecked")
+        final ArgumentCaptor<Map<ConfigResource, Collection<AlterConfigOp>>> 
configCaptor = ArgumentCaptor.forClass(Map.class);
+        when(adminClient.incrementalAlterConfigs(configCaptor.capture(), 
any())).thenReturn(result);
+
+        String capturedOutput = ToolsTestUtils.captureStandardOut(() -> {
+            try {
+                service.alterClientMetrics(new 
ClientMetricsCommand.ClientMetricsCommandOptions(
+                        new String[]{"--bootstrap-server", bootstrapServer, 
"--alter",
+                                     "--name", clientMetricsName, "--metrics", 
"",
+                                     "--interval", "", "--match", ""}));
+            } catch (Throwable t) {
+                fail(t);
+            }
+        });
+        Map<ConfigResource, Collection<AlterConfigOp>> alteredConfigOps = 
configCaptor.getValue();
+        assertNotNull(alteredConfigOps, "alteredConfigOps should not be null");
+        assertEquals(1, alteredConfigOps.size(), "Should have exactly one 
ConfigResource");
+        assertEquals(3, alteredConfigOps.values().iterator().next().size(), 
"Should have exactly 3 operations");
+        for (Collection<AlterConfigOp> operations : alteredConfigOps.values()) 
{
+            for (AlterConfigOp op : operations) {
+                assertEquals(AlterConfigOp.OpType.DELETE, op.opType(),
+                        "Expected DELETE operation for config: " + 
op.configEntry().name());
+            }
+        }
+        assertTrue(capturedOutput.contains("Altered client metrics config for 
" + clientMetricsName + "."));
+    }
+
     @Test
     public void testDelete() {
         Admin adminClient = mock(Admin.class);

Reply via email to