Skip to content

Commit 54a4067

Browse files
authored
KAFKA-14559: Fix JMX tool to handle the object names with wildcard and optional attributes (apache#13060)
Reviewers: Federico Valeri <[email protected]>, Satish Duggana <[email protected]>
1 parent bd65db8 commit 54a4067

File tree

2 files changed

+153
-21
lines changed

2 files changed

+153
-21
lines changed

tools/src/main/java/org/apache/kafka/tools/JmxTool.java

+19-21
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public static void main(String[] args) {
8282
List<ObjectName> queries = options.queries();
8383
boolean hasPatternQueries = queries.stream().filter(Objects::nonNull).anyMatch(ObjectName::isPattern);
8484

85-
Set<ObjectName> found = findObjectsIfNoPattern(options, conn, queries, hasPatternQueries);
85+
Set<ObjectName> found = findObjects(options, conn, queries, hasPatternQueries);
8686
Map<ObjectName, Integer> numExpectedAttributes =
8787
findNumExpectedAttributes(conn, attributesInclude, hasPatternQueries, queries, found);
8888

@@ -113,8 +113,8 @@ public static void main(String[] args) {
113113
}
114114
}
115115

116-
private static String mkString(Stream<Object> stream, String delimeter) {
117-
return stream.filter(Objects::nonNull).map(Object::toString).collect(Collectors.joining(delimeter));
116+
private static String mkString(Stream<Object> stream, String delimiter) {
117+
return stream.filter(Objects::nonNull).map(Object::toString).collect(Collectors.joining(delimiter));
118118
}
119119

120120
private static int sumValues(Map<ObjectName, Integer> numExpectedAttributes) {
@@ -162,26 +162,24 @@ private static MBeanServerConnection connectToBeanServer(JmxToolOptions options)
162162
return serverConn;
163163
}
164164

165-
private static Set<ObjectName> findObjectsIfNoPattern(JmxToolOptions options,
166-
MBeanServerConnection conn,
167-
List<ObjectName> queries,
168-
boolean hasPatternQueries) throws Exception {
165+
private static Set<ObjectName> findObjects(JmxToolOptions options,
166+
MBeanServerConnection conn,
167+
List<ObjectName> queries,
168+
boolean hasPatternQueries) throws Exception {
169169
long waitTimeoutMs = 10_000;
170170
Set<ObjectName> result = new HashSet<>();
171171
Set<ObjectName> querySet = new HashSet<>(queries);
172-
BiPredicate<Set<ObjectName>, Set<ObjectName>> foundAllObjects = (s1, s2) -> s1.containsAll(s2);
173-
if (!hasPatternQueries) {
174-
long start = System.currentTimeMillis();
175-
do {
176-
if (!result.isEmpty()) {
177-
System.err.println("Could not find all object names, retrying");
178-
TimeUnit.MILLISECONDS.sleep(100);
179-
}
180-
result.addAll(queryObjects(conn, queries));
181-
} while (options.hasWait() && System.currentTimeMillis() - start < waitTimeoutMs && !foundAllObjects.test(querySet, result));
182-
}
172+
BiPredicate<Set<ObjectName>, Set<ObjectName>> foundAllObjects = Set::containsAll;
173+
long start = System.currentTimeMillis();
174+
do {
175+
if (!result.isEmpty()) {
176+
System.err.println("Could not find all object names, retrying");
177+
TimeUnit.MILLISECONDS.sleep(100);
178+
}
179+
result.addAll(queryObjects(conn, queries));
180+
} while (!hasPatternQueries && options.hasWait() && System.currentTimeMillis() - start < waitTimeoutMs && !foundAllObjects.test(querySet, result));
183181

184-
if (options.hasWait() && !foundAllObjects.test(querySet, result)) {
182+
if (!hasPatternQueries && options.hasWait() && !foundAllObjects.test(querySet, result)) {
185183
querySet.removeAll(result);
186184
String missing = mkString(querySet.stream().map(Object::toString), ",");
187185
throw new TerseException(String.format("Could not find all requested object names after %d ms. Missing %s", waitTimeoutMs, missing));
@@ -218,7 +216,7 @@ private static Map<ObjectName, Integer> findNumExpectedAttributes(MBeanServerCon
218216
}
219217
});
220218
} else {
221-
if (!hasPatternQueries) {
219+
if (hasPatternQueries) {
222220
found.forEach(objectName -> {
223221
try {
224222
MBeanInfo mBeanInfo = conn.getMBeanInfo(objectName);
@@ -237,7 +235,7 @@ private static Map<ObjectName, Integer> findNumExpectedAttributes(MBeanServerCon
237235
}
238236
});
239237
} else {
240-
queries.forEach(objectName -> result.put(objectName, attributesInclude.get().length));
238+
found.forEach(objectName -> result.put(objectName, attributesInclude.get().length));
241239
}
242240
}
243241

tools/src/test/java/org/apache/kafka/tools/JmxToolTest.java

+134
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,140 @@ public void filteredMetrics() {
174174
assertEquals("3.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FiveMinuteRate"));
175175
}
176176

177+
@Test
178+
public void testDomainNamePattern() {
179+
String[] args = new String[]{
180+
"--jmx-url", jmxUrl,
181+
"--object-name", "kafka.serve?:*",
182+
"--attributes", "FifteenMinuteRate,FiveMinuteRate",
183+
"--report-format", "csv",
184+
"--one-time"
185+
};
186+
String out = executeAndGetOut(args);
187+
assertNormalExit();
188+
189+
Map<String, String> csv = parseCsv(out);
190+
assertEquals("1.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FifteenMinuteRate"));
191+
assertEquals("3.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FiveMinuteRate"));
192+
}
193+
194+
@Test
195+
public void testDomainNamePatternWithNoAttributes() {
196+
String[] args = new String[]{
197+
"--jmx-url", jmxUrl,
198+
"--object-name", "kafka.serve?:*",
199+
"--report-format", "csv",
200+
"--one-time"
201+
};
202+
String out = executeAndGetOut(args);
203+
assertNormalExit();
204+
205+
Map<String, String> csv = parseCsv(out);
206+
assertEquals("1.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FifteenMinuteRate"));
207+
assertEquals("3.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FiveMinuteRate"));
208+
}
209+
210+
@Test
211+
public void testPropertyListPattern() {
212+
String[] args = new String[]{
213+
"--jmx-url", jmxUrl,
214+
"--object-name", "kafka.server:type=BrokerTopicMetrics,*",
215+
"--attributes", "FifteenMinuteRate,FiveMinuteRate",
216+
"--report-format", "csv",
217+
"--one-time"
218+
};
219+
String out = executeAndGetOut(args);
220+
assertNormalExit();
221+
222+
Map<String, String> csv = parseCsv(out);
223+
assertEquals("1.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FifteenMinuteRate"));
224+
assertEquals("3.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FiveMinuteRate"));
225+
}
226+
227+
@Test
228+
public void testPropertyListPatternWithNoAttributes() {
229+
String[] args = new String[]{
230+
"--jmx-url", jmxUrl,
231+
"--object-name", "kafka.server:type=BrokerTopicMetrics,*",
232+
"--report-format", "csv",
233+
"--one-time"
234+
};
235+
String out = executeAndGetOut(args);
236+
assertNormalExit();
237+
238+
Map<String, String> csv = parseCsv(out);
239+
assertEquals("1.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FifteenMinuteRate"));
240+
assertEquals("3.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FiveMinuteRate"));
241+
}
242+
243+
@Test
244+
public void testPropertyValuePattern() {
245+
String[] args = new String[]{
246+
"--jmx-url", jmxUrl,
247+
"--object-name", "kafka.server:type=BrokerTopicMetrics,name=*InPerSec",
248+
"--attributes", "FifteenMinuteRate,FiveMinuteRate",
249+
"--report-format", "csv",
250+
"--one-time"
251+
};
252+
String out = executeAndGetOut(args);
253+
assertNormalExit();
254+
255+
Map<String, String> csv = parseCsv(out);
256+
assertEquals("1.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FifteenMinuteRate"));
257+
assertEquals("3.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FiveMinuteRate"));
258+
}
259+
260+
@Test
261+
public void testPropertyValuePatternWithNoAttributes() {
262+
String[] args = new String[]{
263+
"--jmx-url", jmxUrl,
264+
"--object-name", "kafka.server:type=BrokerTopicMetrics,name=*InPerSec",
265+
"--report-format", "csv",
266+
"--one-time"
267+
};
268+
String out = executeAndGetOut(args);
269+
assertNormalExit();
270+
271+
Map<String, String> csv = parseCsv(out);
272+
assertEquals("1.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FifteenMinuteRate"));
273+
assertEquals("3.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FiveMinuteRate"));
274+
}
275+
276+
@Test
277+
// Combination of property-list and property-value patterns
278+
public void testPropertyPattern() {
279+
String[] args = new String[]{
280+
"--jmx-url", jmxUrl,
281+
"--object-name", "kafka.server:type=*,*",
282+
"--attributes", "FifteenMinuteRate,FiveMinuteRate",
283+
"--report-format", "csv",
284+
"--one-time"
285+
};
286+
String out = executeAndGetOut(args);
287+
assertNormalExit();
288+
289+
Map<String, String> csv = parseCsv(out);
290+
assertEquals("1.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FifteenMinuteRate"));
291+
assertEquals("3.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FiveMinuteRate"));
292+
}
293+
294+
@Test
295+
// Combination of property-list and property-value patterns
296+
public void testPropertyPatternWithNoAttributes() {
297+
String[] args = new String[]{
298+
"--jmx-url", jmxUrl,
299+
"--object-name", "kafka.server:type=*,*",
300+
"--report-format", "csv",
301+
"--one-time"
302+
};
303+
String out = executeAndGetOut(args);
304+
assertNormalExit();
305+
306+
Map<String, String> csv = parseCsv(out);
307+
assertEquals("1.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FifteenMinuteRate"));
308+
assertEquals("3.0", csv.get("kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec:FiveMinuteRate"));
309+
}
310+
177311
@Test
178312
public void dateFormat() {
179313
String dateFormat = "yyyyMMdd-hh:mm:ss";

0 commit comments

Comments
 (0)