Bladeren bron

Get only numeric values of JMX metrics (#318)

* Use only numeric JMX metrics
* Propagate all exceptions from JmxClusterUtil.getJmxMetric to upper call
Ildar Almakaev 4 jaren geleden
bovenliggende
commit
e9a0a1af91

+ 21 - 41
kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/JmxClusterUtil.java

@@ -1,11 +1,10 @@
 package com.provectus.kafka.ui.util;
 package com.provectus.kafka.ui.util;
 
 
 import com.provectus.kafka.ui.model.Metric;
 import com.provectus.kafka.ui.model.Metric;
-import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.BigDecimal;
-import java.net.MalformedURLException;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.List;
@@ -13,16 +12,12 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
-import javax.management.AttributeNotFoundException;
-import javax.management.InstanceNotFoundException;
 import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanAttributeInfo;
-import javax.management.MBeanException;
 import javax.management.MBeanServerConnection;
 import javax.management.MBeanServerConnection;
-import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
 import javax.management.ObjectName;
-import javax.management.ReflectionException;
 import javax.management.remote.JMXConnector;
 import javax.management.remote.JMXConnector;
 import lombok.RequiredArgsConstructor;
 import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.pool2.KeyedObjectPool;
 import org.apache.commons.pool2.KeyedObjectPool;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
@@ -38,12 +33,19 @@ public class JmxClusterUtil {
   private static final String NAME_METRIC_FIELD = "name";
   private static final String NAME_METRIC_FIELD = "name";
   private final KeyedObjectPool<String, JMXConnector> pool;
   private final KeyedObjectPool<String, JMXConnector> pool;
 
 
+  @SneakyThrows
   public List<Metric> getJmxMetrics(int jmxPort, String jmxHost) {
   public List<Metric> getJmxMetrics(int jmxPort, String jmxHost) {
     String jmxUrl = JMX_URL + jmxHost + ":" + jmxPort + "/" + JMX_SERVICE_TYPE;
     String jmxUrl = JMX_URL + jmxHost + ":" + jmxPort + "/" + JMX_SERVICE_TYPE;
-    List<Metric> result = new ArrayList<>();
-    JMXConnector srv = null;
+    JMXConnector srv;
     try {
     try {
       srv = pool.borrowObject(jmxUrl);
       srv = pool.borrowObject(jmxUrl);
+    } catch (Exception e) {
+      log.error("Cannot get JMX connector for the pool due to: ", e);
+      return Collections.emptyList();
+    }
+
+    List<Metric> result = new ArrayList<>();
+    try {
       MBeanServerConnection msc = srv.getMBeanServerConnection();
       MBeanServerConnection msc = srv.getMBeanServerConnection();
       var jmxMetrics = msc.queryNames(null, null).stream()
       var jmxMetrics = msc.queryNames(null, null).stream()
           .filter(q -> q.getCanonicalName().startsWith(KAFKA_SERVER_PARAM))
           .filter(q -> q.getCanonicalName().startsWith(KAFKA_SERVER_PARAM))
@@ -54,50 +56,28 @@ public class JmxClusterUtil {
         metric.setName(params.get(NAME_METRIC_FIELD));
         metric.setName(params.get(NAME_METRIC_FIELD));
         metric.setCanonicalName(jmxMetric.getCanonicalName());
         metric.setCanonicalName(jmxMetric.getCanonicalName());
         metric.setParams(params);
         metric.setParams(params);
-        metric.setValue(getJmxMetric(jmxMetric.getCanonicalName(), msc, srv, jmxUrl));
+        metric.setValue(getJmxMetric(jmxMetric.getCanonicalName(), msc));
         result.add(metric);
         result.add(metric);
       }
       }
       pool.returnObject(jmxUrl, srv);
       pool.returnObject(jmxUrl, srv);
-    } catch (IOException ioe) {
-      log.error("Cannot get jmxMetricsNames, {}", jmxUrl, ioe);
-      closeConnectionExceptionally(jmxUrl, srv);
     } catch (Exception e) {
     } catch (Exception e) {
-      log.error("Cannot get JmxConnection from pool, {}", jmxUrl, e);
+      log.error("Cannot get jmxMetricsNames, {}", jmxUrl, e);
       closeConnectionExceptionally(jmxUrl, srv);
       closeConnectionExceptionally(jmxUrl, srv);
     }
     }
     return result;
     return result;
   }
   }
 
 
 
 
-  private Map<String, BigDecimal> getJmxMetric(String canonicalName, MBeanServerConnection msc,
-                                               JMXConnector srv, String jmxUrl) {
+  @SneakyThrows
+  private Map<String, BigDecimal> getJmxMetric(String canonicalName, MBeanServerConnection msc) {
     Map<String, BigDecimal> resultAttr = new HashMap<>();
     Map<String, BigDecimal> resultAttr = new HashMap<>();
-    try {
-      ObjectName name = new ObjectName(canonicalName);
-      var attrNames = msc.getMBeanInfo(name).getAttributes();
-      for (MBeanAttributeInfo attrName : attrNames) {
-        var value = msc.getAttribute(name, attrName.getName());
-        if ((value instanceof Number)
-            && (!(value instanceof Double) || !((Double) value).isInfinite())) {
-          resultAttr.put(attrName.getName(), new BigDecimal(value.toString()));
-        }
+    ObjectName name = new ObjectName(canonicalName);
+    var attrNames = msc.getMBeanInfo(name).getAttributes();
+    for (MBeanAttributeInfo attrName : attrNames) {
+      var value = msc.getAttribute(name, attrName.getName());
+      if (NumberUtil.isNumeric(value)) {
+        resultAttr.put(attrName.getName(), new BigDecimal(value.toString()));
       }
       }
-    } catch (MalformedURLException url) {
-      log.error("Cannot create JmxServiceUrl from {}", jmxUrl);
-      closeConnectionExceptionally(jmxUrl, srv);
-    } catch (IOException io) {
-      log.error("Cannot connect to KafkaJmxServer with url {}", jmxUrl);
-      closeConnectionExceptionally(jmxUrl, srv);
-    } catch (MBeanException | AttributeNotFoundException
-        | InstanceNotFoundException | ReflectionException e) {
-      log.error("Cannot find attribute", e);
-      closeConnectionExceptionally(jmxUrl, srv);
-    } catch (MalformedObjectNameException objectNameE) {
-      log.error("Cannot create objectName", objectNameE);
-      closeConnectionExceptionally(jmxUrl, srv);
-    } catch (Exception e) {
-      log.error("Error while retrieving connection {} from pool", jmxUrl);
-      closeConnectionExceptionally(jmxUrl, srv);
     }
     }
     return resultAttr;
     return resultAttr;
   }
   }

+ 9 - 0
kafka-ui-api/src/main/java/com/provectus/kafka/ui/util/NumberUtil.java

@@ -0,0 +1,9 @@
+package com.provectus.kafka.ui.util;
+
+import org.apache.commons.lang3.math.NumberUtils;
+
+public class NumberUtil {
+  public static boolean isNumeric(Object value) {
+    return value != null && NumberUtils.isCreatable(value.toString());
+  }
+}

+ 28 - 0
kafka-ui-api/src/test/java/com/provectus/kafka/ui/util/NumberUtilTest.java

@@ -0,0 +1,28 @@
+package com.provectus.kafka.ui.util;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class NumberUtilTest {
+
+  @Test
+  void shouldReturnFalseWhenNonNumeric() {
+    Assertions.assertFalse(NumberUtil.isNumeric(Double.POSITIVE_INFINITY));
+    Assertions.assertFalse(NumberUtil.isNumeric(Double.NEGATIVE_INFINITY));
+    Assertions.assertFalse(NumberUtil.isNumeric(Double.NaN));
+    Assertions.assertFalse(NumberUtil.isNumeric(null));
+    Assertions.assertFalse(NumberUtil.isNumeric(" "));
+    Assertions.assertFalse(NumberUtil.isNumeric(new Object()));
+    Assertions.assertFalse(NumberUtil.isNumeric("1231asd"));
+  }
+
+  @Test
+  void shouldReturnTrueWhenNumeric() {
+    Assertions.assertTrue(NumberUtil.isNumeric("123.45"));
+    Assertions.assertTrue(NumberUtil.isNumeric(123.45));
+    Assertions.assertTrue(NumberUtil.isNumeric(123));
+    Assertions.assertTrue(NumberUtil.isNumeric(-123.45));
+    Assertions.assertTrue(NumberUtil.isNumeric(-1e-10));
+    Assertions.assertTrue(NumberUtil.isNumeric(1e-10));
+  }
+}