Skip to content

Commit 5619f0f

Browse files
authored
More JMX debug logging (#2157)
* More JMX debug logging * Add TODO
1 parent 745e508 commit 5619f0f

File tree

1 file changed

+65
-86
lines changed

1 file changed

+65
-86
lines changed

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/perfcounter/AvailableJmxMetricLogger.java

Lines changed: 65 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,11 @@
2121

2222
package com.microsoft.applicationinsights.agent.internal.perfcounter;
2323

24-
import static java.util.Arrays.asList;
25-
import static java.util.Collections.emptyList;
24+
import static java.util.Collections.singleton;
2625
import static java.util.Collections.singletonList;
2726

2827
import java.lang.management.ManagementFactory;
2928
import java.util.ArrayList;
30-
import java.util.Collections;
3129
import java.util.HashMap;
3230
import java.util.HashSet;
3331
import java.util.List;
@@ -47,35 +45,21 @@
4745
import org.slf4j.Logger;
4846
import org.slf4j.LoggerFactory;
4947

48+
// TODO (trask) add tests
5049
class AvailableJmxMetricLogger {
5150

5251
private static final Logger logger = LoggerFactory.getLogger(AvailableJmxMetricLogger.class);
5352

54-
private static final Set<String> NUMERIC_ATTRIBUTE_TYPES =
55-
new HashSet<>(
56-
asList(
57-
"long",
58-
"int",
59-
"double",
60-
"float",
61-
"java.lang.Long",
62-
"java.lang.Integer",
63-
"java.lang.Double",
64-
"java.lang.Float"));
65-
66-
private static final Set<String> BOOLEAN_ATTRIBUTE_TYPES =
67-
new HashSet<>(asList("boolean", "java.lang.Boolean"));
68-
6953
@GuardedBy("lock")
70-
private Map<String, Set<String>> priorAvailableJmxAttributes = new HashMap<>();
54+
private Map<String, Set<String>> priorAttributeMap = new HashMap<>();
7155

7256
private final Object lock = new Object();
7357

7458
void logAvailableJmxMetrics() {
7559
synchronized (lock) {
76-
Map<String, Set<String>> availableJmxAttributes = getAvailableJmxAttributes();
77-
logDifference(priorAvailableJmxAttributes, availableJmxAttributes);
78-
priorAvailableJmxAttributes = availableJmxAttributes;
60+
Map<String, Set<String>> attributeMap = getAttributeMap();
61+
logDifference(priorAttributeMap, attributeMap);
62+
priorAttributeMap = attributeMap;
7963
}
8064
}
8165

@@ -106,75 +90,64 @@ private static String toString(Map<String, Set<String>> jmxAttributes) {
10690
sb.append(" - object name: ")
10791
.append(entry.getKey())
10892
.append("\n")
109-
.append(" numeric attributes: ")
93+
.append(" attributes: ")
11094
.append(entry.getValue().stream().sorted().collect(Collectors.joining(", ")))
11195
.append("\n");
11296
}
11397
return sb.toString();
11498
}
11599

116-
private static Map<String, Set<String>> getAvailableJmxAttributes() {
100+
private static Map<String, Set<String>> getAttributeMap() {
117101
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
118102
Set<ObjectName> objectNames = server.queryNames(null, null);
119-
Map<String, Set<String>> availableJmxMetrics = new HashMap<>();
103+
Map<String, Set<String>> attributeMap = new HashMap<>();
120104
for (ObjectName objectName : objectNames) {
121105
String name = objectName.toString();
106+
Set<String> attributes;
122107
try {
123-
Set<String> attrs = getJmxAttributes(server, objectName);
124-
if (!attrs.isEmpty()) {
125-
availableJmxMetrics.put(name, attrs);
108+
attributes = getAttributes(server, objectName);
109+
if (attributes.isEmpty()) {
110+
attributes.add("(no attributes found)");
126111
}
127112
} catch (Exception e) {
128113
// log exception at trace level since this is expected in several cases, e.g.
129114
// "java.lang.UnsupportedOperationException: CollectionUsage threshold is not supported"
130115
// and available jmx metrics are already only logged at debug
131116
logger.trace(e.getMessage(), e);
132-
availableJmxMetrics.put(name, Collections.singleton("<error getting attributes: " + e));
117+
attributes = singleton("(error getting attributes)");
133118
}
119+
attributeMap.put(name, attributes);
134120
}
135-
return availableJmxMetrics;
121+
return attributeMap;
136122
}
137123

138-
private static Set<String> getJmxAttributes(MBeanServer server, ObjectName objectName)
124+
private static Set<String> getAttributes(MBeanServer server, ObjectName objectName)
139125
throws Exception {
140126
MBeanInfo mbeanInfo = server.getMBeanInfo(objectName);
141-
Set<String> attributeNames = new HashSet<>();
127+
Set<String> attributes = new HashSet<>();
142128
for (MBeanAttributeInfo attribute : mbeanInfo.getAttributes()) {
143-
if (attribute.isReadable()) {
144-
try {
145-
Object value = server.getAttribute(objectName, attribute.getName());
146-
attributeNames.addAll(getNumericAttributes(attribute, value));
147-
} catch (Exception e) {
148-
// log exception at trace level since this is expected in several cases, e.g.
149-
// "java.lang.UnsupportedOperationException: CollectionUsage threshold is not supported"
150-
// and available jmx metrics are already only logged at debug
151-
logger.trace(e.getMessage(), e);
152-
}
129+
if (!attribute.isReadable()) {
130+
attributes.add(attribute.getName() + " (not readable)");
131+
continue;
132+
}
133+
try {
134+
Object value = server.getAttribute(objectName, attribute.getName());
135+
attributes.addAll(getAttributes(attribute, value));
136+
} catch (Exception e) {
137+
// log exception at trace level since this is expected in several cases, e.g.
138+
// "java.lang.UnsupportedOperationException: CollectionUsage threshold is not supported"
139+
// and available jmx metrics are already only logged at debug
140+
logger.trace(e.getMessage(), e);
141+
attributes.add(attribute.getName() + " (exception)");
153142
}
154143
}
155-
return attributeNames;
144+
return attributes;
156145
}
157146

158-
private static List<String> getNumericAttributes(MBeanAttributeInfo attribute, Object value) {
147+
private static List<String> getAttributes(MBeanAttributeInfo attribute, @Nullable Object value) {
148+
159149
String attributeType = attribute.getType();
160-
if (NUMERIC_ATTRIBUTE_TYPES.contains(attributeType) && value instanceof Number) {
161-
return singletonList(attribute.getName());
162-
}
163-
if (BOOLEAN_ATTRIBUTE_TYPES.contains(attributeType) && value instanceof Boolean) {
164-
return singletonList(attribute.getName());
165-
}
166-
if (attributeType.equals("java.lang.Object") && value instanceof Number) {
167-
return singletonList(attribute.getName());
168-
}
169-
if (attributeType.equals("java.lang.String") && value instanceof String) {
170-
try {
171-
Double.parseDouble((String) value);
172-
return singletonList(attribute.getName());
173-
} catch (NumberFormatException e) {
174-
// this is expected for non-numeric attributes
175-
return emptyList();
176-
}
177-
}
150+
178151
if (attributeType.equals(CompositeData.class.getName())) {
179152
Object openType = attribute.getDescriptor().getFieldValue("openType");
180153
CompositeType compositeType = null;
@@ -184,43 +157,49 @@ private static List<String> getNumericAttributes(MBeanAttributeInfo attribute, O
184157
compositeType = ((CompositeDataSupport) value).getCompositeType();
185158
}
186159
if (compositeType != null) {
187-
return getCompositeTypeAttributeNames(attribute, value, compositeType);
160+
return getCompositeTypeAttributes(attribute, value, compositeType);
188161
}
189162
}
190-
return emptyList();
163+
164+
return singletonList(attribute.getName() + " (" + valueType(value) + ")");
191165
}
192166

193-
private static List<String> getCompositeTypeAttributeNames(
167+
private static List<String> getCompositeTypeAttributes(
194168
MBeanAttributeInfo attribute, Object compositeData, CompositeType compositeType) {
195-
List<String> attributeNames = new ArrayList<>();
169+
List<String> attributes = new ArrayList<>();
196170
for (String itemName : compositeType.keySet()) {
171+
String attributeName = attribute.getName() + "." + itemName;
197172
OpenType<?> itemType = compositeType.getType(itemName);
198173
if (itemType == null) {
174+
attributes.add(attributeName + " (null)");
199175
continue;
200176
}
201-
String className = itemType.getClassName();
202-
Class<?> clazz;
203-
try {
204-
clazz = Class.forName(className);
205-
} catch (ClassNotFoundException e) {
206-
logger.warn(e.getMessage(), e);
207-
continue;
177+
if (compositeData instanceof CompositeData) {
178+
Object value = ((CompositeData) compositeData).get(itemName);
179+
attributes.add(attributeName + " (" + valueType(value) + ")");
180+
} else {
181+
attributes.add(attributeName + " (unexpected: " + compositeData.getClass().getName() + ")");
208182
}
209-
if (Number.class.isAssignableFrom(clazz)) {
210-
attributeNames.add(attribute.getName() + '.' + itemName);
211-
} else if (clazz == String.class && compositeData instanceof CompositeData) {
212-
Object val = ((CompositeData) compositeData).get(itemName);
213-
if (val instanceof String) {
214-
try {
215-
Double.parseDouble((String) val);
216-
attributeNames.add(attribute.getName() + '.' + itemName);
217-
} catch (NumberFormatException e) {
218-
// this is expected for non-numeric attributes
219-
}
220-
}
183+
}
184+
return attributes;
185+
}
186+
187+
private static String valueType(@Nullable Object value) {
188+
if (value instanceof Number) {
189+
return "number";
190+
}
191+
if (value instanceof Boolean) {
192+
return "boolean";
193+
}
194+
if (value instanceof String) {
195+
try {
196+
Double.parseDouble((String) value);
197+
return "number";
198+
} catch (NumberFormatException e) {
199+
return "string";
221200
}
222201
}
223-
return attributeNames;
202+
return "other";
224203
}
225204

226205
// visible for testing

0 commit comments

Comments
 (0)