Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
2ffce5d002 | |||
8c4fd32450 | |||
d1b24274c7 | |||
4fd82a9fe9 | |||
d28556e35c | |||
b9eda05ac4 |
@ -12,6 +12,7 @@ import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.stat.prometheus.PromStat;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@ -25,6 +26,12 @@ public class StatManager {
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
|
||||
/**
|
||||
* stat name to PromStat
|
||||
* @since 0.9.67
|
||||
*/
|
||||
private final ConcurrentHashMap<String, PromStat> _promStats;
|
||||
|
||||
/** stat name to FrequencyStat */
|
||||
private final ConcurrentHashMap<String, FrequencyStat> _frequencyStats;
|
||||
/** stat name to RateStat */
|
||||
@ -57,6 +64,7 @@ public class StatManager {
|
||||
public StatManager(I2PAppContext context) {
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(getClass());
|
||||
_promStats = new ConcurrentHashMap<String, PromStat>(32);
|
||||
_frequencyStats = new ConcurrentHashMap<String,FrequencyStat>(8);
|
||||
_rateStats = new ConcurrentHashMap<String,RateStat>(128);
|
||||
String filter = getStatFilter();
|
||||
@ -66,6 +74,7 @@ public class StatManager {
|
||||
|
||||
/** @since 0.8.8 */
|
||||
public synchronized void shutdown() {
|
||||
_promStats.clear();
|
||||
_frequencyStats.clear();
|
||||
_rateStats.clear();
|
||||
}
|
||||
@ -236,6 +245,70 @@ public class StatManager {
|
||||
return _frequencyStats.containsKey(statName);
|
||||
}
|
||||
|
||||
///// begin PromStats /////
|
||||
|
||||
/**
|
||||
* Is the given stat a PromStat?
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public boolean isPromStat(String statName) {
|
||||
return _promStats.containsKey(statName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PromStat.
|
||||
* The stat is ONLY created if the stat.full property is true or we are not in the router context.
|
||||
*
|
||||
* @param name unique name of the statistic
|
||||
* @param description simple description of the statistic
|
||||
* @param group used to group statistics together
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public void createPromStat(PromStat ps) {
|
||||
if (ignoreStat(ps.getName()))
|
||||
return;
|
||||
createRequiredPromStat(ps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PromStat.
|
||||
* The stat is always created, independent of the stat.full setting or context.
|
||||
*
|
||||
* @param name unique name of the statistic
|
||||
* @param description simple description of the statistic
|
||||
* @param group used to group statistics together
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public void createRequiredPromStat(PromStat ps) {
|
||||
_promStats.putIfAbsent(ps.getName(), ps);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a PromStat.
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public void removePromStat(PromStat ps) {
|
||||
removePromStat(ps.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a PromStat.
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public void removePromStat(String name) {
|
||||
_promStats.remove(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a PromStat.
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public PromStat getPromStat(String name) {
|
||||
return _promStats.get(name);
|
||||
}
|
||||
|
||||
///// end PromStats /////
|
||||
|
||||
/**
|
||||
* Group name (untranslated String) to a SortedSet of untranslated stat names.
|
||||
* Map is unsorted.
|
||||
|
69
core/java/src/net/i2p/stat/prometheus/AtomicFloat.java
Normal file
69
core/java/src/net/i2p/stat/prometheus/AtomicFloat.java
Normal file
@ -0,0 +1,69 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/*
|
||||
* Contains code adapted from Google Guava AtomicDouble:
|
||||
*
|
||||
* Written by Doug Lea and Martin Buchholz with assistance from
|
||||
* members of JCP JSR-166 Expert Group and released to the public
|
||||
* domain, as explained at
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import static java.lang.Float.*;
|
||||
|
||||
/**
|
||||
* ref: https://stackoverflow.com/questions/5505460/java-is-there-no-atomicfloat-or-atomicfloat
|
||||
* with code adapted from Google Guava AtomicDouble
|
||||
* ref: https://github.com/google/guava/blob/master/guava/src/com/google/common/util/concurrent/AtomicDouble.java
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public class AtomicFloat extends Number {
|
||||
|
||||
private final AtomicInteger bits;
|
||||
|
||||
public AtomicFloat() {
|
||||
bits = new AtomicInteger();
|
||||
}
|
||||
|
||||
public AtomicFloat(float initialValue) {
|
||||
bits = new AtomicInteger(floatToIntBits(initialValue));
|
||||
}
|
||||
|
||||
public final void set(float newValue) {
|
||||
bits.set(floatToIntBits(newValue));
|
||||
}
|
||||
|
||||
public final float get() {
|
||||
return intBitsToFloat(bits.get());
|
||||
}
|
||||
|
||||
public final float incrementAndGet() {
|
||||
return addAndGet(1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Code adapted from Google Guava AtomicDouble
|
||||
*/
|
||||
public final float addAndGet(float value) {
|
||||
while (true) {
|
||||
int current = bits.get();
|
||||
float currentVal = intBitsToFloat(current);
|
||||
float nextVal = currentVal + value;
|
||||
int next = floatToRawIntBits(nextVal);
|
||||
if (bits.compareAndSet(current, next))
|
||||
return nextVal;
|
||||
}
|
||||
}
|
||||
|
||||
public int intValue() { return (int) get(); }
|
||||
public long longValue() { return (long) get(); }
|
||||
public float floatValue() { return get(); }
|
||||
public double doubleValue() { return get(); }
|
||||
|
||||
@Override
|
||||
public String toString() { return Double.toString(get()); }
|
||||
|
||||
|
||||
}
|
49
core/java/src/net/i2p/stat/prometheus/Counter.java
Normal file
49
core/java/src/net/i2p/stat/prometheus/Counter.java
Normal file
@ -0,0 +1,49 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* A simple Prometheus-style counter, with overflow protection.
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public abstract class Counter extends PromStat {
|
||||
|
||||
public Counter(String name, String desc, String group, Unit unit) {
|
||||
super(name, desc, group, Type.COUNTER, unit);
|
||||
}
|
||||
|
||||
public Counter(String name, String desc, String group, Unit unit, String label, String... values) {
|
||||
super(name, desc, group, Type.COUNTER, unit, label, values);
|
||||
}
|
||||
|
||||
public abstract void increment();
|
||||
public abstract void add(int value);
|
||||
public abstract void add(long value);
|
||||
public abstract void add(float value);
|
||||
public abstract void add(double value);
|
||||
|
||||
public abstract void increment(int labelIndex);
|
||||
public abstract void add(int labelIndex, int value);
|
||||
public abstract void add(int labelIndex, long value);
|
||||
public abstract void add(int labelIndex, float value);
|
||||
public abstract void add(int labelIndex, double value);
|
||||
|
||||
static void throwIfNegative(int value) {
|
||||
if (value < 0)
|
||||
throw new IllegalArgumentException("value cannot be negative");
|
||||
}
|
||||
|
||||
static void throwIfNegative(long value) {
|
||||
if (value < 0)
|
||||
throw new IllegalArgumentException("value cannot be negative");
|
||||
}
|
||||
|
||||
static void throwIfNegative(float value) {
|
||||
if (value < 0)
|
||||
throw new IllegalArgumentException("value cannot be negative");
|
||||
}
|
||||
|
||||
static void throwIfNegative(double value) {
|
||||
if (value < 0)
|
||||
throw new IllegalArgumentException("value cannot be negative");
|
||||
}
|
||||
}
|
98
core/java/src/net/i2p/stat/prometheus/FCounter.java
Normal file
98
core/java/src/net/i2p/stat/prometheus/FCounter.java
Normal file
@ -0,0 +1,98 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* A simple Prometheus-style counter.
|
||||
* No overflow protection, shouldn't happen.
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public class FCounter extends Counter implements FloatConsumer, FloatSupplier {
|
||||
|
||||
private final AtomicFloat[] a;
|
||||
|
||||
public FCounter(String name, String desc, String group, Unit unit) {
|
||||
this(name, desc, group, unit, null);
|
||||
}
|
||||
|
||||
public FCounter(String name, String desc, String group, Unit unit, String label, String... values) {
|
||||
super(name, desc, group, unit, label, values);
|
||||
a = new AtomicFloat[label != null ? values.length : 1];
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
a[i] = new AtomicFloat();
|
||||
}
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
increment(0);
|
||||
}
|
||||
|
||||
public void add(int value) {
|
||||
add(0, value);
|
||||
}
|
||||
|
||||
public void add(long value) {
|
||||
add(0, value);
|
||||
}
|
||||
|
||||
public void add(float value) {
|
||||
add(0, value);
|
||||
}
|
||||
|
||||
public void add(double value) {
|
||||
add(0, value);
|
||||
}
|
||||
|
||||
public float getValue() {
|
||||
return getValue(0);
|
||||
}
|
||||
|
||||
public double getDoubleValue() {
|
||||
return getDoubleValue(0);
|
||||
}
|
||||
|
||||
public void increment(int idx) {
|
||||
a[idx].incrementAndGet();
|
||||
}
|
||||
|
||||
public void add(int idx, int value) {
|
||||
throwIfNegative(value);
|
||||
a[idx].addAndGet(value);
|
||||
}
|
||||
|
||||
public void add(int idx, long value) {
|
||||
throwIfNegative(value);
|
||||
a[idx].addAndGet((float) value);
|
||||
}
|
||||
|
||||
public void add(int idx, float value) {
|
||||
throwIfNegative(value);
|
||||
a[idx].addAndGet(value);
|
||||
}
|
||||
|
||||
public void add(int idx, double value) {
|
||||
throwIfNegative(value);
|
||||
a[idx].addAndGet((float) value);
|
||||
}
|
||||
|
||||
public float getValue(int idx) {
|
||||
return a[idx].get();
|
||||
}
|
||||
|
||||
public double getDoubleValue(int idx) {
|
||||
return a[idx].get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplier interface
|
||||
*/
|
||||
public float getAsFloat() {
|
||||
return a[0].get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumer interface
|
||||
*/
|
||||
public void accept(float value) {
|
||||
a[0].addAndGet(value);
|
||||
}
|
||||
}
|
103
core/java/src/net/i2p/stat/prometheus/FGauge.java
Normal file
103
core/java/src/net/i2p/stat/prometheus/FGauge.java
Normal file
@ -0,0 +1,103 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
|
||||
/**
|
||||
* A simple Prometheus-style gauge
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public class FGauge extends Gauge implements FloatConsumer, FloatSupplier {
|
||||
|
||||
private final AtomicFloat[] a;
|
||||
private final FloatSupplier s;
|
||||
|
||||
public FGauge(String name, String desc, String group, Unit unit) {
|
||||
this(name, desc, group, unit, null);
|
||||
}
|
||||
|
||||
public FGauge(String name, String desc, String group, Unit unit, FloatSupplier supplier) {
|
||||
this(name, desc, group, unit, supplier, (String) null);
|
||||
}
|
||||
|
||||
public FGauge(String name, String desc, String group, Unit unit, FloatSupplier supplier, String label, String... values) {
|
||||
super(name, desc, group, unit);
|
||||
a = new AtomicFloat[label != null ? values.length : 1];
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
a[i] = new AtomicFloat();
|
||||
}
|
||||
s = supplier;
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
setValue(0, value);
|
||||
}
|
||||
|
||||
public void setValue(long value) {
|
||||
setValue(0, value);
|
||||
}
|
||||
|
||||
public void setValue(float value) {
|
||||
setValue(0, value);
|
||||
}
|
||||
|
||||
public void setValue(double value) {
|
||||
setValue(0, value);
|
||||
}
|
||||
|
||||
public float getValue() {
|
||||
return getValue(0);
|
||||
}
|
||||
|
||||
public double getDoubleValue() {
|
||||
return getDoubleValue(0);
|
||||
}
|
||||
|
||||
public void setValue(int idx, int value) {
|
||||
a[idx].set(value);
|
||||
}
|
||||
|
||||
public void setValue(int idx, long value) {
|
||||
a[idx].set((float) value);
|
||||
}
|
||||
|
||||
public void setValue(int idx, float value) {
|
||||
a[idx].set(value);
|
||||
}
|
||||
|
||||
public void setValue(int idx, double value) {
|
||||
a[idx].set((float) value);
|
||||
}
|
||||
|
||||
public float getValue(int idx) {
|
||||
return a[idx].get();
|
||||
}
|
||||
|
||||
public double getDoubleValue(int idx) {
|
||||
return a[idx].get();
|
||||
}
|
||||
|
||||
/**
|
||||
* For StatManager
|
||||
*/
|
||||
@Override
|
||||
public void coalesceStats() {
|
||||
if (s != null)
|
||||
a[0].set(s.getAsFloat());
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplier interface
|
||||
*/
|
||||
public float getAsFloat() {
|
||||
return a[0].get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumer interface
|
||||
*
|
||||
* Adds the value
|
||||
*/
|
||||
public void accept(float value) {
|
||||
a[0].set(value);
|
||||
}
|
||||
}
|
10
core/java/src/net/i2p/stat/prometheus/FloatConsumer.java
Normal file
10
core/java/src/net/i2p/stat/prometheus/FloatConsumer.java
Normal file
@ -0,0 +1,10 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* Until we set a min SDK in Android that has java.util.function
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public interface FloatConsumer {
|
||||
public void accept(float value);
|
||||
}
|
10
core/java/src/net/i2p/stat/prometheus/FloatSupplier.java
Normal file
10
core/java/src/net/i2p/stat/prometheus/FloatSupplier.java
Normal file
@ -0,0 +1,10 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* Until we set a min SDK in Android that has java.util.function
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public interface FloatSupplier {
|
||||
public float getAsFloat();
|
||||
}
|
27
core/java/src/net/i2p/stat/prometheus/Gauge.java
Normal file
27
core/java/src/net/i2p/stat/prometheus/Gauge.java
Normal file
@ -0,0 +1,27 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* A simple Prometheus-style gauge
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public abstract class Gauge extends PromStat {
|
||||
|
||||
public Gauge(String name, String desc, String group, Unit unit) {
|
||||
super(name, desc, group, Type.GAUGE, unit);
|
||||
}
|
||||
|
||||
public Gauge(String name, String desc, String group, Unit unit, String label, String... values) {
|
||||
super(name, desc, group, Type.GAUGE, unit, label, values);
|
||||
}
|
||||
|
||||
public abstract void setValue(int value);
|
||||
public abstract void setValue(long value);
|
||||
public abstract void setValue(float value);
|
||||
public abstract void setValue(double value);
|
||||
|
||||
public abstract void setValue(int labelIndex, int value);
|
||||
public abstract void setValue(int labelIndex, long value);
|
||||
public abstract void setValue(int labelIndex, float value);
|
||||
public abstract void setValue(int labelIndex, double value);
|
||||
}
|
122
core/java/src/net/i2p/stat/prometheus/ICounter.java
Normal file
122
core/java/src/net/i2p/stat/prometheus/ICounter.java
Normal file
@ -0,0 +1,122 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicIntegerArray;
|
||||
|
||||
/**
|
||||
* A simple Prometheus-style counter, with overflow protection.
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public class ICounter extends Counter implements IntConsumer, IntSupplier {
|
||||
|
||||
private final AtomicIntegerArray a;
|
||||
private final AtomicInteger c;
|
||||
|
||||
public ICounter(String name, String desc, String group, Unit unit) {
|
||||
this(name, desc, group, unit, null);
|
||||
}
|
||||
|
||||
public ICounter(String name, String desc, String group, Unit unit, String label, String... values) {
|
||||
super(name, desc, group, unit, label, values);
|
||||
if (label != null) {
|
||||
a = new AtomicIntegerArray(values.length);
|
||||
c = null;
|
||||
} else {
|
||||
a = null;
|
||||
c = new AtomicInteger();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets to 0 on overflow.
|
||||
*/
|
||||
public void increment() {
|
||||
int v = c.incrementAndGet();
|
||||
if (v < 0)
|
||||
c.set(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets to 0 on overflow.
|
||||
*/
|
||||
public void add(int value) {
|
||||
throwIfNegative(value);
|
||||
int v = c.addAndGet(value);
|
||||
if (v < 0)
|
||||
c.set(0);
|
||||
}
|
||||
|
||||
public void add(long value) {
|
||||
add((int) value);
|
||||
}
|
||||
|
||||
public void add(float value) {
|
||||
add((int) value);
|
||||
}
|
||||
|
||||
public void add(double value) {
|
||||
add((int) value);
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
public double getDoubleValue() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets to 0 on overflow.
|
||||
*/
|
||||
public void increment(int idx) {
|
||||
int v = a.incrementAndGet(idx);
|
||||
if (v < 0)
|
||||
a.set(idx, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets to 0 on overflow.
|
||||
*/
|
||||
public void add(int idx, int value) {
|
||||
throwIfNegative(value);
|
||||
int v = a.addAndGet(idx, value);
|
||||
if (v < 0)
|
||||
a.set(idx, 0);
|
||||
}
|
||||
|
||||
public void add(int idx, long value) {
|
||||
add(idx, (int) value);
|
||||
}
|
||||
|
||||
public void add(int idx, float value) {
|
||||
add(idx, (int) value);
|
||||
}
|
||||
|
||||
public void add(int idx, double value) {
|
||||
add(idx, (int) value);
|
||||
}
|
||||
|
||||
public int getValue(int idx) {
|
||||
return a.get(idx);
|
||||
}
|
||||
|
||||
public double getDoubleValue(int idx) {
|
||||
return a.get(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplier interface
|
||||
*/
|
||||
public int getAsInt() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumer interface
|
||||
*/
|
||||
public void accept(int value) {
|
||||
c.addAndGet(value);
|
||||
}
|
||||
}
|
110
core/java/src/net/i2p/stat/prometheus/IGauge.java
Normal file
110
core/java/src/net/i2p/stat/prometheus/IGauge.java
Normal file
@ -0,0 +1,110 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicIntegerArray;
|
||||
|
||||
/**
|
||||
* A simple Prometheus-style gauge
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public class IGauge extends Gauge implements IntConsumer, IntSupplier {
|
||||
|
||||
private final AtomicIntegerArray a;
|
||||
private final AtomicInteger c;
|
||||
private final IntSupplier s;
|
||||
|
||||
public IGauge(String name, String desc, String group, Unit unit) {
|
||||
this(name, desc, group, unit, null);
|
||||
}
|
||||
|
||||
public IGauge(String name, String desc, String group, Unit unit, IntSupplier supplier) {
|
||||
this(name, desc, group, unit, supplier, null);
|
||||
}
|
||||
|
||||
public IGauge(String name, String desc, String group, Unit unit, IntSupplier supplier, String label, String... values) {
|
||||
super(name, desc, group, unit, label, values);
|
||||
if (label != null) {
|
||||
a = new AtomicIntegerArray(values.length);
|
||||
c = null;
|
||||
} else {
|
||||
a = null;
|
||||
c = new AtomicInteger();
|
||||
}
|
||||
s = supplier;
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
c.set(value);
|
||||
}
|
||||
|
||||
public void setValue(long value) {
|
||||
c.set((int) value);
|
||||
}
|
||||
|
||||
public void setValue(float value) {
|
||||
c.set((int) value);
|
||||
}
|
||||
|
||||
public void setValue(double value) {
|
||||
c.set((int) value);
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
public double getDoubleValue() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
public void setValue(int idx, int value) {
|
||||
a.set(idx, value);
|
||||
}
|
||||
|
||||
public void setValue(int idx, long value) {
|
||||
a.set(idx, (int) value);
|
||||
}
|
||||
|
||||
public void setValue(int idx, float value) {
|
||||
a.set(idx, (int) value);
|
||||
}
|
||||
|
||||
public void setValue(int idx, double value) {
|
||||
a.set(idx, (int) value);
|
||||
}
|
||||
|
||||
public long getValue(int idx) {
|
||||
return a.get(idx);
|
||||
}
|
||||
|
||||
public double getDoubleValue(int idx) {
|
||||
return a.get(idx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For StatManager
|
||||
*/
|
||||
@Override
|
||||
public void coalesceStats() {
|
||||
if (s != null)
|
||||
c.set(s.getAsInt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplier interface
|
||||
*/
|
||||
public int getAsInt() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumer interface
|
||||
*
|
||||
* Adds the value
|
||||
*/
|
||||
public void accept(int value) {
|
||||
c.set(value);
|
||||
}
|
||||
}
|
76
core/java/src/net/i2p/stat/prometheus/Info.java
Normal file
76
core/java/src/net/i2p/stat/prometheus/Info.java
Normal file
@ -0,0 +1,76 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* A simple Prometheus-style info. Value is always 1.
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public class Info extends PromStat implements IntSupplier, MapSupplier, MapConsumer {
|
||||
|
||||
private final Map<String, String> labels;
|
||||
|
||||
/**
|
||||
* Map returned by getValues() will be a ConcurrentHashMap
|
||||
*/
|
||||
public Info(String name, String desc, String group) {
|
||||
this(name, desc, group, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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, String group, Map<String, String> labels) {
|
||||
super(name, desc, group, Type.GAUGE, Unit.NONE);
|
||||
this.labels = (labels != null) ? labels : new ConcurrentHashMap<String, String>(4);
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public double getDoubleValue() {
|
||||
return 1.0d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return not a copy
|
||||
*/
|
||||
public Map<String, String> getLabels() {
|
||||
return labels;
|
||||
}
|
||||
|
||||
public void setLabel(String labelName, String labelValue) {
|
||||
labels.put(labelName, labelValue);
|
||||
}
|
||||
|
||||
public void removeLabel(String labelName) {
|
||||
labels.remove(labelName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplier interface
|
||||
*/
|
||||
public int getAsInt() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplier interface
|
||||
*/
|
||||
public Map<String, String> getAsMap() {
|
||||
return labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumer interface
|
||||
*/
|
||||
public void accept(Map<String, String> labels) {
|
||||
this.labels.putAll(labels);
|
||||
}
|
||||
}
|
10
core/java/src/net/i2p/stat/prometheus/IntConsumer.java
Normal file
10
core/java/src/net/i2p/stat/prometheus/IntConsumer.java
Normal file
@ -0,0 +1,10 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* Until we set a min SDK in Android that has java.util.function
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public interface IntConsumer {
|
||||
public void accept(int value);
|
||||
}
|
10
core/java/src/net/i2p/stat/prometheus/IntSupplier.java
Normal file
10
core/java/src/net/i2p/stat/prometheus/IntSupplier.java
Normal file
@ -0,0 +1,10 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* Until we set a min SDK in Android that has java.util.function
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public interface IntSupplier {
|
||||
public int getAsInt();
|
||||
}
|
109
core/java/src/net/i2p/stat/prometheus/LCounter.java
Normal file
109
core/java/src/net/i2p/stat/prometheus/LCounter.java
Normal file
@ -0,0 +1,109 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicLongArray;
|
||||
|
||||
/**
|
||||
* A simple Prometheus-style counter.
|
||||
* No overflow protection, shouldn't happen.
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public class LCounter extends Counter implements LongConsumer, LongSupplier {
|
||||
|
||||
private final AtomicLongArray a;
|
||||
private final AtomicLong c;
|
||||
|
||||
public LCounter(String name, String desc, String group, Unit unit) {
|
||||
this(name, desc, group, unit, null);
|
||||
}
|
||||
|
||||
public LCounter(String name, String desc, String group, Unit unit, String label, String... values) {
|
||||
super(name, desc, group, unit, label, values);
|
||||
if (label != null) {
|
||||
a = new AtomicLongArray(values.length);
|
||||
c = null;
|
||||
} else {
|
||||
a = null;
|
||||
c = new AtomicLong();
|
||||
}
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
c.incrementAndGet();
|
||||
}
|
||||
|
||||
public void add(int value) {
|
||||
throwIfNegative(value);
|
||||
c.addAndGet(value);
|
||||
}
|
||||
|
||||
public void add(long value) {
|
||||
throwIfNegative(value);
|
||||
c.addAndGet(value);
|
||||
}
|
||||
|
||||
public void add(float value) {
|
||||
throwIfNegative(value);
|
||||
c.addAndGet((long) value);
|
||||
}
|
||||
|
||||
public void add(double value) {
|
||||
throwIfNegative(value);
|
||||
c.addAndGet((long) value);
|
||||
}
|
||||
|
||||
public long getValue() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
public double getDoubleValue() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
public void increment(int idx) {
|
||||
a.incrementAndGet(idx);
|
||||
}
|
||||
|
||||
public void add(int idx, int value) {
|
||||
throwIfNegative(value);
|
||||
a.addAndGet(idx, value);
|
||||
}
|
||||
|
||||
public void add(int idx, long value) {
|
||||
throwIfNegative(value);
|
||||
a.addAndGet(idx, value);
|
||||
}
|
||||
|
||||
public void add(int idx, float value) {
|
||||
throwIfNegative(value);
|
||||
a.addAndGet(idx, (long) value);
|
||||
}
|
||||
|
||||
public void add(int idx, double value) {
|
||||
throwIfNegative(value);
|
||||
a.addAndGet(idx, (long) value);
|
||||
}
|
||||
|
||||
public long getValue(int idx) {
|
||||
return a.get(idx);
|
||||
}
|
||||
|
||||
public double getDoubleValue(int idx) {
|
||||
return a.get(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplier interface
|
||||
*/
|
||||
public long getAsLong() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumer interface
|
||||
*/
|
||||
public void accept(long value) {
|
||||
c.addAndGet(value);
|
||||
}
|
||||
}
|
109
core/java/src/net/i2p/stat/prometheus/LGauge.java
Normal file
109
core/java/src/net/i2p/stat/prometheus/LGauge.java
Normal file
@ -0,0 +1,109 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicLongArray;
|
||||
|
||||
/**
|
||||
* A simple Prometheus-style gauge
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public class LGauge extends Gauge implements LongConsumer, LongSupplier {
|
||||
|
||||
private final AtomicLongArray a;
|
||||
private final AtomicLong c;
|
||||
private final LongSupplier s;
|
||||
|
||||
public LGauge(String name, String desc, String group, Unit unit) {
|
||||
this(name, desc, group, unit, null);
|
||||
}
|
||||
|
||||
public LGauge(String name, String desc, String group, Unit unit, LongSupplier supplier) {
|
||||
this(name, desc, group, unit, supplier, null);
|
||||
}
|
||||
|
||||
public LGauge(String name, String desc, String group, Unit unit, LongSupplier supplier, String label, String... values) {
|
||||
super(name, desc, group, unit, label, values);
|
||||
if (label != null) {
|
||||
a = new AtomicLongArray(values.length);
|
||||
c = null;
|
||||
} else {
|
||||
a = null;
|
||||
c = new AtomicLong();
|
||||
}
|
||||
s = supplier;
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
c.set(value);
|
||||
}
|
||||
|
||||
public void setValue(long value) {
|
||||
c.set(value);
|
||||
}
|
||||
|
||||
public void setValue(float value) {
|
||||
c.set((long) value);
|
||||
}
|
||||
|
||||
public void setValue(double value) {
|
||||
c.set((long) value);
|
||||
}
|
||||
|
||||
public long getValue() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
public double getDoubleValue() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
public void setValue(int idx, int value) {
|
||||
a.set(idx, value);
|
||||
}
|
||||
|
||||
public void setValue(int idx, long value) {
|
||||
a.set(idx, value);
|
||||
}
|
||||
|
||||
public void setValue(int idx, float value) {
|
||||
a.set(idx, (long) value);
|
||||
}
|
||||
|
||||
public void setValue(int idx, double value) {
|
||||
a.set(idx, (long) value);
|
||||
}
|
||||
|
||||
public long getValue(int idx) {
|
||||
return a.get(idx);
|
||||
}
|
||||
|
||||
public double getDoubleValue(int idx) {
|
||||
return a.get(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* For StatManager
|
||||
*/
|
||||
@Override
|
||||
public void coalesceStats() {
|
||||
if (s != null)
|
||||
c.set(s.getAsLong());
|
||||
}
|
||||
|
||||
/**
|
||||
* Supplier interface
|
||||
*/
|
||||
public long getAsLong() {
|
||||
return c.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumer interface
|
||||
*
|
||||
* Adds the value
|
||||
*/
|
||||
public void accept(long value) {
|
||||
c.set(value);
|
||||
}
|
||||
}
|
10
core/java/src/net/i2p/stat/prometheus/LongConsumer.java
Normal file
10
core/java/src/net/i2p/stat/prometheus/LongConsumer.java
Normal file
@ -0,0 +1,10 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* Until we set a min SDK in Android that has java.util.function
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public interface LongConsumer {
|
||||
public void accept(long value);
|
||||
}
|
10
core/java/src/net/i2p/stat/prometheus/LongSupplier.java
Normal file
10
core/java/src/net/i2p/stat/prometheus/LongSupplier.java
Normal file
@ -0,0 +1,10 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* Until we set a min SDK in Android that has java.util.function
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public interface LongSupplier {
|
||||
public long getAsLong();
|
||||
}
|
12
core/java/src/net/i2p/stat/prometheus/MapConsumer.java
Normal file
12
core/java/src/net/i2p/stat/prometheus/MapConsumer.java
Normal file
@ -0,0 +1,12 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Until we set a min SDK in Android that has java.util.function
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public interface MapConsumer {
|
||||
public void accept(Map<String, String> values);
|
||||
}
|
12
core/java/src/net/i2p/stat/prometheus/MapSupplier.java
Normal file
12
core/java/src/net/i2p/stat/prometheus/MapSupplier.java
Normal file
@ -0,0 +1,12 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Until we set a min SDK in Android that has java.util.function
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public interface MapSupplier {
|
||||
public Map<String, String> getAsMap();
|
||||
}
|
190
core/java/src/net/i2p/stat/prometheus/PromStat.java
Normal file
190
core/java/src/net/i2p/stat/prometheus/PromStat.java
Normal file
@ -0,0 +1,190 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* A simple Prometheus-style metric.
|
||||
*
|
||||
* Units are stored in the units specified,
|
||||
* and scaled in getScaledValue().
|
||||
*
|
||||
* These stats are not persisted by StatManager.
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public abstract class PromStat {
|
||||
|
||||
private final String desc;
|
||||
private final String name;
|
||||
private final String promName;
|
||||
private final String groupName;
|
||||
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()
|
||||
* @param group use same group names as RateStat and FrequencyStat
|
||||
*/
|
||||
public PromStat(String name, String description, String group, Type type, Unit unit) {
|
||||
this(name, description, group, 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 group use same group names as RateStat and FrequencyStat
|
||||
* @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, String group, Type type, Unit unit, String label, String... values) {
|
||||
this.name = name;
|
||||
desc = description;
|
||||
groupName = group;
|
||||
this.type = type;
|
||||
this.unit = unit;
|
||||
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() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPromName() {
|
||||
return promName;
|
||||
}
|
||||
|
||||
/*
|
||||
* @return same group names as RateStat and FrequencyStat
|
||||
*/
|
||||
public String getGroupName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
public Type getType() { return type; }
|
||||
|
||||
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.
|
||||
*/
|
||||
public double getScaledValue() {
|
||||
double rv = getDoubleValue();
|
||||
switch (unit) {
|
||||
case KBYTES:
|
||||
case KBPS:
|
||||
rv *= 1000f;
|
||||
break;
|
||||
|
||||
case MS:
|
||||
rv /= 1000f;
|
||||
break;
|
||||
}
|
||||
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:
|
||||
case KBPS:
|
||||
rv *= 1000f;
|
||||
break;
|
||||
|
||||
case MS:
|
||||
rv /= 1000f;
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* For StatManager.
|
||||
* Does nothing (for counters), extend for guages if necessary.
|
||||
*/
|
||||
public void coalesceStats() {}
|
||||
}
|
21
core/java/src/net/i2p/stat/prometheus/Type.java
Normal file
21
core/java/src/net/i2p/stat/prometheus/Type.java
Normal file
@ -0,0 +1,21 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* Prometheus-style types
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
COUNTER("counter"),
|
||||
GAUGE("gauge"),
|
||||
INFO("info");
|
||||
|
||||
private final String name;
|
||||
|
||||
Type(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
}
|
26
core/java/src/net/i2p/stat/prometheus/Unit.java
Normal file
26
core/java/src/net/i2p/stat/prometheus/Unit.java
Normal file
@ -0,0 +1,26 @@
|
||||
package net.i2p.stat.prometheus;
|
||||
|
||||
/**
|
||||
* Prometheus-style units
|
||||
*
|
||||
* @since 0.9.67
|
||||
*/
|
||||
public enum Unit {
|
||||
|
||||
BYTES("bytes"),
|
||||
KBYTES("bytes"),
|
||||
BPS("bytes"),
|
||||
KBPS("bytes"),
|
||||
SECONDS("seconds"),
|
||||
MS("seconds"),
|
||||
EVENTS("count"),
|
||||
NONE("");
|
||||
|
||||
private final String name;
|
||||
|
||||
Unit(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
}
|
Reference in New Issue
Block a user