mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Add increment() to PrefixMetricWriter
In the redis repository we also switch to store the value in the zset (so it can be atomically incremented) rather than in the regular key-value. Fixes gh-929
This commit is contained in:
parent
14899ba3b2
commit
0cbd0b609a
@ -85,7 +85,7 @@ public class PrefixMetricGroupExporter extends AbstractMetricExporter {
|
||||
|
||||
@Override
|
||||
protected void write(String group, Collection<Metric<?>> values) {
|
||||
this.writer.save(group, values);
|
||||
this.writer.set(group, values);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import org.springframework.boot.actuate.metrics.repository.MultiMetricRepository
|
||||
import org.springframework.boot.actuate.metrics.rich.RichGauge;
|
||||
import org.springframework.boot.actuate.metrics.rich.RichGaugeReader;
|
||||
import org.springframework.boot.actuate.metrics.writer.MetricWriter;
|
||||
import org.springframework.boot.actuate.metrics.writer.PrefixMetricWriter;
|
||||
|
||||
/**
|
||||
* Exporter or converter for {@link RichGauge} data to a metric-based back end. Each gauge
|
||||
@ -53,13 +54,14 @@ public class RichGaugeExporter extends AbstractMetricExporter {
|
||||
private static final String ALPHA = ".alpha";
|
||||
|
||||
private final RichGaugeReader reader;
|
||||
private final MetricWriter writer;
|
||||
private final PrefixMetricWriter writer;
|
||||
|
||||
public RichGaugeExporter(RichGaugeReader reader, MetricWriter writer) {
|
||||
public RichGaugeExporter(RichGaugeReader reader, PrefixMetricWriter writer) {
|
||||
this(reader, writer, "");
|
||||
}
|
||||
|
||||
public RichGaugeExporter(RichGaugeReader reader, MetricWriter writer, String prefix) {
|
||||
public RichGaugeExporter(RichGaugeReader reader, PrefixMetricWriter writer,
|
||||
String prefix) {
|
||||
super(prefix);
|
||||
this.reader = reader;
|
||||
this.writer = writer;
|
||||
@ -89,14 +91,7 @@ public class RichGaugeExporter extends AbstractMetricExporter {
|
||||
|
||||
@Override
|
||||
protected void write(String group, Collection<Metric<?>> values) {
|
||||
if (this.writer instanceof MultiMetricRepository) {
|
||||
((MultiMetricRepository) this.writer).save(group, values);
|
||||
}
|
||||
else {
|
||||
for (Metric<?> value : values) {
|
||||
this.writer.set(value);
|
||||
}
|
||||
}
|
||||
this.writer.set(group, values);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ public class InMemoryMetricRepository implements MetricRepository, MultiMetricRe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(String group, Collection<Metric<?>> values) {
|
||||
public void set(String group, Collection<Metric<?>> values) {
|
||||
String prefix = group;
|
||||
if (!prefix.endsWith(".")) {
|
||||
prefix = prefix + ".";
|
||||
@ -86,6 +86,20 @@ public class InMemoryMetricRepository implements MetricRepository, MultiMetricRe
|
||||
this.groups.add(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increment(String group, Delta<?> delta) {
|
||||
String prefix = group;
|
||||
if (!prefix.endsWith(".")) {
|
||||
prefix = prefix + ".";
|
||||
}
|
||||
if (!delta.getName().startsWith(prefix)) {
|
||||
delta = new Delta<Number>(prefix + delta.getName(), delta.getValue(),
|
||||
delta.getTimestamp());
|
||||
}
|
||||
increment(delta);
|
||||
this.groups.add(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> groups() {
|
||||
return Collections.unmodifiableCollection(this.groups);
|
||||
|
@ -25,6 +25,7 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
import org.springframework.boot.actuate.metrics.repository.MultiMetricRepository;
|
||||
import org.springframework.boot.actuate.metrics.writer.Delta;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.BoundZSetOperations;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
@ -67,10 +68,10 @@ public class RedisMultiMetricRepository implements MultiMetricRepository {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Metric<?>> findAll(String metricNamePrefix) {
|
||||
public Iterable<Metric<?>> findAll(String group) {
|
||||
|
||||
BoundZSetOperations<String, String> zSetOperations = this.redisOperations
|
||||
.boundZSetOps(keyFor(metricNamePrefix));
|
||||
.boundZSetOps(keyFor(group));
|
||||
|
||||
Set<String> keys = zSetOperations.range(0, -1);
|
||||
Iterator<String> keysIt = keys.iterator();
|
||||
@ -78,14 +79,15 @@ public class RedisMultiMetricRepository implements MultiMetricRepository {
|
||||
List<Metric<?>> result = new ArrayList<Metric<?>>(keys.size());
|
||||
List<String> values = this.redisOperations.opsForValue().multiGet(keys);
|
||||
for (String v : values) {
|
||||
result.add(deserialize(keysIt.next(), v));
|
||||
String key = keysIt.next();
|
||||
result.add(deserialize(group, key, v, zSetOperations.score(key)));
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(String group, Collection<Metric<?>> values) {
|
||||
public void set(String group, Collection<Metric<?>> values) {
|
||||
String groupKey = keyFor(group);
|
||||
trackMembership(groupKey);
|
||||
BoundZSetOperations<String, String> zSetOperations = this.redisOperations
|
||||
@ -93,11 +95,24 @@ public class RedisMultiMetricRepository implements MultiMetricRepository {
|
||||
for (Metric<?> metric : values) {
|
||||
String raw = serialize(metric);
|
||||
String key = keyFor(metric.getName());
|
||||
zSetOperations.add(key, 0.0D);
|
||||
zSetOperations.add(key, metric.getValue().doubleValue());
|
||||
this.redisOperations.opsForValue().set(key, raw);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increment(String group, Delta<?> delta) {
|
||||
String groupKey = keyFor(group);
|
||||
trackMembership(groupKey);
|
||||
BoundZSetOperations<String, String> zSetOperations = this.redisOperations
|
||||
.boundZSetOps(groupKey);
|
||||
String key = keyFor(delta.getName());
|
||||
double value = zSetOperations.incrementScore(key, delta.getValue().doubleValue());
|
||||
String raw = serialize(new Metric<Double>(delta.getName(), value,
|
||||
delta.getTimestamp()));
|
||||
this.redisOperations.opsForValue().set(key, raw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> groups() {
|
||||
Set<String> range = this.zSetOperations.range(0, -1);
|
||||
@ -128,15 +143,17 @@ public class RedisMultiMetricRepository implements MultiMetricRepository {
|
||||
this.zSetOperations.remove(groupKey);
|
||||
}
|
||||
|
||||
private Metric<?> deserialize(String redisKey, String v) {
|
||||
String[] vals = v.split("@");
|
||||
Double value = Double.valueOf(vals[0]);
|
||||
Date timestamp = vals.length > 1 ? new Date(Long.valueOf(vals[1])) : new Date();
|
||||
return new Metric<Double>(nameFor(redisKey), value, timestamp);
|
||||
private Metric<?> deserialize(String group, String redisKey, String v, Double value) {
|
||||
String prefix = group;
|
||||
if (!group.endsWith(".")) {
|
||||
prefix = group + ".";
|
||||
}
|
||||
Date timestamp = new Date(Long.valueOf(v));
|
||||
return new Metric<Double>(prefix + nameFor(redisKey), value, timestamp);
|
||||
}
|
||||
|
||||
private String serialize(Metric<?> entity) {
|
||||
return String.valueOf(entity.getValue() + "@" + entity.getTimestamp().getTime());
|
||||
return String.valueOf(entity.getTimestamp().getTime());
|
||||
}
|
||||
|
||||
private String keyFor(String name) {
|
||||
|
@ -33,7 +33,14 @@ public interface PrefixMetricWriter {
|
||||
* @param group the name of the group
|
||||
* @param values the metric values to save
|
||||
*/
|
||||
void save(String group, Collection<Metric<?>> values);
|
||||
void set(String group, Collection<Metric<?>> values);
|
||||
|
||||
/**
|
||||
* Increment the value of a metric (or decrement if the delta is negative). The name
|
||||
* of the metric to increment is <code>group + "." + delta.name</code>.
|
||||
* @param delta the amount to increment by
|
||||
*/
|
||||
void increment(String group, Delta<?> delta);
|
||||
|
||||
/**
|
||||
* Rest the values of all metrics in the group. Implementations may choose to discard
|
||||
|
@ -60,7 +60,7 @@ public class PrefixMetricGroupExporterTests {
|
||||
|
||||
@Test
|
||||
public void multiMetricGroupsCopiedAsDefault() {
|
||||
this.reader.save("foo", Arrays.<Metric<?>> asList(new Metric<Number>("bar", 2.3),
|
||||
this.reader.set("foo", Arrays.<Metric<?>> asList(new Metric<Number>("bar", 2.3),
|
||||
new Metric<Number>("spam", 1.3)));
|
||||
this.exporter.export();
|
||||
assertEquals(1, this.writer.countGroups());
|
||||
|
@ -47,7 +47,7 @@ public class InMemoryPrefixMetricRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void perfixWithWildcard() {
|
||||
public void prefixWithWildcard() {
|
||||
this.repository.increment(new Delta<Number>("foo.bar", 1));
|
||||
Set<String> names = new HashSet<String>();
|
||||
for (Metric<?> metric : this.repository.findAll("foo.*")) {
|
||||
@ -58,7 +58,7 @@ public class InMemoryPrefixMetricRepositoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void perfixWithPeriod() {
|
||||
public void prefixWithPeriod() {
|
||||
this.repository.increment(new Delta<Number>("foo.bar", 1));
|
||||
Set<String> names = new HashSet<String>();
|
||||
for (Metric<?> metric : this.repository.findAll("foo.")) {
|
||||
@ -80,4 +80,18 @@ public class InMemoryPrefixMetricRepositoryTests {
|
||||
assertTrue(names.contains("foo.bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementGroup() {
|
||||
this.repository.increment("foo", new Delta<Number>("bar", 1));
|
||||
this.repository.increment("foo", new Delta<Number>("bar", 2));
|
||||
this.repository.increment("foo", new Delta<Number>("spam", 1));
|
||||
Set<String> names = new HashSet<String>();
|
||||
for (Metric<?> metric : this.repository.findAll("foo")) {
|
||||
names.add(metric.getName());
|
||||
}
|
||||
assertEquals(2, names.size());
|
||||
assertTrue(names.contains("foo.bar"));
|
||||
assertEquals(3L, this.repository.findOne("foo.bar").getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,7 +17,9 @@
|
||||
package org.springframework.boot.actuate.metrics.repository.redis;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@ -29,6 +31,7 @@ import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.springframework.boot.actuate.metrics.Iterables;
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
import org.springframework.boot.actuate.metrics.writer.Delta;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@ -78,27 +81,44 @@ public class RedisMultiMetricRepositoryTests {
|
||||
|
||||
@Test
|
||||
public void setAndGet() {
|
||||
this.repository.save("foo", Arrays.<Metric<?>> asList(new Metric<Number>(
|
||||
this.repository.set("foo", Arrays.<Metric<?>> asList(new Metric<Number>(
|
||||
"foo.val", 12.3), new Metric<Number>("foo.bar", 11.3)));
|
||||
assertEquals(2, Iterables.collection(this.repository.findAll("foo")).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groups() {
|
||||
this.repository.save("foo", Arrays.<Metric<?>> asList(new Metric<Number>(
|
||||
this.repository.set("foo", Arrays.<Metric<?>> asList(new Metric<Number>(
|
||||
"foo.val", 12.3), new Metric<Number>("foo.bar", 11.3)));
|
||||
this.repository.save("bar", Arrays.<Metric<?>> asList(new Metric<Number>(
|
||||
this.repository.set("bar", Arrays.<Metric<?>> asList(new Metric<Number>(
|
||||
"bar.val", 12.3), new Metric<Number>("bar.foo", 11.3)));
|
||||
assertEquals(2, Iterables.collection(this.repository.groups()).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void count() {
|
||||
this.repository.save("foo", Arrays.<Metric<?>> asList(new Metric<Number>(
|
||||
this.repository.set("foo", Arrays.<Metric<?>> asList(new Metric<Number>(
|
||||
"foo.val", 12.3), new Metric<Number>("foo.bar", 11.3)));
|
||||
this.repository.save("bar", Arrays.<Metric<?>> asList(new Metric<Number>(
|
||||
this.repository.set("bar", Arrays.<Metric<?>> asList(new Metric<Number>(
|
||||
"bar.val", 12.3), new Metric<Number>("bar.foo", 11.3)));
|
||||
assertEquals(2, this.repository.countGroups());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void increment() {
|
||||
this.repository.increment("foo", new Delta<Number>("bar", 1));
|
||||
this.repository.increment("foo", new Delta<Number>("bar", 2));
|
||||
this.repository.increment("foo", new Delta<Number>("spam", 1));
|
||||
Metric<?> bar = null;
|
||||
Set<String> names = new HashSet<String>();
|
||||
for (Metric<?> metric : this.repository.findAll("foo")) {
|
||||
names.add(metric.getName());
|
||||
if (metric.getName().equals("foo.bar")) {
|
||||
bar = metric;
|
||||
}
|
||||
}
|
||||
assertEquals(2, names.size());
|
||||
assertTrue("Wrong names: " + names, names.contains("foo.bar"));
|
||||
assertEquals(3d, bar.getValue());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user