This is an automated email from the ASF dual-hosted git repository.
morrySnow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new aec06f991d9 [fix](metric) Preserve labels for histogram metrics to fix
wrong metric name for prometheus (#63485)
aec06f991d9 is described below
commit aec06f991d9684653ca62309e6c0835dd064b892
Author: seawinde <[email protected]>
AuthorDate: Tue May 26 14:39:07 2026 +0800
[fix](metric) Preserve labels for histogram metrics to fix wrong metric
name for prometheus (#63485)
### What problem does this PR solve?
Related PR: #13832
Problem Summary:
Histogram metrics that encode labels in the Dropwizard metric name can
be rendered incorrectly when label values contain dots or other special
characters. For example, a user value like `[email protected]` can be
split as part of the metric name instead of being kept as the `user`
label.
Root cause: In `PrometheusMetricVisitor.visitHistogram()` and
`JsonMetricVisitor.visitHistogram()`, the legacy histogram export path
splits the Dropwizard histogram name by dots and infers labels from
`k=v` name segments. `MetricRepo.USER_HISTO_QUERY_LATENCY` previously
embedded the user label into the histogram name, so dots inside user
names were treated as metric-name separators.
Change Summary:
| File | Change Description |
|------|--------------------|
|
`fe/fe-core/src/main/java/org/apache/doris/metric/HistogramMetric.java`
| Add a small wrapper that keeps the Dropwizard `Histogram` together
with its metric name and structured labels. |
| `fe/fe-core/src/main/java/org/apache/doris/metric/MetricRepo.java` |
Export labeled histogram metrics through the new structured label path
while keeping existing static histograms exported. |
| `fe/fe-core/src/main/java/org/apache/doris/metric/CloudMetrics.java` |
Keep cloud query latency and meta-service RPC latency labels structured
instead of encoding them in histogram names. |
| `fe/fe-core/src/main/java/org/apache/doris/metric/MetricVisitor.java`
| Add a labeled histogram visit overload. |
|
`fe/fe-core/src/main/java/org/apache/doris/metric/PrometheusMetricVisitor.java`
| Render structured histogram labels directly in Prometheus output. |
|
`fe/fe-core/src/main/java/org/apache/doris/metric/JsonMetricVisitor.java`
| Render structured histogram labels directly in JSON output. |
| `fe/fe-core/src/test/java/org/apache/doris/metric/MetricsTest.java` |
Cover user and cloud histogram labels containing dots and at signs. |
Design Rationale:
The fix follows the existing counter and gauge approach: keep metric
names stable and carry dimensions as `MetricLabel` values. The legacy
three-argument histogram visitor remains for existing static Dropwizard
histograms without labels, while dynamic histograms that need labels use
the structured four-argument path.
```mermaid
graph TD
A["Query finished"] --> B["Update query metrics"]
B --> C["Get or create per-user histogram"]
C --> D["HistogramMetric stores name, histogram, and labels"]
D --> E["MetricRepo visits histogram metrics"]
E --> F["Prometheus or JSON visitor renders output"]
F --> G["Stable metric name with structured labels"]
```
### Release note
Fixed an issue where FE histogram metrics with label values containing
dots, such as user names or cloud cluster names, could be exported with
malformed metric names or labels.
---------
Co-authored-by: Copilot <[email protected]>
---
.../java/org/apache/doris/metric/CloudMetrics.java | 26 +++--
.../apache/doris/metric/DorisMetricRegistry.java | 36 +++++++
.../{MetricVisitor.java => HistogramMetric.java} | 47 +++++----
.../org/apache/doris/metric/JsonMetricVisitor.java | 18 ++++
.../java/org/apache/doris/metric/MetricRepo.java | 27 ++++--
.../org/apache/doris/metric/MetricVisitor.java | 4 +
.../doris/metric/PrometheusMetricVisitor.java | 24 +++--
.../doris/metric/SimpleCoreMetricVisitor.java | 6 ++
.../java/org/apache/doris/metric/MetricsTest.java | 105 ++++++++++++++++-----
9 files changed, 220 insertions(+), 73 deletions(-)
diff --git a/fe/fe-core/src/main/java/org/apache/doris/metric/CloudMetrics.java
b/fe/fe-core/src/main/java/org/apache/doris/metric/CloudMetrics.java
index e580291018b..b88780a9f4c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/metric/CloudMetrics.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/metric/CloudMetrics.java
@@ -20,9 +20,12 @@ package org.apache.doris.metric;
import org.apache.doris.common.Config;
import org.apache.doris.metric.Metric.MetricUnit;
-import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
public class CloudMetrics {
protected static String CLOUD_CLUSTER_DELIMITER = "@delimiter#";
protected static AutoMappedMetric<LongCounterMetric>
CLUSTER_REQUEST_ALL_COUNTER;
@@ -33,7 +36,7 @@ public class CloudMetrics {
protected static AutoMappedMetric<GaugeMetricImpl<Double>>
CLUSTER_QUERY_PER_SECOND_GAUGE;
protected static AutoMappedMetric<GaugeMetricImpl<Double>>
CLUSTER_QUERY_ERR_RATE_GAUGE;
- protected static AutoMappedMetric<Histogram> CLUSTER_QUERY_LATENCY_HISTO;
+ protected static AutoMappedMetric<HistogramMetric>
CLUSTER_QUERY_LATENCY_HISTO;
protected static AutoMappedMetric<GaugeMetricImpl<Integer>>
CLUSTER_BACKEND_ALIVE;
protected static AutoMappedMetric<GaugeMetricImpl<Integer>>
CLUSTER_BACKEND_ALIVE_TOTAL;
@@ -57,7 +60,7 @@ public class CloudMetrics {
public static AutoMappedMetric<LongCounterMetric> META_SERVICE_RPC_FAILED;
public static AutoMappedMetric<LongCounterMetric> META_SERVICE_RPC_RETRY;
public static AutoMappedMetric<GaugeMetricImpl<Double>>
META_SERVICE_RPC_PER_SECOND;
- public static AutoMappedMetric<Histogram> META_SERVICE_RPC_LATENCY;
+ public static AutoMappedMetric<HistogramMetric> META_SERVICE_RPC_LATENCY;
// Aggregate meta-service metrics
public static LongCounterMetric META_SERVICE_RPC_ALL_TOTAL;
@@ -94,13 +97,15 @@ public class CloudMetrics {
MetricUnit.NOUNIT, "backend alive num in cluster", 0));
CLUSTER_QUERY_LATENCY_HISTO = new AutoMappedMetric<>(key -> {
- String[] values = key.split(CLOUD_CLUSTER_DELIMITER);
+ String[] values = key.split(CLOUD_CLUSTER_DELIMITER, 2);
String clusterId = values[0];
String clusterName = values[1];
- String metricName = MetricRegistry.name("query", "latency", "ms",
"cluster_id="
- + clusterId, "cluster_name=" + clusterName);
- return MetricRepo.METRIC_REGISTER.histogram(metricName);
+ List<MetricLabel> labels = Arrays.asList(new
MetricLabel("cluster_id", clusterId),
+ new MetricLabel("cluster_name", clusterName));
+ return new HistogramMetric(MetricRegistry.name("query", "latency",
"ms"), labels);
});
+ MetricRepo.DORIS_METRIC_REGISTER.addHistogramMetrics(
+ "cloud_cluster_query_latency", CLUSTER_QUERY_LATENCY_HISTO,
Config::isCloudMode);
CLUSTER_WARM_UP_JOB_EXEC_COUNT = new AutoMappedMetric<>(name -> new
LongCounterMetric(
"file_cache_warm_up_job_exec_count", MetricUnit.NOUNIT, "warm
up job execution count"));
@@ -160,10 +165,11 @@ public class CloudMetrics {
return gauge;
});
META_SERVICE_RPC_LATENCY = new AutoMappedMetric<>(methodName -> {
- String metricName = MetricRegistry.name("meta_service", "rpc",
"latency", "ms",
- "method=" + methodName);
- return MetricRepo.METRIC_REGISTER.histogram(metricName);
+ List<MetricLabel> labels = Collections.singletonList(new
MetricLabel("method", methodName));
+ return new HistogramMetric(MetricRegistry.name("meta_service",
"rpc", "latency", "ms"), labels);
});
+ MetricRepo.DORIS_METRIC_REGISTER.addHistogramMetrics(
+ "meta_service_rpc_latency", META_SERVICE_RPC_LATENCY,
Config::isCloudMode);
// Aggregate meta-service metrics
META_SERVICE_RPC_ALL_TOTAL = new
LongCounterMetric("meta_service_rpc_all_total",
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/metric/DorisMetricRegistry.java
b/fe/fe-core/src/main/java/org/apache/doris/metric/DorisMetricRegistry.java
index 21e5e366ebc..5627767f277 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/metric/DorisMetricRegistry.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/metric/DorisMetricRegistry.java
@@ -27,11 +27,13 @@ import java.util.List;
import java.util.Optional;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
public class DorisMetricRegistry {
ConcurrentHashMap<String, MetricList> metrics = new ConcurrentHashMap<>();
ConcurrentHashMap<String, MetricList> systemMetrics = new
ConcurrentHashMap<>();
+ private final ConcurrentHashMap<String, HistogramMetricGroup>
histogramMetricGroups = new ConcurrentHashMap<>();
public DorisMetricRegistry() {
@@ -56,6 +58,18 @@ public class DorisMetricRegistry {
}
}
+ public void addHistogramMetrics(String name,
AutoMappedMetric<HistogramMetric> histogramMetrics) {
+ addHistogramMetrics(name, histogramMetrics, () -> true);
+ }
+
+ public void addHistogramMetrics(String name,
AutoMappedMetric<HistogramMetric> histogramMetrics,
+ Supplier<Boolean> enabled) {
+ // Same reason as comment in addMetrics()
+ if (!Env.isCheckpointThread()) {
+ histogramMetricGroups.put(name, new
HistogramMetricGroup(histogramMetrics, enabled));
+ }
+ }
+
public void accept(MetricVisitor visitor) {
final List<MetricList> metricsList = Lists.newArrayList();
metrics.forEach((name, list) -> metricsList.add(list));
@@ -73,6 +87,18 @@ public class DorisMetricRegistry {
}
}
+ public void acceptHistograms(MetricVisitor visitor) {
+ for (HistogramMetricGroup group : histogramMetricGroups.values()) {
+ if (!group.enabled.get()) {
+ continue;
+ }
+ for (HistogramMetric metric :
group.histogramMetrics.getMetrics().values()) {
+ visitor.visitHistogram(MetricVisitor.FE_PREFIX,
+ metric.getName(), metric.getHistogram(),
metric.getLabels());
+ }
+ }
+ }
+
// the metrics by metric name
public List<Metric> getMetricsByName(String name) {
MetricList list = metrics.get(name);
@@ -132,4 +158,14 @@ public class DorisMetricRegistry {
metrics.remove(labelId);
}
}
+
+ private static class HistogramMetricGroup {
+ private final AutoMappedMetric<HistogramMetric> histogramMetrics;
+ private final Supplier<Boolean> enabled;
+
+ private HistogramMetricGroup(AutoMappedMetric<HistogramMetric>
histogramMetrics, Supplier<Boolean> enabled) {
+ this.histogramMetrics = histogramMetrics;
+ this.enabled = enabled;
+ }
+ }
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/metric/MetricVisitor.java
b/fe/fe-core/src/main/java/org/apache/doris/metric/HistogramMetric.java
similarity index 51%
copy from fe/fe-core/src/main/java/org/apache/doris/metric/MetricVisitor.java
copy to fe/fe-core/src/main/java/org/apache/doris/metric/HistogramMetric.java
index 32f368a2270..ed8349f2eb5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/metric/MetricVisitor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/metric/HistogramMetric.java
@@ -17,38 +17,37 @@
package org.apache.doris.metric;
-import org.apache.doris.monitor.jvm.JvmStats;
-
+import com.codahale.metrics.ExponentiallyDecayingReservoir;
import com.codahale.metrics.Histogram;
-/*
- * MetricVisitor will visit the metrics in metric repo and print them in
StringBuilder
- */
-public abstract class MetricVisitor {
-
- // for FE metrics
- public static final String FE_PREFIX = "doris_fe_";
- // for system metrics
- public static final String SYS_PREFIX = "system_";
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
- protected StringBuilder sb = new StringBuilder();
+public class HistogramMetric {
+ private final String name;
+ private final Histogram histogram;
+ private final List<MetricLabel> labels;
- public MetricVisitor() {
+ public HistogramMetric(String name, List<MetricLabel> labels) {
+ this.name = name;
+ this.histogram = new Histogram(new ExponentiallyDecayingReservoir());
+ this.labels = Collections.unmodifiableList(new ArrayList<>(labels));
}
- public abstract void visitJvm(JvmStats jvmStats);
-
- public abstract void visit(String prefix, Metric metric);
-
- public abstract void visitHistogram(String prefix, String name, Histogram
histogram);
-
- public abstract void visitNodeInfo();
+ public void update(long value) {
+ histogram.update(value);
+ }
- public abstract void visitCloudTableStats();
+ public String getName() {
+ return name;
+ }
- public abstract void visitWorkloadGroup();
+ public Histogram getHistogram() {
+ return histogram;
+ }
- public String finish() {
- return sb.toString();
+ public List<MetricLabel> getLabels() {
+ return labels;
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/metric/JsonMetricVisitor.java
b/fe/fe-core/src/main/java/org/apache/doris/metric/JsonMetricVisitor.java
index 0364781cd3b..01652bc5cc8 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/metric/JsonMetricVisitor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/metric/JsonMetricVisitor.java
@@ -160,6 +160,24 @@ public class JsonMetricVisitor extends MetricVisitor {
}
}
final String fullName = prefix + String.join("_", names);
+ appendHistogram(fullName, histogram, tags);
+ }
+
+ @Override
+ public void visitHistogram(String prefix, String name, Histogram
histogram, List<MetricLabel> labels) {
+ if (histogramOrdinal++ == 0) {
+ sb.append(",\n");
+ }
+
+ final String fullName = prefix + name.replace('.', '_');
+ List<String> tags = new ArrayList<>();
+ for (MetricLabel label : labels) {
+ tags.add(String.format("\"%s\":\"%s\"", label.getKey(),
label.getValue()));
+ }
+ appendHistogram(fullName, histogram, tags);
+ }
+
+ private void appendHistogram(String fullName, Histogram histogram,
List<String> tags) {
Snapshot snapshot = histogram.getSnapshot();
setHistogramJsonMetric(sb, fullName, "\"quantile\":\"0.75\"", tags,
snapshot.get75thPercentile());
setHistogramJsonMetric(sb, fullName, "\"quantile\":\"0.95\"", tags,
snapshot.get95thPercentile());
diff --git a/fe/fe-core/src/main/java/org/apache/doris/metric/MetricRepo.java
b/fe/fe-core/src/main/java/org/apache/doris/metric/MetricRepo.java
index 9b3e37d8f2c..c1ab64a9590 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/metric/MetricRepo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/metric/MetricRepo.java
@@ -110,7 +110,7 @@ public final class MetricRepo {
public static AutoMappedMetric<LongCounterMetric> USER_COUNTER_QUERY_ALL;
public static AutoMappedMetric<LongCounterMetric> USER_COUNTER_QUERY_ERR;
public static Histogram HISTO_QUERY_LATENCY;
- public static AutoMappedMetric<Histogram> USER_HISTO_QUERY_LATENCY;
+ public static AutoMappedMetric<HistogramMetric> USER_HISTO_QUERY_LATENCY;
public static AutoMappedMetric<GaugeMetricImpl<Long>>
USER_GAUGE_QUERY_INSTANCE_NUM;
public static AutoMappedMetric<GaugeMetricImpl<Integer>>
USER_GAUGE_CONNECTIONS;
public static AutoMappedMetric<LongCounterMetric>
USER_COUNTER_QUERY_INSTANCE_BEGIN;
@@ -508,9 +508,10 @@ public final class MetricRepo {
HISTO_QUERY_LATENCY = METRIC_REGISTER.histogram(
MetricRegistry.name("query", "latency", "ms"));
USER_HISTO_QUERY_LATENCY = new AutoMappedMetric<>(name -> {
- String metricName = MetricRegistry.name("query", "latency", "ms",
"user=" + name);
- return METRIC_REGISTER.histogram(metricName);
+ List<MetricLabel> labels = Collections.singletonList(new
MetricLabel("user", name));
+ return new HistogramMetric(MetricRegistry.name("query", "latency",
"ms"), labels);
});
+ DORIS_METRIC_REGISTER.addHistogramMetrics("user_query_latency",
USER_HISTO_QUERY_LATENCY);
USER_COUNTER_QUERY_INSTANCE_BEGIN = addLabeledMetrics("user", () ->
new LongCounterMetric("query_instance_begin",
MetricUnit.NOUNIT,
"number of query instance begin"));
@@ -1520,10 +1521,7 @@ public final class MetricRepo {
DORIS_METRIC_REGISTER.accept(visitor);
// histogram
- SortedMap<String, Histogram> histograms =
METRIC_REGISTER.getHistograms();
- for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
- visitor.visitHistogram(MetricVisitor.FE_PREFIX, entry.getKey(),
entry.getValue());
- }
+ visitHistograms(visitor);
visitor.visitNodeInfo();
@@ -1543,6 +1541,15 @@ public final class MetricRepo {
});
}
+ public static void visitHistograms(MetricVisitor visitor) {
+ SortedMap<String, Histogram> histograms =
METRIC_REGISTER.getHistograms();
+ for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
+ visitor.visitHistogram(MetricVisitor.FE_PREFIX, entry.getKey(),
entry.getValue());
+ }
+
+ DORIS_METRIC_REGISTER.acceptHistograms(visitor);
+ }
+
// update some metrics to make a ready to be visited
private static void updateMetrics() {
SYSTEM_METRICS.update();
@@ -2014,9 +2021,9 @@ public final class MetricRepo {
}
}
- METRIC_REGISTER.getHistograms().keySet().stream()
- .filter(k -> k.contains(clusterId))
- .forEach(METRIC_REGISTER::remove);
+ CloudMetrics.CLUSTER_QUERY_LATENCY_HISTO.remove(clusterId +
CloudMetrics.CLOUD_CLUSTER_DELIMITER
+ + clusterName);
+ // Meta-service RPC latency is keyed by method name only, so it is
not removed by cluster.
for (Backend backend : backends) {
List<MetricLabel> backendLabels = new ArrayList<>();
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/metric/MetricVisitor.java
b/fe/fe-core/src/main/java/org/apache/doris/metric/MetricVisitor.java
index 32f368a2270..eb8c2741e13 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/metric/MetricVisitor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/metric/MetricVisitor.java
@@ -21,6 +21,8 @@ import org.apache.doris.monitor.jvm.JvmStats;
import com.codahale.metrics.Histogram;
+import java.util.List;
+
/*
* MetricVisitor will visit the metrics in metric repo and print them in
StringBuilder
*/
@@ -42,6 +44,8 @@ public abstract class MetricVisitor {
public abstract void visitHistogram(String prefix, String name, Histogram
histogram);
+ public abstract void visitHistogram(String prefix, String name, Histogram
histogram, List<MetricLabel> labels);
+
public abstract void visitNodeInfo();
public abstract void visitCloudTableStats();
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/metric/PrometheusMetricVisitor.java
b/fe/fe-core/src/main/java/org/apache/doris/metric/PrometheusMetricVisitor.java
index 2103dcb6c21..e32097f54df 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/metric/PrometheusMetricVisitor.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/metric/PrometheusMetricVisitor.java
@@ -188,8 +188,20 @@ public class PrometheusMetricVisitor extends MetricVisitor
{
}
}
final String fullName = prefix + String.join("_", names);
+ appendHistogram(fullName, histogram, tags);
+ }
+
+ @Override
+ public void visitHistogram(String prefix, String name, Histogram
histogram, List<MetricLabel> labels) {
+ final String fullName = prefix + name.replace('.', '_');
+ List<String> tags = labels.stream()
+ .map(l -> l.getKey() + "=\"" + l.getValue() + "\"")
+ .collect(Collectors.toList());
+ appendHistogram(fullName, histogram, tags);
+ }
+
+ private void appendHistogram(String fullName, Histogram histogram,
List<String> tags) {
final String fullTag = String.join(",", tags);
- // we should define metric name only once
if (!metricNames.contains(fullName)) {
sb.append(HELP).append(fullName).append(" ").append("\n");
sb.append(TYPE).append(fullName).append(" ").append("summary\n");
@@ -198,15 +210,15 @@ public class PrometheusMetricVisitor extends
MetricVisitor {
String delimiter = tags.isEmpty() ? "" : ",";
Snapshot snapshot = histogram.getSnapshot();
sb.append(fullName).append("{quantile=\"0.75\"").append(delimiter).append(fullTag).append("}
")
- .append(snapshot.get75thPercentile()).append("\n");
+ .append(snapshot.get75thPercentile()).append("\n");
sb.append(fullName).append("{quantile=\"0.95\"").append(delimiter).append(fullTag).append("}
")
- .append(snapshot.get95thPercentile()).append("\n");
+ .append(snapshot.get95thPercentile()).append("\n");
sb.append(fullName).append("{quantile=\"0.98\"").append(delimiter).append(fullTag).append("}
")
- .append(snapshot.get98thPercentile()).append("\n");
+ .append(snapshot.get98thPercentile()).append("\n");
sb.append(fullName).append("{quantile=\"0.99\"").append(delimiter).append(fullTag).append("}
")
- .append(snapshot.get99thPercentile()).append("\n");
+ .append(snapshot.get99thPercentile()).append("\n");
sb.append(fullName).append("{quantile=\"0.999\"").append(delimiter).append(fullTag).append("}
")
- .append(snapshot.get999thPercentile()).append("\n");
+ .append(snapshot.get999thPercentile()).append("\n");
sb.append(fullName).append("_sum{").append(fullTag).append("} ")
.append(histogram.getCount() *
snapshot.getMean()).append("\n");
sb.append(fullName).append("_count{").append(fullTag).append("} ")
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/metric/SimpleCoreMetricVisitor.java
b/fe/fe-core/src/main/java/org/apache/doris/metric/SimpleCoreMetricVisitor.java
index 06a2b8cc1a7..ba729fefdcb 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/metric/SimpleCoreMetricVisitor.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/metric/SimpleCoreMetricVisitor.java
@@ -31,6 +31,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
/*
@@ -128,6 +129,11 @@ public class SimpleCoreMetricVisitor extends MetricVisitor
{
String.format("%.0f",
snapshot.get99thPercentile()))).append("\n");
}
+ @Override
+ public void visitHistogram(String prefix, String name, Histogram
histogram, List<MetricLabel> labels) {
+ visitHistogram(prefix, name, histogram);
+ }
+
@Override
public void visitNodeInfo() {
long feDeadNum =
Env.getCurrentEnv().getFrontends(null).stream().filter(f ->
!f.isAlive()).count();
diff --git a/fe/fe-core/src/test/java/org/apache/doris/metric/MetricsTest.java
b/fe/fe-core/src/test/java/org/apache/doris/metric/MetricsTest.java
index 8e2babbf609..164d767b66e 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/metric/MetricsTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/metric/MetricsTest.java
@@ -24,8 +24,8 @@ import org.apache.doris.metric.Metric.MetricUnit;
import org.apache.doris.monitor.jvm.JvmService;
import org.apache.doris.monitor.jvm.JvmStats;
-import com.codahale.metrics.Histogram;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -34,8 +34,6 @@ import org.junit.Test;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
import java.util.concurrent.atomic.AtomicInteger;
@Slf4j
@@ -73,12 +71,10 @@ public class MetricsTest {
MetricRepo.USER_COUNTER_QUERY_ALL.getOrAdd("test_user").increase(1L);
MetricRepo.USER_COUNTER_QUERY_ERR.getOrAdd("test_user").increase(1L);
MetricRepo.USER_HISTO_QUERY_LATENCY.getOrAdd("test_user").update(10L);
+
MetricRepo.USER_HISTO_QUERY_LATENCY.getOrAdd("[email protected]").update(20L);
MetricVisitor visitor = new PrometheusMetricVisitor();
MetricRepo.DORIS_METRIC_REGISTER.accept(visitor);
- SortedMap<String, Histogram> histograms =
MetricRepo.METRIC_REGISTER.getHistograms();
- for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
- visitor.visitHistogram(MetricVisitor.FE_PREFIX, entry.getKey(),
entry.getValue());
- }
+ MetricRepo.visitHistograms(visitor);
String metricResult = visitor.finish();
Assert.assertTrue(metricResult.contains("# TYPE doris_fe_query_total
counter"));
Assert.assertTrue(metricResult.contains("doris_fe_query_total{user=\"test_user\"}
1"));
@@ -87,7 +83,82 @@ public class MetricsTest {
Assert.assertTrue(metricResult.contains("# TYPE
doris_fe_query_latency_ms summary"));
Assert.assertTrue(metricResult.contains("doris_fe_query_latency_ms{quantile=\"0.999\"}
0.0"));
Assert.assertTrue(metricResult.contains("doris_fe_query_latency_ms{quantile=\"0.999\",user=\"test_user\"}
10.0"));
+ Assert.assertTrue(metricResult.contains(
+
"doris_fe_query_latency_ms{quantile=\"0.999\",user=\"[email protected]\"} 20.0"));
+
Assert.assertFalse(metricResult.contains("doris_fe_query_latency_ms_lu@lbk_one"));
+
+ }
+
+ @Test
+ public void
testPrometheusVisitorKeepsLabeledHistogramValuesOutOfMetricName() {
+ HistogramMetric histogramMetric = new
HistogramMetric("query.latency.ms",
+ Lists.newArrayList(new MetricLabel("user",
"[email protected]")));
+ histogramMetric.update(30L);
+ MetricVisitor prometheusVisitor = new PrometheusMetricVisitor();
+ prometheusVisitor.visitHistogram(MetricVisitor.FE_PREFIX,
histogramMetric.getName(),
+ histogramMetric.getHistogram(), histogramMetric.getLabels());
+ String prometheusResult = prometheusVisitor.finish();
+ Assert.assertTrue(prometheusResult.contains(
+
"doris_fe_query_latency_ms{quantile=\"0.999\",user=\"[email protected]\"}
30.0"));
+
Assert.assertFalse(prometheusResult.contains("doris_fe_query_latency_ms_liu@developertools_com"));
+ Assert.assertFalse(prometheusResult.contains("user=\"thomas\""));
+ }
+ @Test
+ public void testJsonVisitorKeepsLabeledHistogramValuesOutOfMetricName() {
+ HistogramMetric histogramMetric = new
HistogramMetric("query.latency.ms",
+ Lists.newArrayList(new MetricLabel("user",
"[email protected]")));
+ histogramMetric.update(20L);
+ MetricVisitor jsonVisitor = new JsonMetricVisitor();
+ jsonVisitor.visitHistogram(MetricVisitor.FE_PREFIX,
histogramMetric.getName(),
+ histogramMetric.getHistogram(), histogramMetric.getLabels());
+ String jsonResult = jsonVisitor.finish();
+
Assert.assertTrue(jsonResult.contains("\"metric\":\"doris_fe_query_latency_ms\""));
+ Assert.assertTrue(jsonResult.contains("\"user\":\"[email protected]\""));
+
Assert.assertFalse(jsonResult.contains("\"metric\":\"doris_fe_query_latency_ms_lu@lbk_one\""));
+ }
+
+ @Test
+ public void testHistogramMetricRegistryWithSpecialCharacters() {
+ DorisMetricRegistry registry = new DorisMetricRegistry();
+ AutoMappedMetric<HistogramMetric> clusterHisto = new
AutoMappedMetric<>(key -> {
+ String[] values = key.split(CloudMetrics.CLOUD_CLUSTER_DELIMITER,
2);
+ return new HistogramMetric("query.latency.ms", Lists.newArrayList(
+ new MetricLabel("cluster_id", values[0]), new
MetricLabel("cluster_name", values[1])));
+ });
+ AutoMappedMetric<HistogramMetric> metaHisto = new
AutoMappedMetric<>(methodName ->
+ new HistogramMetric("meta_service.rpc.latency.ms",
+ Lists.newArrayList(new MetricLabel("method",
methodName))));
+ AutoMappedMetric<HistogramMetric> disabledHisto = new
AutoMappedMetric<>(name ->
+ new HistogramMetric("disabled.latency.ms",
+ Lists.newArrayList(new MetricLabel("name", name))));
+ AutoMappedMetric<HistogramMetric> staleHisto = new
AutoMappedMetric<>(name ->
+ new HistogramMetric("stale.latency.ms",
+ Lists.newArrayList(new MetricLabel("name", name))));
+
+ registry.addHistogramMetrics("cluster_query_latency", staleHisto);
+ registry.addHistogramMetrics("cluster_query_latency", clusterHisto);
+ registry.addHistogramMetrics("meta_service_rpc_latency", metaHisto);
+ registry.addHistogramMetrics("disabled_latency", disabledHisto, () ->
false);
+
+ String clusterKey = "cluster.id-1" +
CloudMetrics.CLOUD_CLUSTER_DELIMITER + "cluster.name@prod";
+ staleHisto.getOrAdd("stale.name").update(30L);
+ clusterHisto.getOrAdd(clusterKey).update(40L);
+ metaHisto.getOrAdd("get.Instance").update(50L);
+ disabledHisto.getOrAdd("disabled.name").update(60L);
+
+ MetricVisitor prometheusVisitor = new PrometheusMetricVisitor();
+ registry.acceptHistograms(prometheusVisitor);
+ String prometheusResult = prometheusVisitor.finish();
+ Assert.assertTrue(prometheusResult.contains(
+
"doris_fe_query_latency_ms{quantile=\"0.999\",cluster_id=\"cluster.id-1\","
+ + "cluster_name=\"cluster.name@prod\"} 40.0"));
+ Assert.assertTrue(prometheusResult.contains(
+
"doris_fe_meta_service_rpc_latency_ms{quantile=\"0.999\",method=\"get.Instance\"}
50.0"));
+
Assert.assertFalse(prometheusResult.contains("doris_fe_query_latency_ms_id-1_cluster"));
+
Assert.assertFalse(prometheusResult.contains("doris_fe_meta_service_rpc_latency_ms_Instance"));
+
Assert.assertFalse(prometheusResult.contains("doris_fe_stale_latency_ms"));
+
Assert.assertFalse(prometheusResult.contains("doris_fe_disabled_latency_ms"));
}
@Test
@@ -209,10 +280,7 @@ public class MetricsTest {
// doris metrics and system metrics.
MetricRepo.DORIS_METRIC_REGISTER.accept(visitor);
// histogram
- SortedMap<String, Histogram> histograms =
MetricRepo.METRIC_REGISTER.getHistograms();
- for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
- visitor.visitHistogram(MetricVisitor.FE_PREFIX, entry.getKey(),
entry.getValue());
- }
+ MetricRepo.visitHistograms(visitor);
String metricResult = visitor.finish();
Assert.assertTrue(metricResult.contains("# TYPE
doris_fe_async_materialized_view_task_failed_num counter"));
@@ -232,10 +300,7 @@ public class MetricsTest {
// doris metrics and system metrics.
MetricRepo.DORIS_METRIC_REGISTER.accept(visitor);
// histogram
- SortedMap<String, Histogram> histograms =
MetricRepo.METRIC_REGISTER.getHistograms();
- for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
- visitor.visitHistogram(MetricVisitor.FE_PREFIX, entry.getKey(),
entry.getValue());
- }
+ MetricRepo.visitHistograms(visitor);
String metricResult = visitor.finish();
Assert.assertTrue(metricResult.contains("# TYPE
doris_fe_statistics_succeed_analyze_job counter"));
@@ -262,10 +327,7 @@ public class MetricsTest {
// doris metrics and system metrics.
MetricRepo.DORIS_METRIC_REGISTER.accept(visitor);
// histogram
- SortedMap<String, Histogram> histograms =
MetricRepo.METRIC_REGISTER.getHistograms();
- for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
- visitor.visitHistogram(MetricVisitor.FE_PREFIX, entry.getKey(),
entry.getValue());
- }
+ MetricRepo.visitHistograms(visitor);
String metricResult = visitor.finish();
Assert.assertTrue(metricResult.contains("# TYPE doris_fe_sql_cache_num
gauge"));
@@ -281,10 +343,7 @@ public class MetricsTest {
// doris metrics and system metrics.
MetricRepo.DORIS_METRIC_REGISTER.accept(visitor);
// histogram
- SortedMap<String, Histogram> histograms =
MetricRepo.METRIC_REGISTER.getHistograms();
- for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
- visitor.visitHistogram(MetricVisitor.FE_PREFIX, entry.getKey(),
entry.getValue());
- }
+ MetricRepo.visitHistograms(visitor);
String metricResult = visitor.finish();
Assert.assertTrue(metricResult.contains("# TYPE doris_fe_plan_num
gauge"));
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]