Allow to attach labels to metrics (#2650)
* Allow to attach labels to metrics
* Removed testCache since it's now invalid
* Fixed checkstyle
* Unused imports
* Fixed test
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperClientStats.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperClientStats.java
index ddc757e..7d58e5f 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperClientStats.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeperClientStats.java
@@ -103,6 +103,8 @@
String WRITE_TIMED_OUT_DUE_TO_NOT_ENOUGH_FAULT_DOMAINS = "WRITE_TIME_OUT_DUE_TO_NOT_ENOUGH_FAULT_DOMAINS";
String NUM_WRITABLE_BOOKIES_IN_DEFAULT_FAULTDOMAIN = "NUM_WRITABLE_BOOKIES_IN_DEFAULT_FAULTDOMAIN";
+ String BOOKIE_LABEL = "bookie";
+
OpStatsLogger getCreateOpLogger();
OpStatsLogger getOpenOpLogger();
OpStatsLogger getDeleteOpLogger();
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/impl/BookKeeperClientStatsImpl.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/impl/BookKeeperClientStatsImpl.java
index 811a4b8..db1b448 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/impl/BookKeeperClientStatsImpl.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/impl/BookKeeperClientStatsImpl.java
@@ -274,7 +274,7 @@
}
@Override
public Counter getEnsembleBookieDistributionCounter(String bookie) {
- return stats.getCounter(LEDGER_ENSEMBLE_BOOKIE_DISTRIBUTION + "-" + bookie);
+ return stats.scopeLabel(BOOKIE_LABEL, bookie).getCounter(LEDGER_ENSEMBLE_BOOKIE_DISTRIBUTION);
}
@Override
public OpStatsLogger getWriteDelayedDueToNotEnoughFaultDomainsLatency() {
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java
index 89863a3..279497e 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/PerChannelBookieClient.java
@@ -404,7 +404,7 @@
}
this.statsLogger = parentStatsLogger.scope(BookKeeperClientStats.CHANNEL_SCOPE)
- .scope(buildStatsLoggerScopeName(bookieId));
+ .scopeLabel(BookKeeperClientStats.BOOKIE_LABEL, bookieId.toString());
readEntryOpLogger = statsLogger.getOpStatsLogger(BookKeeperClientStats.CHANNEL_READ_OP);
addEntryOpLogger = statsLogger.getOpStatsLogger(BookKeeperClientStats.CHANNEL_ADD_OP);
@@ -504,12 +504,6 @@
};
}
- public static String buildStatsLoggerScopeName(BookieId addr) {
- StringBuilder nameBuilder = new StringBuilder();
- nameBuilder.append(addr.toString().replace('.', '_').replace('-', '_').replace(":", "_"));
- return nameBuilder.toString();
- }
-
private void completeOperation(GenericCallback<PerChannelBookieClient> op, int rc) {
//Thread.dumpStack();
closeLock.readLock().lock();
diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDelayEnsembleChange.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDelayEnsembleChange.java
index 7b73f8b..996c040 100644
--- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDelayEnsembleChange.java
+++ b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/TestDelayEnsembleChange.java
@@ -197,7 +197,8 @@
assertTrue(
LEDGER_ENSEMBLE_BOOKIE_DISTRIBUTION + " should be > 0 for " + addr,
bkc.getTestStatsProvider().getCounter(
- CLIENT_SCOPE + "." + LEDGER_ENSEMBLE_BOOKIE_DISTRIBUTION + "-" + addr)
+ CLIENT_SCOPE + ".bookie_" + addr.toString().replace('-', '_')
+ + "." + LEDGER_ENSEMBLE_BOOKIE_DISTRIBUTION)
.get() > 0);
}
assertTrue(
diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieClientTest.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieClientTest.java
index ff838f3..944203c 100644
--- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieClientTest.java
+++ b/bookkeeper-server/src/test/java/org/apache/bookkeeper/test/BookieClientTest.java
@@ -57,7 +57,6 @@
import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.ReadEntryCallback;
import org.apache.bookkeeper.proto.BookkeeperInternalCallbacks.WriteCallback;
import org.apache.bookkeeper.proto.BookkeeperProtocol;
-import org.apache.bookkeeper.proto.PerChannelBookieClient;
import org.apache.bookkeeper.stats.NullStatsLogger;
import org.apache.bookkeeper.test.TestStatsProvider.TestOpStatsLogger;
import org.apache.bookkeeper.test.TestStatsProvider.TestStatsLogger;
@@ -338,7 +337,7 @@
TestOpStatsLogger perChannelBookieClientScopeOfThisAddr = (TestOpStatsLogger) statsLogger
.scope(BookKeeperClientStats.CHANNEL_SCOPE)
- .scope(PerChannelBookieClient.buildStatsLoggerScopeName(addr.toBookieId()))
+ .scopeLabel(BookKeeperClientStats.BOOKIE_LABEL, addr.toBookieId().toString())
.getOpStatsLogger(BookKeeperClientStats.GET_BOOKIE_INFO_OP);
int expectedBookieInfoSuccessCount = (limitStatsLogging) ? 0 : 1;
assertEquals("BookieInfoSuccessCount", expectedBookieInfoSuccessCount,
diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java
index 3123b8b..d235073 100644
--- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java
+++ b/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java
@@ -27,7 +27,6 @@
import java.io.File;
import java.io.IOException;
-import java.net.InetSocketAddress;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
@@ -60,7 +59,6 @@
import org.apache.bookkeeper.proto.BookieConnectionPeer;
import org.apache.bookkeeper.proto.BookieServer;
import org.apache.bookkeeper.proto.ClientConnectionPeer;
-import org.apache.bookkeeper.proto.PerChannelBookieClient;
import org.apache.bookkeeper.proto.TestPerChannelBookieClient;
import org.apache.bookkeeper.test.BookKeeperClusterTestCase;
import org.apache.bookkeeper.test.TestStatsProvider;
@@ -884,10 +882,12 @@
// verify stats
for (int i = 0; i < numBookies; i++) {
BookieServer bookie = bs.get(i);
- InetSocketAddress addr = bookie.getLocalAddress().getSocketAddress();
StringBuilder nameBuilder = new StringBuilder(BookKeeperClientStats.CHANNEL_SCOPE)
.append(".")
- .append(PerChannelBookieClient.buildStatsLoggerScopeName(bookie.getBookieId()))
+ .append("bookie_")
+ .append(bookie.getBookieId().toString()
+ .replace('.', '_')
+ .replace('-', '_'))
.append(".");
// check stats on TLS enabled client
@@ -983,10 +983,12 @@
}
// check failed handshake counter
- InetSocketAddress addr = bookie.getLocalAddress().getSocketAddress();
StringBuilder nameBuilder = new StringBuilder(BookKeeperClientStats.CHANNEL_SCOPE)
.append(".")
- .append(PerChannelBookieClient.buildStatsLoggerScopeName(bookie.getBookieId()))
+ .append("bookie_")
+ .append(bookie.getBookieId().toString()
+ .replace('.', '_')
+ .replace('-', '_'))
.append(".");
assertEquals("TLS handshake failure expected", 1,
diff --git a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/DataSketchesOpStatsLogger.java b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/DataSketchesOpStatsLogger.java
index ad0e7d4..0c72d580 100644
--- a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/DataSketchesOpStatsLogger.java
+++ b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/DataSketchesOpStatsLogger.java
@@ -55,9 +55,12 @@
private final LongAdder successSumAdder = new LongAdder();
private final LongAdder failSumAdder = new LongAdder();
- DataSketchesOpStatsLogger() {
+ private final Map<String, String> labels;
+
+ public DataSketchesOpStatsLogger(Map<String, String> labels) {
this.current = new ThreadLocalAccessor();
this.replacement = new ThreadLocalAccessor();
+ this.labels = labels;
}
@Override
@@ -173,6 +176,10 @@
return s != null ? s.getQuantile(quantile) : Double.NaN;
}
+ public Map<String, String> getLabels() {
+ return labels;
+ }
+
private static class LocalData {
private final DoublesSketch successSketch = new DoublesSketchBuilder().build();
private final DoublesSketch failSketch = new DoublesSketchBuilder().build();
diff --git a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/LongAdderCounter.java b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/LongAdderCounter.java
index 4b67703..ddd278e 100644
--- a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/LongAdderCounter.java
+++ b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/LongAdderCounter.java
@@ -16,6 +16,7 @@
*/
package org.apache.bookkeeper.stats.prometheus;
+import java.util.Map;
import java.util.concurrent.atomic.LongAdder;
import org.apache.bookkeeper.stats.Counter;
@@ -29,6 +30,12 @@
public class LongAdderCounter implements Counter {
private final LongAdder counter = new LongAdder();
+ private final Map<String, String> labels;
+
+ public LongAdderCounter(Map<String, String> labels) {
+ this.labels = labels;
+ }
+
@Override
public void clear() {
counter.reset();
@@ -53,4 +60,8 @@
public Long get() {
return counter.sum();
}
+
+ public Map<String, String> getLabels() {
+ return labels;
+ }
}
diff --git a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusMetricsProvider.java b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusMetricsProvider.java
index f999068..573df79 100644
--- a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusMetricsProvider.java
+++ b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusMetricsProvider.java
@@ -35,14 +35,14 @@
import java.io.Writer;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
-import org.apache.bookkeeper.stats.CachingStatsProvider;
import org.apache.bookkeeper.stats.StatsLogger;
import org.apache.bookkeeper.stats.StatsProvider;
import org.apache.commons.configuration.Configuration;
@@ -75,14 +75,13 @@
final CollectorRegistry registry;
Server server;
- private final CachingStatsProvider cachingStatsProvider;
/*
* These acts a registry of the metrics defined in this provider
*/
- final ConcurrentMap<String, LongAdderCounter> counters = new ConcurrentSkipListMap<>();
- final ConcurrentMap<String, SimpleGauge<? extends Number>> gauges = new ConcurrentSkipListMap<>();
- final ConcurrentMap<String, DataSketchesOpStatsLogger> opStats = new ConcurrentSkipListMap<>();
+ final ConcurrentMap<ScopeContext, LongAdderCounter> counters = new ConcurrentHashMap<>();
+ final ConcurrentMap<ScopeContext, SimpleGauge<? extends Number>> gauges = new ConcurrentHashMap<>();
+ final ConcurrentMap<ScopeContext, DataSketchesOpStatsLogger> opStats = new ConcurrentHashMap<>();
public PrometheusMetricsProvider() {
this(CollectorRegistry.defaultRegistry);
@@ -90,35 +89,6 @@
public PrometheusMetricsProvider(CollectorRegistry registry) {
this.registry = registry;
- this.cachingStatsProvider = new CachingStatsProvider(new StatsProvider() {
- @Override
- public void start(Configuration conf) {
- // nop
- }
-
- @Override
- public void stop() {
- // nop
- }
-
- @Override
- public StatsLogger getStatsLogger(String scope) {
- return new PrometheusStatsLogger(PrometheusMetricsProvider.this, scope);
- }
-
- @Override
- public String getStatsName(String... statsComponents) {
- String completeName;
- if (statsComponents.length == 0) {
- return "";
- } else if (statsComponents[0].isEmpty()) {
- completeName = StringUtils.join(statsComponents, '_', 1, statsComponents.length);
- } else {
- completeName = StringUtils.join(statsComponents, '_');
- }
- return Collector.sanitizeMetricName(completeName);
- }
- });
}
@Override
@@ -190,21 +160,30 @@
@Override
public StatsLogger getStatsLogger(String scope) {
- return this.cachingStatsProvider.getStatsLogger(scope);
+ return new PrometheusStatsLogger(PrometheusMetricsProvider.this, scope, Collections.emptyMap());
}
@Override
public void writeAllMetrics(Writer writer) throws IOException {
PrometheusTextFormatUtil.writeMetricsCollectedByPrometheusClient(writer, registry);
- gauges.forEach((name, gauge) -> PrometheusTextFormatUtil.writeGauge(writer, name, gauge));
- counters.forEach((name, counter) -> PrometheusTextFormatUtil.writeCounter(writer, name, counter));
- opStats.forEach((name, opStatLogger) -> PrometheusTextFormatUtil.writeOpStat(writer, name, opStatLogger));
+ gauges.forEach((sc, gauge) -> PrometheusTextFormatUtil.writeGauge(writer, sc.getScope(), gauge));
+ counters.forEach((sc, counter) -> PrometheusTextFormatUtil.writeCounter(writer, sc.getScope(), counter));
+ opStats.forEach((sc, opStatLogger) ->
+ PrometheusTextFormatUtil.writeOpStat(writer, sc.getScope(), opStatLogger));
}
@Override
public String getStatsName(String... statsComponents) {
- return cachingStatsProvider.getStatsName(statsComponents);
+ String completeName;
+ if (statsComponents.length == 0) {
+ return "";
+ } else if (statsComponents[0].isEmpty()) {
+ completeName = StringUtils.join(statsComponents, '_', 1, statsComponents.length);
+ } else {
+ completeName = StringUtils.join(statsComponents, '_');
+ }
+ return Collector.sanitizeMetricName(completeName);
}
@VisibleForTesting
diff --git a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusStatsLogger.java b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusStatsLogger.java
index 472a3fb..dcc7527 100644
--- a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusStatsLogger.java
+++ b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusStatsLogger.java
@@ -19,7 +19,8 @@
import com.google.common.base.Joiner;
import io.prometheus.client.Collector;
-
+import java.util.Map;
+import java.util.TreeMap;
import org.apache.bookkeeper.stats.Counter;
import org.apache.bookkeeper.stats.Gauge;
import org.apache.bookkeeper.stats.OpStatsLogger;
@@ -32,25 +33,27 @@
private final PrometheusMetricsProvider provider;
private final String scope;
+ private final Map<String, String> labels;
- PrometheusStatsLogger(PrometheusMetricsProvider provider, String scope) {
+ PrometheusStatsLogger(PrometheusMetricsProvider provider, String scope, Map<String, String> labels) {
this.provider = provider;
this.scope = scope;
+ this.labels = labels;
}
@Override
public OpStatsLogger getOpStatsLogger(String name) {
- return provider.opStats.computeIfAbsent(completeName(name), x -> new DataSketchesOpStatsLogger());
+ return provider.opStats.computeIfAbsent(scopeContext(name), x -> new DataSketchesOpStatsLogger(labels));
}
@Override
public Counter getCounter(String name) {
- return provider.counters.computeIfAbsent(completeName(name), x -> new LongAdderCounter());
+ return provider.counters.computeIfAbsent(scopeContext(name), x -> new LongAdderCounter(labels));
}
@Override
public <T extends Number> void registerGauge(String name, Gauge<T> gauge) {
- provider.gauges.computeIfAbsent(completeName(name), x -> new SimpleGauge<T>(gauge));
+ provider.gauges.computeIfAbsent(scopeContext(name), x -> new SimpleGauge<T>(gauge, labels));
}
@Override
@@ -65,11 +68,21 @@
@Override
public StatsLogger scope(String name) {
- return new PrometheusStatsLogger(provider, completeName(name));
+ return new PrometheusStatsLogger(provider, completeName(name), labels);
+ }
+
+ @Override
+ public StatsLogger scopeLabel(String labelName, String labelValue) {
+ Map<String, String> newLabels = new TreeMap<>(labels);
+ newLabels.put(labelName, labelValue);
+ return new PrometheusStatsLogger(provider, scope, newLabels);
+ }
+
+ private ScopeContext scopeContext(String name) {
+ return new ScopeContext(completeName(name), labels);
}
private String completeName(String name) {
- String completeName = scope.isEmpty() ? name : Joiner.on('_').join(scope, name);
- return Collector.sanitizeMetricName(completeName);
+ return Collector.sanitizeMetricName(scope.isEmpty() ? name : Joiner.on('_').join(scope, name));
}
}
diff --git a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusTextFormatUtil.java b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusTextFormatUtil.java
index d2fae28..330bcd6 100644
--- a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusTextFormatUtil.java
+++ b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/PrometheusTextFormatUtil.java
@@ -24,8 +24,7 @@
import java.io.IOException;
import java.io.Writer;
import java.util.Enumeration;
-
-import org.apache.bookkeeper.stats.Counter;
+import java.util.Map;
/**
* Logic to write metrics in Prometheus text format.
@@ -37,19 +36,23 @@
// bookie_storage_entries_count 519
try {
w.append("# TYPE ").append(name).append(" gauge\n");
- w.append(name).append(' ').append(gauge.getSample().toString()).append('\n');
+ w.append(name);
+ writeLabels(w, gauge.getLabels());
+ w.append(' ').append(gauge.getSample().toString()).append('\n');
} catch (IOException e) {
throw new RuntimeException(e);
}
}
- static void writeCounter(Writer w, String name, Counter counter) {
+ static void writeCounter(Writer w, String name, LongAdderCounter counter) {
// Example:
// # TYPE jvm_threads_started_total counter
// jvm_threads_started_total 59
try {
w.append("# TYPE ").append(name).append(" counter\n");
- w.append(name).append(' ').append(counter.get().toString()).append('\n');
+ w.append(name);
+ writeLabels(w, counter.getLabels());
+ w.append(' ').append(counter.get().toString()).append('\n');
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -103,22 +106,58 @@
}
}
+ private static void writeLabels(Writer w, Map<String, String> labels) throws IOException {
+ if (labels.isEmpty()) {
+ return;
+ }
+
+ w.append('{');
+ writeLabelsNoBraces(w, labels);
+ w.append('}');
+ }
+
+ private static void writeLabelsNoBraces(Writer w, Map<String, String> labels) throws IOException {
+ if (labels.isEmpty()) {
+ return;
+ }
+
+ boolean isFirst = true;
+ for (Map.Entry<String, String> e : labels.entrySet()) {
+ if (!isFirst) {
+ w.append(',');
+ }
+ isFirst = false;
+ w.append(e.getKey())
+ .append("=\"")
+ .append(e.getValue())
+ .append('"');
+ }
+ }
+
private static void writeQuantile(Writer w, DataSketchesOpStatsLogger opStat, String name, Boolean success,
double quantile) throws IOException {
- w.append(name).append("{success=\"").append(success.toString()).append("\",quantile=\"")
- .append(Double.toString(quantile)).append("\"} ")
+ w.append(name)
+ .append("{success=\"").append(success.toString())
+ .append("\",quantile=\"").append(Double.toString(quantile))
+ .append("\", ");
+ writeLabelsNoBraces(w, opStat.getLabels());
+ w.append("} ")
.append(Double.toString(opStat.getQuantileValue(success, quantile))).append('\n');
}
private static void writeCount(Writer w, DataSketchesOpStatsLogger opStat, String name, Boolean success)
throws IOException {
- w.append(name).append("_count{success=\"").append(success.toString()).append("\"} ")
+ w.append(name).append("_count{success=\"").append(success.toString()).append("\", ");
+ writeLabelsNoBraces(w, opStat.getLabels());
+ w.append("\"} ")
.append(Long.toString(opStat.getCount(success))).append('\n');
}
private static void writeSum(Writer w, DataSketchesOpStatsLogger opStat, String name, Boolean success)
throws IOException {
- w.append(name).append("_sum{success=\"").append(success.toString()).append("\"} ")
+ w.append(name).append("_sum{success=\"").append(success.toString()).append("\", ");
+ writeLabelsNoBraces(w, opStat.getLabels());
+ w.append("\"} ")
.append(Double.toString(opStat.getSum(success))).append('\n');
}
diff --git a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/ScopeContext.java b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/ScopeContext.java
new file mode 100644
index 0000000..48a8d63
--- /dev/null
+++ b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/ScopeContext.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bookkeeper.stats.prometheus;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Holder for a scope and a set of associated labels.
+ */
+public class ScopeContext {
+ private final String scope;
+ private final Map<String, String> labels;
+
+ public ScopeContext(String scope, Map<String, String> labels) {
+ this.scope = scope;
+ this.labels = labels;
+ }
+
+ public String getScope() {
+ return scope;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ScopeContext that = (ScopeContext) o;
+ return Objects.equals(scope, that.scope) && Objects.equals(labels, that.labels);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(scope, labels);
+ }
+}
diff --git a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/SimpleGauge.java b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/SimpleGauge.java
index 1f30872..1d831cc 100644
--- a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/SimpleGauge.java
+++ b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/prometheus/SimpleGauge.java
@@ -16,6 +16,7 @@
*/
package org.apache.bookkeeper.stats.prometheus;
+import java.util.Map;
import org.apache.bookkeeper.stats.Gauge;
/**
@@ -23,18 +24,19 @@
*/
public class SimpleGauge<T extends Number> {
- // public SimpleGauge(CollectorRegistry registry, String name) {
- // this.gauge = PrometheusUtil.safeRegister(registry,
- // Gauge.build().name(Collector.sanitizeMetricName(name)).help("-").create());
- // }
-
+ private final Map<String, String> labels;
private final Gauge<T> gauge;
- public SimpleGauge(final Gauge<T> gauge) {
+ public SimpleGauge(final Gauge<T> gauge, Map<String, String> labels) {
this.gauge = gauge;
+ this.labels = labels;
}
Number getSample() {
return gauge.getSample();
}
+
+ public Map<String, String> getLabels() {
+ return labels;
+ }
}
diff --git a/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusMetricsProvider.java b/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusMetricsProvider.java
index 5fd34a3..df954e6 100644
--- a/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusMetricsProvider.java
+++ b/bookkeeper-stats-providers/prometheus-metrics-provider/src/test/java/org/apache/bookkeeper/stats/prometheus/TestPrometheusMetricsProvider.java
@@ -21,9 +21,9 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
+import java.util.Collections;
import lombok.Cleanup;
import org.apache.bookkeeper.stats.Counter;
-import org.apache.bookkeeper.stats.OpStatsLogger;
import org.apache.bookkeeper.stats.StatsLogger;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.junit.Test;
@@ -34,25 +34,6 @@
public class TestPrometheusMetricsProvider {
@Test
- public void testCache() {
- PrometheusMetricsProvider provider = new PrometheusMetricsProvider();
-
- StatsLogger statsLogger = provider.getStatsLogger("test");
-
- OpStatsLogger opStatsLogger1 = statsLogger.getOpStatsLogger("optest");
- OpStatsLogger opStatsLogger2 = statsLogger.getOpStatsLogger("optest");
- assertSame(opStatsLogger1, opStatsLogger2);
-
- Counter counter1 = statsLogger.getCounter("countertest");
- Counter counter2 = statsLogger.getCounter("countertest");
- assertSame(counter1, counter2);
-
- StatsLogger scope1 = statsLogger.scope("scopetest");
- StatsLogger scope2 = statsLogger.scope("scopetest");
- assertSame(scope1, scope2);
- }
-
- @Test
public void testStartNoHttp() {
PropertiesConfiguration config = new PropertiesConfiguration();
config.setProperty(PrometheusMetricsProvider.PROMETHEUS_STATS_HTTP_ENABLE, false);
@@ -106,7 +87,7 @@
@Test
public void testCounter() {
- LongAdderCounter counter = new LongAdderCounter();
+ LongAdderCounter counter = new LongAdderCounter(Collections.emptyMap());
long value = counter.get();
assertEquals(0L, value);
counter.inc();
diff --git a/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/StatsLogger.java b/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/StatsLogger.java
index f750685..3023d36 100644
--- a/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/StatsLogger.java
+++ b/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/StatsLogger.java
@@ -65,6 +65,27 @@
StatsLogger scope(String name);
/**
+ * Provide the stats logger with an attached label.
+ *
+ * @param labelName
+ * the name of the label.
+ * @param labelValue
+ * the value of the label.
+ *
+ * @return stats logger under scope <i>name</i>.
+ */
+ default StatsLogger scopeLabel(String labelName, String labelValue) {
+ // Provide default implementation for backward compatibility
+ return scope(new StringBuilder()
+ .append(labelName)
+ .append('_')
+ .append(labelValue.replace('.', '_')
+ .replace('-', '_')
+ .replace(':', '_'))
+ .toString());
+ }
+
+ /**
* Remove the given <i>statsLogger</i> for scope <i>name</i>.
* It can be no-op if the underlying stats provider doesn't have the ability to remove scope.
*