Skip to content

Conversation

majialoong
Copy link
Contributor

KIP-188 introduced MetricValueProvider, adding Measurable and Gauge as its sub interfaces. However, this left a legacy issue: move the value method from Gauge to the super interface, MetricValueProvider.

This PR moves the value method from Gauge to MetricValueProvider and provides a default implementation in Measurable. This unifies the methods used by Gauge and Measurable to obtain monitoring values.

@github-actions github-actions bot added triage PRs from the community clients small Small PRs labels Sep 16, 2025
@majialoong
Copy link
Contributor Author

For binary compatibility issues, the following tests were performed:

  1. Binary compatibility tested using japicmp

kafka-clients-4.2.0-SNAPSHOT.jar is the code before this PR, and kafka-clients-4.2.0-SNAPSHOT-new.jar contains the changed code of this PR.

image
  1. Write a test code to verify
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import org.apache.kafka.common.MetricName;
import org.apache.kafka.common.metrics.Gauge;
import org.apache.kafka.common.metrics.MetricConfig;
import org.apache.kafka.common.metrics.Metrics;
import org.apache.kafka.common.metrics.stats.Min;

public class CustomMetrics {
    public static void main(String[] args) {
        Metrics metrics = new Metrics();

        MetricName gaugeMetricNameOne = new MetricName("gaugeMetricNameOne", "test-metrics", "description for gauge "
                + "metric "
                + "one",
                new HashMap<>());
        metrics.addMetric(gaugeMetricNameOne, (Gauge<String>) (config, now) -> "hello gauge.");

        MetricName gaugeMetricNameTwo = new MetricName("gaugeMetricNameTwo", "test-metrics", "description for gauge "
                + "metric two",
                new HashMap<>());
        metrics.addMetric(gaugeMetricNameTwo, (Gauge<Integer>) (config, now) -> 123);

        MetricName measurableMetricNameOne = new MetricName("measurableMetricNameOne", "test-metrics", "description for "
                + " measurable metric one",
                new HashMap<>());
        metrics.addMetric(measurableMetricNameOne, (config, now) -> 100L);

        MetricName measurableMetricNameTwo = new MetricName("measurableMetricNameTwo", "test-metrics", "description "
                + "for measurable metric two",
                new HashMap<>());
        Min min = new Min();
        long windowMs = 100;
        int samples = 2;
        MetricConfig config = new MetricConfig().timeWindow(windowMs, TimeUnit.MILLISECONDS).samples(samples);
        min.record(config, 50, System.currentTimeMillis());
        metrics.addMetric(measurableMetricNameTwo, min);

        System.out.println("gaugeMetricNameOne: " + metrics.metric(gaugeMetricNameOne).metricValue());
        System.out.println("gaugeMetricNameTwo: " + metrics.metric(gaugeMetricNameTwo).metricValue());
        System.out.println("measurableMetricNameOne: " + metrics.metric(measurableMetricNameOne).metricValue());
        System.out.println("measurableMetricNameTwo: " + metrics.metric(measurableMetricNameTwo).metricValue());
    }
}

Compile using the code in the current trunk branch and version 1.0.1. Then run using the code that includes the changes in this PR.

trunk beanch :
image

1.0.1 version :
image

@majialoong
Copy link
Contributor Author

Hello, @ijuma @rajinisivaram @chia7712 , when have time, please review this PR , thanks !

Copy link
Member

@chia7712 chia7712 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@majialoong thanks for this patch!

return ((Gauge<?>) metricValueProvider).value(config, now);
else
throw new IllegalStateException("Not a valid metric: " + this.metricValueProvider.getClass());
return metricValueProvider.value(config, now);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we update the docs so they match these changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the reminder, I will update this doc.

@majialoong majialoong requested a review from chia7712 September 17, 2025 16:25
@github-actions github-actions bot removed the triage PRs from the community label Sep 18, 2025
T value(MetricConfig config, long now);

}
public interface Gauge<T> extends MetricValueProvider<T> { }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Gauge type seems redundant at this stage. Would it be worth filing a KIP to deprecate it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping the Gauge type can improves code readability. Readers immediately understand that the monitoring metric represents an instantaneous value, and it can also be equated with the concept of Gauge in mainstream monitoring systems. Directly using the MetricValueProvider may be a bit too abstract.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another follow-up (KIP) could be removing addMetric(MetricName metricName, Measurable measurable), which would let us drop the explicit type from the lambda
before

metrics.addMetric(metricName(metrics, "version", Map.of()), (Gauge<String>) (config, now) -> appInfo.getVersion());

after

metrics.addMetric(metricName(metrics, "version", Map.of()),  (config, now) -> appInfo.getVersion());

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good suggestion, I've created a JIRA to track this issue:https://issues.apache.org/jira/browse/KAFKA-19729

@ijuma
Copy link
Member

ijuma commented Sep 21, 2025

Thanks for the PR. Regarding compatibility, you'd want to test both binary and source compatibility.

@majialoong
Copy link
Contributor Author

Thanks for the PR. Regarding compatibility, you'd want to test both binary and source compatibility.

@ijuma Thank you for your comments. In the above conversation, I listed two methods for testing binary compatibility. If there are any scenarios I've overlooked, please comment and add them. I'll test and verify them promptly. I will also conduct some further testing and verification and add to this in subsequent conversations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants