in apm-agent-plugins/apm-jmx-plugin/src/main/java/co/elastic/apm/agent/jmx/JmxMetricTracker.java [238:320]
private void registerMBeanNotificationListener(final MBeanServer server) {
MBeanServerNotificationFilter filter = new MBeanServerNotificationFilter();
filter.enableAllObjectNames();
filter.enableType(MBeanServerNotification.REGISTRATION_NOTIFICATION);
listener = new NotificationListener() {
@Override
public void handleNotification(Notification notification, Object handback) {
try {
if (notification instanceof MBeanServerNotification) {
onMBeanAdded(((MBeanServerNotification) notification).getMBeanName());
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
private void onMBeanAdded(ObjectName mBeanName) {
logger.trace("Receiving MBean registration notification for {}", mBeanName);
for (JmxMetric jmxMetric : jmxConfiguration.getCaptureJmxMetrics().get()) {
addMBean(mBeanName, jmxMetric);
}
}
private void addMBean(ObjectName mBeanName, JmxMetric jmxMetric) {
ObjectName metricName = jmxMetric.getObjectName();
if (metricName.apply(mBeanName) || matchesJbossStatisticsPool(mBeanName, metricName, server)) {
logger.debug("MBean added at runtime: {}", jmxMetric.getObjectName());
register(Collections.singletonList(jmxMetric), server, failedMetrics);
}
}
private boolean matchesJbossStatisticsPool(ObjectName beanName, ObjectName metricName, MBeanServer server) {
String asDomain = "jboss.as";
String exprDomain = "jboss.as.expr";
if (!asDomain.equals(metricName.getDomain())) {
// only relevant for metrics in 'jboss.as' domain
return false;
}
if (!exprDomain.equals(beanName.getDomain()) && !asDomain.equals(beanName.getDomain())) {
// only relevant for notifications in the 'jboss.as' or 'jboss.as.expr' domains
return false;
}
// On JBoos EAP 7.3.0 and 7.1.0, we have similar behaviors
// - notification can be on `jboss.as.expr` or `jboss.as` domain, but we registered `jboss.as`
// - notification on `jboss.as.expr` seems to be setup-dependant and might be optional
// - notification bean will miss the `statistics=pool` property
// - when we get one of those "close but not 100% identical", the beans we usually look for are available
//
// We just do an extra lookup to check that the MBean we are looking for is actually present
// thus in the worst case it just means few extra lookups.
//
// while we haven't found a clear "why is this not reflected on JMX notifications", some
// references to this can be found in Jboss/Wildfly sources with the following regex: `statistics.*pool`
try {
Hashtable<String, String> metricProperties = metricName.getKeyPropertyList();
Hashtable<String, String> beanProperties = beanName.getKeyPropertyList();
if ("pool".equals(metricProperties.get("statistics")) && !beanProperties.containsKey("statistics")) {
beanProperties.put("statistics", "pool");
}
ObjectName newName = new ObjectName(asDomain, beanProperties);
boolean matches = metricName.apply(newName) && server.queryMBeans(newName, null).size() > 0;
if (matches) {
logger.debug("JBoss fallback detection applied for {} MBean metric registration", newName);
}
return matches;
} catch (MalformedObjectNameException e) {
return false;
}
}
};
try {
server.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, listener, filter, null);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}