Skip to content

Commit

Permalink
More JMX debug logging
Browse files Browse the repository at this point in the history
  • Loading branch information
trask committed Mar 9, 2022
1 parent 745e508 commit a5141c3
Showing 1 changed file with 46 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@
package com.microsoft.applicationinsights.agent.internal.perfcounter;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;

import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -119,62 +118,51 @@ private static Map<String, Set<String>> getAvailableJmxAttributes() {
Map<String, Set<String>> availableJmxMetrics = new HashMap<>();
for (ObjectName objectName : objectNames) {
String name = objectName.toString();
Set<String> attrs;
try {
Set<String> attrs = getJmxAttributes(server, objectName);
if (!attrs.isEmpty()) {
availableJmxMetrics.put(name, attrs);
attrs = getAttributeDescriptions(server, objectName);
if (attrs.isEmpty()) {
attrs.add("<no numeric attributes found>");
}
} catch (Exception e) {
attrs = singleton("<error getting attributes: " + e);
// log exception at trace level since this is expected in several cases, e.g.
// "java.lang.UnsupportedOperationException: CollectionUsage threshold is not supported"
// and available jmx metrics are already only logged at debug
logger.trace(e.getMessage(), e);
availableJmxMetrics.put(name, Collections.singleton("<error getting attributes: " + e));
}
availableJmxMetrics.put(name, attrs);
}
return availableJmxMetrics;
}

private static Set<String> getJmxAttributes(MBeanServer server, ObjectName objectName)
private static Set<String> getAttributeDescriptions(MBeanServer server, ObjectName objectName)
throws Exception {
MBeanInfo mbeanInfo = server.getMBeanInfo(objectName);
Set<String> attributeNames = new HashSet<>();
Set<String> numericAttributeNames = new HashSet<>();
for (MBeanAttributeInfo attribute : mbeanInfo.getAttributes()) {
if (attribute.isReadable()) {
try {
Object value = server.getAttribute(objectName, attribute.getName());
attributeNames.addAll(getNumericAttributes(attribute, value));
} catch (Exception e) {
// log exception at trace level since this is expected in several cases, e.g.
// "java.lang.UnsupportedOperationException: CollectionUsage threshold is not supported"
// and available jmx metrics are already only logged at debug
logger.trace(e.getMessage(), e);
}
if (!attribute.isReadable()) {
numericAttributeNames.add(attribute.getName() + " (not readable)");
continue;
}
try {
Object value = server.getAttribute(objectName, attribute.getName());
numericAttributeNames.addAll(getAttributeDescriptions(attribute, value));
} catch (Exception e) {
// log exception at trace level since this is expected in several cases, e.g.
// "java.lang.UnsupportedOperationException: CollectionUsage threshold is not supported"
// and available jmx metrics are already only logged at debug
logger.trace(e.getMessage(), e);
}
}
return attributeNames;
return numericAttributeNames;
}

private static List<String> getNumericAttributes(MBeanAttributeInfo attribute, Object value) {
private static List<String> getAttributeDescriptions(
MBeanAttributeInfo attribute, @Nullable Object value) {

String attributeType = attribute.getType();
if (NUMERIC_ATTRIBUTE_TYPES.contains(attributeType) && value instanceof Number) {
return singletonList(attribute.getName());
}
if (BOOLEAN_ATTRIBUTE_TYPES.contains(attributeType) && value instanceof Boolean) {
return singletonList(attribute.getName());
}
if (attributeType.equals("java.lang.Object") && value instanceof Number) {
return singletonList(attribute.getName());
}
if (attributeType.equals("java.lang.String") && value instanceof String) {
try {
Double.parseDouble((String) value);
return singletonList(attribute.getName());
} catch (NumberFormatException e) {
// this is expected for non-numeric attributes
return emptyList();
}
}

if (attributeType.equals(CompositeData.class.getName())) {
Object openType = attribute.getDescriptor().getFieldValue("openType");
CompositeType compositeType = null;
Expand All @@ -187,7 +175,8 @@ private static List<String> getNumericAttributes(MBeanAttributeInfo attribute, O
return getCompositeTypeAttributeNames(attribute, value, compositeType);
}
}
return emptyList();

return singletonList(attribute.getName() + "(" + attributeType + "/" + valueType(value));
}

private static List<String> getCompositeTypeAttributeNames(
Expand Down Expand Up @@ -223,6 +212,24 @@ private static List<String> getCompositeTypeAttributeNames(
return attributeNames;
}

private static String valueType(@Nullable Object value) {
if (value instanceof Number) {
return "Number";
}
if (value instanceof Boolean) {
return "Boolean";
}
if (value instanceof String) {
try {
Double.parseDouble((String) value);
return "Number";
} catch (NumberFormatException e) {
return "String";
}
}
return value == null ? null : value.getClass().getName();
}

// visible for testing
static Map<String, Set<String>> difference(
Map<String, Set<String>> map1, Map<String, Set<String>> map2) {
Expand Down

0 comments on commit a5141c3

Please sign in to comment.