From d28556e35c7f3d61716396f31ccd3a4ee137bbb9 Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 21 Apr 2025 08:33:37 -0400 Subject: [PATCH] add partial label support (WIP) --- .../src/net/i2p/stat/prometheus/Info.java | 28 ++--- .../src/net/i2p/stat/prometheus/PromStat.java | 100 +++++++++++++++++- 2 files changed, 111 insertions(+), 17 deletions(-) diff --git a/core/java/src/net/i2p/stat/prometheus/Info.java b/core/java/src/net/i2p/stat/prometheus/Info.java index dfe5bdc27..2e6f9770d 100644 --- a/core/java/src/net/i2p/stat/prometheus/Info.java +++ b/core/java/src/net/i2p/stat/prometheus/Info.java @@ -12,7 +12,7 @@ import java.util.concurrent.atomic.AtomicInteger; */ public class Info extends PromStat implements IntSupplier, PropsSupplier, PropsConsumer { - private final Map props; + private final Map labels; /** * Map returned by getValues() will be a ConcurrentHashMap @@ -22,12 +22,12 @@ public class Info extends PromStat implements IntSupplier, PropsSupplier, PropsC } /** - * @param props use caution, use a ConcurrentHashMap if setValue() or accept() - * will be called later to change the properties + * @param labels use caution, use a ConcurrentHashMap if setValue() or accept() + * will be called later to add label names or change the label values */ - public Info(String name, String desc, Map props) { + public Info(String name, String desc, Map labels) { super(name, desc, Type.GAUGE, Unit.NONE); - this.props = (props != null) ? props : new ConcurrentHashMap(4); + this.labels = (labels != null) ? labels : new ConcurrentHashMap(4); } public int getValue() { @@ -41,16 +41,16 @@ public class Info extends PromStat implements IntSupplier, PropsSupplier, PropsC /** * @return not a copy */ - public Map getValues() { - return props; + public Map getLabels() { + return labels; } - public void setValue(String key, String val) { - props.put(key, val); + public void setLabel(String labelName, String labelValue) { + labels.put(labelName, labelValue); } - public void removeValue(String key) { - props.remove(key); + public void removeLabel(String labelName) { + labels.remove(labelName); } /** @@ -64,13 +64,13 @@ public class Info extends PromStat implements IntSupplier, PropsSupplier, PropsC * Supplier interface */ public Map getAsMap() { - return props; + return labels; } /** * Consumer interface */ - public void accept(Map values) { - props.putAll(values); + public void accept(Map labels) { + this.labels.putAll(labels); } } diff --git a/core/java/src/net/i2p/stat/prometheus/PromStat.java b/core/java/src/net/i2p/stat/prometheus/PromStat.java index 2abcf634d..9ddd72059 100644 --- a/core/java/src/net/i2p/stat/prometheus/PromStat.java +++ b/core/java/src/net/i2p/stat/prometheus/PromStat.java @@ -15,25 +15,55 @@ public abstract class PromStat { private final String desc; private final String name; private final String promName; + private final String labelName; + private final String[] labelValues; private final Type type; private final Unit unit; /* + * No label + * * @param name [a-zA-Z0-9_.] only. '.' will be replaced with '_' for getPromName() */ public PromStat(String name, String description, Type type, Unit unit) { + this(name, description, type, unit, null); + } + + /* + * With one label and one or more values + * + * @param name [a-zA-Z0-9_.] only. '.' will be replaced with '_' for getPromName() + * @param label [a-zA-Z0-9_.] only. '.' will be replaced with '_' for getLabelName() + * for example "dir" + * @param values for example "in", "out" + */ + public PromStat(String name, String description, Type type, Unit unit, String label, String... values) { this.name = name; desc = description; this.type = type; this.unit = unit; - String p = name.replace(".", "_"); - if (p.replaceAll("[a-zA-Z0-9_]", "").length() != 0) - throw new IllegalArgumentException("invalid chars in name " + name); + String p = fixup(name); if (type != Type.INFO) p += '_' + unit.getName(); if (type == Type.COUNTER) p += "_total"; promName = p; + if (label != null) { + labelName = fixup(label); + if (values == null || values.length == 0) + throw new IllegalArgumentException("must have at least one label value"); + labelValues = values; + } else { + labelName = null; + labelValues = null; + } + } + + static String fixup(String name) { + String p = name.replace(".", "_"); + if (p.replaceAll("[a-zA-Z0-9_]", "").length() != 0) + throw new IllegalArgumentException("invalid chars in name or label " + name); + return p; } public String getName() { @@ -44,6 +74,36 @@ public abstract class PromStat { return promName; } + /** + * @return may be null + */ + public String getLabelName() { + return labelName; + } + + /** + * @return may be null + */ + public String[] getLabelValues() { + return labelValues; + } + + /** + * @return may be null + */ + public String getLabelValue(int labelValueIndex) { + if (labelValues == null || labelValueIndex < 0 || labelValueIndex >= labelValues.length) + return null; + return labelValues[labelValueIndex]; + } + + /** + * @return number of label values + */ + public int getLabelValueCount() { + return labelValues != null ? labelValues.length : 0; + } + public String getDescription() { return desc; } @@ -53,11 +113,26 @@ public abstract class PromStat { public Unit getUnit() { return unit; } /** + * No label. * In units specified */ public abstract double getDoubleValue(); /** + * This implementation requires labelValueIndex to be 0, + * and returns getDoubleValue(). + * Classes supporting labels must override. + * + * @return getDoubleValue() + */ + public double getDoubleValue(int labelValueIndex) { + if (labelValueIndex != 0) + throw new IllegalArgumentException("Index must be 0"); + return getDoubleValue(); + } + + /** + * No label. * Scaled to what Prometheus expects, * seconds, bytes, or count. */ @@ -75,6 +150,25 @@ public abstract class PromStat { return rv; } + /** + * With label. + * Scaled to what Prometheus expects, + * seconds, bytes, or count. + */ + public double getScaledValue(int labelValueIndex) { + double rv = getDoubleValue(labelValueIndex); + switch (unit) { + case KBYTES: + rv *= 1000f; + break; + + case MS: + rv /= 1000f; + break; + } + return rv; + } + /** * For StatManager. * Does nothing (for counters), extend for guages if necessary.