diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/Buffer.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/Buffer.java new file mode 100644 index 0000000000..f0392753c0 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/Buffer.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.springframework.boot.actuate.metrics.buffer; + +/** + * Base class for a mutable buffer containing a timestamp and a value. + * + * @author Dave Syer + * @author Phillip Webb + * @param The value type + */ +abstract class Buffer { + + private volatile long timestamp; + + public Buffer(long timestamp) { + this.timestamp = timestamp; + } + + public long getTimestamp() { + return this.timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + /** + * Returns the buffer value. + * @return the value of the buffer + */ + public abstract T getValue(); + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferCounterService.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferCounterService.java index 0b11d0ac19..c68ca3d97a 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferCounterService.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferCounterService.java @@ -32,29 +32,29 @@ public class BufferCounterService implements CounterService { private final ConcurrentHashMap names = new ConcurrentHashMap(); - private final CounterBuffers writer; + private final CounterBuffers buffers; /** * Create a {@link BufferCounterService} instance. - * @param writer the underlying writer used to manage metrics + * @param buffers the underlying buffers used to store metrics */ - public BufferCounterService(CounterBuffers writer) { - this.writer = writer; + public BufferCounterService(CounterBuffers buffers) { + this.buffers = buffers; } @Override public void increment(String metricName) { - this.writer.increment(wrap(metricName), 1L); + this.buffers.increment(wrap(metricName), 1L); } @Override public void decrement(String metricName) { - this.writer.increment(wrap(metricName), -1L); + this.buffers.increment(wrap(metricName), -1L); } @Override public void reset(String metricName) { - this.writer.reset(wrap(metricName)); + this.buffers.reset(wrap(metricName)); } private String wrap(String metricName) { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferGaugeService.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferGaugeService.java index 91a5d82883..f96afa3695 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferGaugeService.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferGaugeService.java @@ -32,19 +32,19 @@ public class BufferGaugeService implements GaugeService { private final ConcurrentHashMap names = new ConcurrentHashMap(); - private final GaugeBuffers writer; + private final GaugeBuffers buffers; /** * Create a {@link BufferGaugeService} instance. - * @param writer the underlying writer used to manage metrics + * @param buffers the underlying buffers used to store metrics */ - public BufferGaugeService(GaugeBuffers writer) { - this.writer = writer; + public BufferGaugeService(GaugeBuffers buffers) { + this.buffers = buffers; } @Override public void submit(String metricName, double value) { - this.writer.set(wrap(metricName), value); + this.buffers.set(wrap(metricName), value); } private String wrap(String metricName) { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferMetricReader.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferMetricReader.java index 79f247bcbf..443cc24fbf 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferMetricReader.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/BufferMetricReader.java @@ -38,35 +38,29 @@ import org.springframework.lang.UsesJava8; @UsesJava8 public class BufferMetricReader implements MetricReader, PrefixMetricReader { - private final CounterBuffers counters; + private static final Predicate ALL = Pattern.compile(".*").asPredicate(); - private final GaugeBuffers gauges; + private final CounterBuffers counterBuffers; - private final Predicate all = Pattern.compile(".*").asPredicate(); + private final GaugeBuffers gaugeBuffers; - public BufferMetricReader(CounterBuffers counters, GaugeBuffers gauges) { - this.counters = counters; - this.gauges = gauges; + public BufferMetricReader(CounterBuffers counterBuffers, GaugeBuffers gaugeBuffers) { + this.counterBuffers = counterBuffers; + this.gaugeBuffers = gaugeBuffers; } @Override public Metric findOne(final String name) { - LongBuffer buffer = this.counters.find(name); - if (buffer != null) { - return new Metric(name, buffer.getValue(), new Date( - buffer.getTimestamp())); + Buffer buffer = this.counterBuffers.find(name); + if (buffer == null) { + buffer = this.gaugeBuffers.find(name); } - DoubleBuffer doubleValue = this.gauges.find(name); - if (doubleValue != null) { - return new Metric(name, doubleValue.getValue(), new Date( - doubleValue.getTimestamp())); - } - return null; + return (buffer == null ? null : asMetric(name, buffer)); } @Override public Iterable> findAll() { - return findAll(this.all); + return findAll(BufferMetricReader.ALL); } @Override @@ -76,30 +70,30 @@ public class BufferMetricReader implements MetricReader, PrefixMetricReader { @Override public long count() { - return this.counters.count() + this.gauges.count(); + return this.counterBuffers.count() + this.gaugeBuffers.count(); } private Iterable> findAll(Predicate predicate) { final List> metrics = new ArrayList>(); - this.counters.forEach(predicate, new BiConsumer() { - - @Override - public void accept(String name, LongBuffer value) { - metrics.add(new Metric(name, value.getValue(), new Date(value - .getTimestamp()))); - } - - }); - this.gauges.forEach(predicate, new BiConsumer() { - - @Override - public void accept(String name, DoubleBuffer value) { - metrics.add(new Metric(name, value.getValue(), new Date(value - .getTimestamp()))); - } - - }); + collectMetrics(this.gaugeBuffers, predicate, metrics); + collectMetrics(this.counterBuffers, predicate, metrics); return metrics; } + private > void collectMetrics( + Buffers buffers, Predicate predicate, final List> metrics) { + buffers.forEach(predicate, new BiConsumer() { + + @Override + public void accept(String name, B value) { + metrics.add(asMetric(name, value)); + } + + }); + } + + private Metric asMetric(final String name, Buffer buffer) { + return new Metric(name, buffer.getValue(), new Date(buffer.getTimestamp())); + } + } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/Buffers.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/Buffers.java new file mode 100644 index 0000000000..920af45fc9 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/Buffers.java @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.springframework.boot.actuate.metrics.buffer; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.springframework.lang.UsesJava8; + +/** + * Base class used to manage a map of {@link Buffer} objects. + * + * @author Dave Syer + * @author Phillip Webb + * @param The buffer type + */ +@UsesJava8 +abstract class Buffers> { + + private final ConcurrentHashMap buffers = new ConcurrentHashMap(); + + public void forEach(final Predicate predicate, + final BiConsumer consumer) { + this.buffers.forEach(new BiConsumer() { + + @Override + public void accept(String name, B value) { + if (predicate.test(name)) { + consumer.accept(name, value); + } + } + + }); + } + + public B find(final String name) { + return this.buffers.get(name); + } + + public int count() { + return this.buffers.size(); + } + + protected final void doWith(final String name, final Consumer consumer) { + B buffer = this.buffers.get(name); + if (buffer == null) { + buffer = this.buffers.computeIfAbsent(name, new Function() { + @Override + public B apply(String name) { + return createBuffer(); + } + }); + } + consumer.accept(buffer); + } + + protected abstract B createBuffer(); + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/LongBuffer.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/CounterBuffer.java similarity index 79% rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/LongBuffer.java rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/CounterBuffer.java index 8d658a0554..8d036c6245 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/LongBuffer.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/CounterBuffer.java @@ -27,35 +27,26 @@ import org.springframework.lang.UsesJava8; * @since 1.3.0 */ @UsesJava8 -public class LongBuffer { +public class CounterBuffer extends Buffer { private final LongAdder adder; - private volatile long timestamp; - - public LongBuffer(long timestamp) { + public CounterBuffer(long timestamp) { + super(timestamp); this.adder = new LongAdder(); - this.timestamp = timestamp; - } - - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - - public long getValue() { - return this.adder.sum(); - } - - public long getTimestamp() { - return this.timestamp; - } - - public void reset() { - this.adder.reset(); } public void add(long delta) { this.adder.add(delta); } + public void reset() { + this.adder.reset(); + } + + @Override + public Long getValue() { + return this.adder.sum(); + } + } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/CounterBuffers.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/CounterBuffers.java index 1d0e3b5625..9a71a5c43d 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/CounterBuffers.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/CounterBuffers.java @@ -16,93 +16,46 @@ package org.springframework.boot.actuate.metrics.buffer; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; import org.springframework.lang.UsesJava8; /** - * Fast writes to in-memory metrics store using {@link LongBuffer}. + * Fast writes to in-memory metrics store using {@link CounterBuffer}. * * @author Dave Syer * @since 1.3.0 */ @UsesJava8 -public class CounterBuffers { - - private final ConcurrentHashMap metrics = new ConcurrentHashMap(); - - public void forEach(final Predicate predicate, - final BiConsumer consumer) { - this.metrics.forEach(new BiConsumer() { - @Override - public void accept(String name, LongBuffer value) { - if (predicate.test(name)) { - consumer.accept(name, value); - } - } - }); - } - - public LongBuffer find(final String name) { - return this.metrics.get(name); - } - - public void get(final String name, final Consumer consumer) { - read(name, consumer); - } +public class CounterBuffers extends Buffers { public void increment(final String name, final long delta) { - write(name, new Consumer() { + doWith(name, new Consumer() { + @Override - public void accept(LongBuffer adder) { - adder.add(delta); + public void accept(CounterBuffer buffer) { + buffer.setTimestamp(System.currentTimeMillis()); + buffer.add(delta); } + }); } public void reset(final String name) { - write(name, new Consumer() { + doWith(name, new Consumer() { + @Override - public void accept(LongBuffer adder) { - adder.reset(); - } - }); - } - - public int count() { - return this.metrics.size(); - } - - private void read(final String name, final Consumer consumer) { - acceptInternal(name, consumer); - } - - private void write(final String name, final Consumer consumer) { - acceptInternal(name, new Consumer() { - @Override - public void accept(LongBuffer buffer) { + public void accept(CounterBuffer buffer) { buffer.setTimestamp(System.currentTimeMillis()); - consumer.accept(buffer); + buffer.reset(); } + }); } - private void acceptInternal(final String name, final Consumer consumer) { - LongBuffer adder; - if (null == (adder = this.metrics.get(name))) { - adder = this.metrics.computeIfAbsent(name, - new Function() { - @Override - public LongBuffer apply(String name) { - return new LongBuffer(0L); - } - }); - } - consumer.accept(adder); + @Override + protected CounterBuffer createBuffer() { + return new CounterBuffer(0); } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/DoubleBuffer.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/GaugeBuffer.java similarity index 75% rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/DoubleBuffer.java rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/GaugeBuffer.java index 43389b85cf..fa5f6568bc 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/DoubleBuffer.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/GaugeBuffer.java @@ -22,22 +22,17 @@ package org.springframework.boot.actuate.metrics.buffer; * @author Dave Syer * @since 1.3.0 */ -public class DoubleBuffer { +public class GaugeBuffer extends Buffer { private volatile double value; - private volatile long timestamp; - - public DoubleBuffer(long timestamp) { + public GaugeBuffer(long timestamp) { + super(timestamp); this.value = 0; - this.timestamp = timestamp; } - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - - public double getValue() { + @Override + public Double getValue() { return this.value; } @@ -45,8 +40,4 @@ public class DoubleBuffer { this.value = value; } - public long getTimestamp() { - return this.timestamp; - } - } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/GaugeBuffers.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/GaugeBuffers.java index aa899c1a61..7720443ddf 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/GaugeBuffers.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/buffer/GaugeBuffers.java @@ -16,79 +16,32 @@ package org.springframework.boot.actuate.metrics.buffer; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; import org.springframework.lang.UsesJava8; /** - * Fast writes to in-memory metrics store using {@link DoubleBuffer}. + * Fast writes to in-memory metrics store using {@link GaugeBuffer}. * * @author Dave Syer * @since 1.3.0 */ @UsesJava8 -public class GaugeBuffers { - - private final ConcurrentHashMap metrics = new ConcurrentHashMap(); - - public void forEach(final Predicate predicate, - final BiConsumer consumer) { - this.metrics.forEach(new BiConsumer() { - @Override - public void accept(String name, DoubleBuffer value) { - if (predicate.test(name)) { - consumer.accept(name, value); - } - } - }); - } - - public DoubleBuffer find(final String name) { - return this.metrics.get(name); - } - - public void get(final String name, final Consumer consumer) { - acceptInternal(name, consumer); - } +public class GaugeBuffers extends Buffers { public void set(final String name, final double value) { - write(name, value); - } - - public int count() { - return this.metrics.size(); - } - - private void write(final String name, final double value) { - acceptInternal(name, new Consumer() { + doWith(name, new Consumer() { @Override - public void accept(DoubleBuffer buffer) { + public void accept(GaugeBuffer buffer) { buffer.setTimestamp(System.currentTimeMillis()); buffer.setValue(value); } }); } - public void reset(String name) { - this.metrics.remove(name, this.metrics.get(name)); - } - - private void acceptInternal(final String name, final Consumer consumer) { - DoubleBuffer value; - if (null == (value = this.metrics.get(name))) { - value = this.metrics.computeIfAbsent(name, - new Function() { - @Override - public DoubleBuffer apply(String tag) { - return new DoubleBuffer(0L); - } - }); - } - consumer.accept(value); + @Override + protected GaugeBuffer createBuffer() { + return new GaugeBuffer(0L); } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/BufferGaugeServiceSpeedTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/BufferGaugeServiceSpeedTests.java index eb680c30c7..f02123848f 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/BufferGaugeServiceSpeedTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/BufferGaugeServiceSpeedTests.java @@ -99,18 +99,18 @@ public class BufferGaugeServiceSpeedTests { watch.start("readRaw" + count); for (String name : names) { this.gauges.forEach(Pattern.compile(name).asPredicate(), - new BiConsumer() { + new BiConsumer() { @Override - public void accept(String name, DoubleBuffer value) { + public void accept(String name, GaugeBuffer value) { err.println(name + "=" + value); } }); } final DoubleAdder total = new DoubleAdder(); this.gauges.forEach(Pattern.compile(".*").asPredicate(), - new BiConsumer() { + new BiConsumer() { @Override - public void accept(String name, DoubleBuffer value) { + public void accept(String name, GaugeBuffer value) { total.add(value.getValue()); } }); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/CounterBuffersTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/CounterBuffersTests.java index e871fa9aca..afc65e445d 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/CounterBuffersTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/CounterBuffersTests.java @@ -37,9 +37,9 @@ public class CounterBuffersTests { @Test public void inAndOut() { this.buffers.increment("foo", 2); - this.buffers.get("foo", new Consumer() { + this.buffers.doWith("foo", new Consumer() { @Override - public void accept(LongBuffer buffer) { + public void accept(CounterBuffer buffer) { CounterBuffersTests.this.value = buffer.getValue(); } }); @@ -48,9 +48,9 @@ public class CounterBuffersTests { @Test public void getNonExistent() { - this.buffers.get("foo", new Consumer() { + this.buffers.doWith("foo", new Consumer() { @Override - public void accept(LongBuffer buffer) { + public void accept(CounterBuffer buffer) { CounterBuffersTests.this.value = buffer.getValue(); } }); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/CounterServiceSpeedTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/CounterServiceSpeedTests.java index 3bb4039d0d..4cebbb1629 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/CounterServiceSpeedTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/buffer/CounterServiceSpeedTests.java @@ -98,18 +98,18 @@ public class CounterServiceSpeedTests { watch.start("readRaw" + count); for (String name : names) { this.counters.forEach(Pattern.compile(name).asPredicate(), - new BiConsumer() { + new BiConsumer() { @Override - public void accept(String name, LongBuffer value) { + public void accept(String name, CounterBuffer value) { err.println(name + "=" + value); } }); } final LongAdder total = new LongAdder(); this.counters.forEach(Pattern.compile(".*").asPredicate(), - new BiConsumer() { + new BiConsumer() { @Override - public void accept(String name, LongBuffer value) { + public void accept(String name, CounterBuffer value) { total.add(value.getValue()); } });