DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
...
As the AppInfoParser class registers a JMX MBean with the provided client-id but when it adds metrics to the Metrics registry the client-id is not included.
Public Interfaces
...
org.apache.kafka.common.utils.AppInfoParser.AppInfoMBean
Proposed Changes
1) Update the AppInfoMBean interface add interface to add a new method getClientId() .
Proposed Changes
The following code is a demonstration of how we will add to the getClientId method:
| Code Block |
|---|
public interface AppInfoMBean {
String getVersion();
String getCommitId();
Long getStartTimeMs();
String getClientId();
} |
Also updated AppInfoParser to include a new field CLIENT_ID, so that when reading /kafka/kafka-version.properties, the clientId can be retrieved.
2) Deprecated old AppInfoMBean implementation and mark it deprecated
| Code Block |
|---|
@Deprecated(since = "4.2")
public static class DeprecatedAppInfo implements AppInfoMBean {
} |
3) Add new AppInfoMBeanimplementation
| Code Block | ||
|---|---|---|
public static class AppInfo implements AppInfoMBean { | ||
| Code Block | ||
| ||
public class AppInfoParser { private static final Logger log = LoggerFactory.getLogger(AppInfoParser.class); private static final String VERSION; private static final String COMMIT_ID; private static final String CLIENT_ID; protected staticprivate final String DEFAULT_VALUE = "unknown"Long startTimeMs; static { Properties props = new Properties(); try (InputStream resourceStream = AppInfoParser.class.getResourceAsStream("/kafka/kafka-version.properties"))public AppInfo(long startTimeMs) { this.startTimeMs props.load(resourceStream)= startTimeMs; } catch (Exception e) { log.warninfo("Error while loading kafka-version.propertiesKafka version: {}", eAppInfoParser.getMessagegetVersion()); } VERSION = props.getProperty("version", DEFAULT_VALUE).trim(); COMMIT_ID = props.getProperty("commitId", DEFAULT_VALUE).trim()log.info("Kafka commitId: {}", AppInfoParser.getCommitId()); CLIENT_ID = props.getProperty("clientId", DEFAULT_VALUE).trim(); } public static String getVersion() { return VERSION; } public static String getCommitId() { return COMMIT_ID; } public static String getClientId() { return CLIENT_ID; } public static synchronized void registerAppInfo(String prefix, String id, Metrics metrics, long nowMs) { try { ObjectName name = new ObjectName(prefix + ":type=app-info,id=" + Sanitizer.jmxSanitize(id)); log.info("Kafka startTimeMs: {}", startTimeMs); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); if (server.isRegistered(name)) { log.info("The mbean of App info: [{}], Kafka client id: [{}] already exists, so skipping a new mbean creation.", prefix, id); return; ", AppInfoParser.getClientId()); } DeprecatedAppInfo deprecatedMBean = new DeprecatedAppInfo(nowMs); AppInfo mBean = new AppInfo(nowMs); server.registerMBean(deprecatedMBean, name); server.registerMBean(mBean, name); // skip... registerMetrics(metrics, mBean); // prefix will be added later by JmxReporter@Override public } catch (JMException eString getClientId() { return log.warn("Error registering AppInfo mbean", eAppInfoParser.getClientId(); } } public static synchronized void unregisterAppInfo(String prefix, String id, Metrics metrics)} |
4) When AppInfoParser register MBean, we will register the new one and the deprecated one
| Code Block | ||
|---|---|---|
| ||
public class AppInfoParser { private static final Logger MBeanServerlog server = ManagementFactoryLoggerFactory.getPlatformMBeanServer(); try { ObjectName name = new ObjectName(prefix + ":type=app-info,id=" + Sanitizer.jmxSanitize(id))getLogger(AppInfoParser.class); private static final if (server.isRegistered(name)) server.unregisterMBean(name); String VERSION; private static final unregisterMetrics(metrics)String COMMIT_ID; private static final } catch (JMException e) { log.warn("Error unregistering AppInfo mbean", e); } finally {String CLIENT_ID; log.info("App info {} for {} unregistered", prefix, id); } } private static MetricName metricName(Metrics metrics, String name) { return metrics.metricName(name, "app-info", "Metric indicating " + name); } private static void registerMetrics(Metrics metrics, AppInfoMBean appInfo)protected static final String DEFAULT_VALUE = "unknown"; static { ifProperties (metricsprops != null) { metrics.addMetric(metricName(metrics, "version"), new ImmutableValue<>(appInfo.getVersion())Properties(); metrics.addMetric(metricName(metrics, "commit-id"), new ImmutableValue<>(appInfo.getCommitId())); metrics.addMetric(metricName(metrics, "start-time-ms"), new ImmutableValue<>(appInfo.getStartTimeMs())); if (appInfo instanceof AppInfo) try (InputStream resourceStream = AppInfoParser.class.getResourceAsStream("/kafka/kafka-version.properties")) { metrics.addMetric(metricName(metrics, "client-id"), new ImmutableValue<>(appInfo.getClientId())); props.load(resourceStream); } } } private static void unregisterMetrics(Metrics metricscatch (Exception e) { if (metrics != null) { metrics.removeMetric(metricName(metrics, "version")); metrics.removeMetric(metricName(metrics, "commit-id")); metrics.removeMetric(metricName(metrics, "start-time-ms")); metrics.removeMetric(metricName(metrics, "client-id" log.warn("Error while loading kafka-version.properties: {}", e.getMessage()); } } public interface AppInfoMBean { String getVersion(); String getCommitId(); String getClientId(); Long getStartTimeMs(); } @Deprecated(since = "4.2") public static class DeprecatedAppInfo implements AppInfoMBean { private final Long startTimeMs; public DeprecatedAppInfo(long startTimeMs) { this.startTimeMs = startTimeMs; log.info("Kafka version: {}", AppInfoParser.getVersion())VERSION = props.getProperty("version", DEFAULT_VALUE).trim(); COMMIT_ID = logprops.infogetProperty("Kafka commitId: {}", AppInfoParser.getCommitIdDEFAULT_VALUE).trim()); CLIENT_ID = logprops.infogetProperty("Kafka startTimeMs: {}clientId", startTimeMsDEFAULT_VALUE).trim(); } @Override public String getVersionpublic static String getClientId() { return AppInfoParser.getVersion()CLIENT_ID; } public static synchronized void @Override public String getCommitId(registerAppInfo(String prefix, String id, Metrics metrics, long nowMs) { return AppInfoParser.getCommitId();try { } @Override// skip... public String getClientId() { DeprecatedAppInfo throw new UnsupportedOperationException("client-id is not implemented in DeprecatedAppInfo"); } @Override public Long getStartTimeMs() { return startTimeMs; } } public static class AppInfo implements AppInfoMBean { private final Long startTimeMs; public AppInfo(long startTimeMs) { this.startTimeMs = startTimeMsdeprecatedMBean = new DeprecatedAppInfo(nowMs); AppInfo mBean = new AppInfo(nowMs); logserver.info("Kafka version: {}", AppInfoParser.getVersion()registerMBean(deprecatedMBean, name); logserver.info("Kafka commitId: {}", AppInfoParser.getCommitId()); log.info("Kafka startTimeMs: {}", startTimeMs);registerMBean(mBean, name); log.info("Kafka client id: {}", AppInfoParser.getClientId()); } @Override public String getVersion() {registerMetrics(metrics, mBean); // prefix will be added later by JmxReporter return AppInfoParser.getVersion(); } @Override public String getCommitId() { return AppInfoParser.getCommitId(); } @Override public String getClientId(catch (JMException e) { return AppInfoParserlog.getClientId(); } @Override public Long getStartTimeMs() { return startTimeMswarn("Error registering AppInfo mbean", e); } } static class ImmutableValue<T> implements Gauge<T> { private final T value; public ImmutableValue(T value) { this.value = value; } @Override public T value(MetricConfig config, long now) { return value; } } } |
Compatibility, Deprecation, and Migration Plan
...