Repository: apache/kafka
File: clients/src/main/java/org/apache/kafka/common/utils/AppInfoParser.java (Java)

Code before:
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        try {
            ObjectName name = new ObjectName(prefix + ":type=app-info,id=" + Sanitizer.jmxSanitize(id));
            if (server.isRegistered(name))
                server.unregisterMBean(name);

            unregisterMetrics(metrics, id);
        } catch (JMException e) {
            log.warn("Error unregistering AppInfo mbean", e);
        } finally {
            log.info("App info {} for {} unregistered", prefix, id);
        }
    }

    private static MetricName metricName(Metrics metrics, String name, Map<String, String> tags) {
        return metrics.metricName(name, "app-info", "Metric indicating " + name, tags);
    }

    private static void registerMetrics(Metrics metrics, AppInfo appInfo, String clientId) {
        if (metrics == null) return;
        // Most Kafka clients (producer/consumer/admin) set the client-id tag in the metrics config.
        // Although we don’t explicitly parse client-id here, these metrics are automatically tagged with client-id.
        metrics.addMetric(metricName(metrics, "version", Map.of()), (Gauge<String>) (config, now) -> appInfo.getVersion());
        metrics.addMetric(metricName(metrics, "commit-id", Map.of()), (Gauge<String>) (config, now) -> appInfo.getCommitId());
        metrics.addMetric(metricName(metrics, "start-time-ms", Map.of()), (Gauge<Long>) (config, now) -> appInfo.getStartTimeMs());
        // MirrorMaker doesn't set client-id tag into the metrics config, so we need to set it here.
        if (!metrics.config().tags().containsKey("client-id") && clientId != null) {
            metrics.addMetric(metricName(metrics, "version", Map.of("client-id", clientId)), (Gauge<String>) (config, now) -> appInfo.getVersion());
            metrics.addMetric(metricName(metrics, "commit-id", Map.of("client-id", clientId)), (Gauge<String>) (config, now) -> appInfo.getCommitId());
            metrics.addMetric(metricName(metrics, "start-time-ms", Map.of("client-id", clientId)), (Gauge<Long>) (config, now) -> appInfo.getStartTimeMs());
        }
    }

    private static void unregisterMetrics(Metrics metrics, String clientId) {
        if (metrics == null) return;

        metrics.removeMetric(metricName(metrics, "version", Map.of()));
        metrics.removeMetric(metricName(metrics, "commit-id", Map.of()));
        metrics.removeMetric(metricName(metrics, "start-time-ms", Map.of()));

        if (!metrics.config().tags().containsKey("client-id") && clientId != null) {
            metrics.removeMetric(metricName(metrics, "version", Map.of("client-id", clientId)));
            metrics.removeMetric(metricName(metrics, "commit-id", Map.of("client-id", clientId)));
            metrics.removeMetric(metricName(metrics, "start-time-ms", Map.of("client-id", clientId)));
        }
    }

    public interface AppInfoMBean {
        String getVersion();
        String getCommitId();
        Long getStartTimeMs();

Review comment (suggestion):
To be precise, the worker also does not set `client-id`
 https://github.com/apache/kafka/blob/trunk/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/ConnectMetrics.java#L89

Code after:
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        try {
            ObjectName name = new ObjectName(prefix + ":type=app-info,id=" + Sanitizer.jmxSanitize(id));
            if (server.isRegistered(name))
                server.unregisterMBean(name);

            unregisterMetrics(metrics, id);
        } catch (JMException e) {
            log.warn("Error unregistering AppInfo mbean", e);
        } finally {
            log.info("App info {} for {} unregistered", prefix, id);
        }
    }

    private static MetricName metricName(Metrics metrics, String name, Map<String, String> tags) {
        return metrics.metricName(name, "app-info", "Metric indicating " + name, tags);
    }

    private static void registerMetrics(Metrics metrics, AppInfo appInfo, String clientId) {
        if (metrics == null) return;
        // Most Kafka clients (producer/consumer/admin) set the client-id tag in the metrics config.
        // Although we don’t explicitly parse client-id here, these metrics are automatically tagged with client-id.
        metrics.addMetric(metricName(metrics, "version", Map.of()), (Gauge<String>) (config, now) -> appInfo.getVersion());
        metrics.addMetric(metricName(metrics, "commit-id", Map.of()), (Gauge<String>) (config, now) -> appInfo.getCommitId());
        metrics.addMetric(metricName(metrics, "start-time-ms", Map.of()), (Gauge<Long>) (config, now) -> appInfo.getStartTimeMs());
        // MirrorMaker/Worker doesn't set client-id tag into the metrics config, so we need to set it here.
        if (!metrics.config().tags().containsKey("client-id") && clientId != null) {
            metrics.addMetric(metricName(metrics, "version", Map.of("client-id", clientId)), (Gauge<String>) (config, now) -> appInfo.getVersion());
            metrics.addMetric(metricName(metrics, "commit-id", Map.of("client-id", clientId)), (Gauge<String>) (config, now) -> appInfo.getCommitId());
            metrics.addMetric(metricName(metrics, "start-time-ms", Map.of("client-id", clientId)), (Gauge<Long>) (config, now) -> appInfo.getStartTimeMs());
        }
    }

    private static void unregisterMetrics(Metrics metrics, String clientId) {
        if (metrics == null) return;

        metrics.removeMetric(metricName(metrics, "version", Map.of()));
        metrics.removeMetric(metricName(metrics, "commit-id", Map.of()));
        metrics.removeMetric(metricName(metrics, "start-time-ms", Map.of()));

        if (!metrics.config().tags().containsKey("client-id") && clientId != null) {
            metrics.removeMetric(metricName(metrics, "version", Map.of("client-id", clientId)));
            metrics.removeMetric(metricName(metrics, "commit-id", Map.of("client-id", clientId)));
            metrics.removeMetric(metricName(metrics, "start-time-ms", Map.of("client-id", clientId)));
        }
    }

    public interface AppInfoMBean {
        String getVersion();
        String getCommitId();
        Long getStartTimeMs();