private void registerMBeanNotificationListener()

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);
        }
    }