Polish updated metrics code

This commit is contained in:
Phillip Webb 2015-06-04 00:44:19 -07:00
parent d2f11c465e
commit 31d6a0f17a
60 changed files with 615 additions and 443 deletions

View File

@ -30,6 +30,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
* others that might be installed by the user for other purposes). * others that might be installed by the user for other purposes).
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@Qualifier @Qualifier
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE,

View File

@ -30,6 +30,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
* the {@link ExportMetricReader} readers. * the {@link ExportMetricReader} readers.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@Qualifier @Qualifier
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE,

View File

@ -29,6 +29,7 @@ import org.springframework.boot.actuate.metrics.export.MetricExporters;
import org.springframework.boot.actuate.metrics.reader.CompositeMetricReader; import org.springframework.boot.actuate.metrics.reader.CompositeMetricReader;
import org.springframework.boot.actuate.metrics.reader.MetricReader; import org.springframework.boot.actuate.metrics.reader.MetricReader;
import org.springframework.boot.actuate.metrics.writer.MetricWriter; import org.springframework.boot.actuate.metrics.writer.MetricWriter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
@ -37,9 +38,13 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.util.CollectionUtils;
/** /**
* {@link EnableAutoConfiguration Auto-configuration} for metrics export.
*
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@Configuration @Configuration
@EnableScheduling @EnableScheduling
@ -47,22 +52,39 @@ import org.springframework.scheduling.config.ScheduledTaskRegistrar;
@EnableConfigurationProperties @EnableConfigurationProperties
public class MetricExportAutoConfiguration { public class MetricExportAutoConfiguration {
@Autowired(required = false)
@ExportMetricWriter
private Map<String, MetricWriter> writers = Collections.emptyMap();
@Autowired @Autowired
private MetricExportProperties metrics; private MetricExportProperties properties;
@Autowired(required = false)
private MetricsEndpointMetricReader endpointReader;
@Autowired(required = false) @Autowired(required = false)
@ExportMetricReader @ExportMetricReader
private List<MetricReader> readers; private List<MetricReader> readers;
@Autowired(required = false) @Autowired(required = false)
private MetricsEndpointMetricReader endpointReader; @ExportMetricWriter
private Map<String, MetricWriter> writers = Collections.emptyMap();
@Bean
@ConditionalOnMissingBean(name = "metricWritersMetricExporter")
public SchedulingConfigurer metricWritersMetricExporter() {
Map<String, MetricWriter> writers = new HashMap<String, MetricWriter>();
MetricReader reader = this.endpointReader;
if (reader == null && !CollectionUtils.isEmpty(this.readers)) {
reader = new CompositeMetricReader(
this.readers.toArray(new MetricReader[this.readers.size()]));
}
if (reader != null) {
writers.putAll(this.writers);
return new MetricExporters(reader, writers, this.properties);
}
return new NoOpSchedulingConfigurer();
}
@Configuration @Configuration
protected static class MetricExportPropertiesConfiguration { protected static class MetricExportPropertiesConfiguration {
@Value("spring.metrics.${random.value:0000}.${spring.application.name:application}") @Value("spring.metrics.${random.value:0000}.${spring.application.name:application}")
private String prefix = "spring.metrics"; private String prefix = "spring.metrics";
@ -70,36 +92,18 @@ public class MetricExportAutoConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
public MetricExportProperties metricExportProperties() { public MetricExportProperties metricExportProperties() {
MetricExportProperties export = new MetricExportProperties(); MetricExportProperties export = new MetricExportProperties();
export.getRedis().setPrefix(prefix); export.getRedis().setPrefix(this.prefix);
return export; return export;
} }
} }
@Bean private static class NoOpSchedulingConfigurer implements SchedulingConfigurer {
@ConditionalOnMissingBean(name = "metricWritersMetricExporter")
public SchedulingConfigurer metricWritersMetricExporter() {
Map<String, MetricWriter> writers = new HashMap<String, MetricWriter>(); @Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
MetricReader reader = this.endpointReader;
if (reader == null && this.readers != null && !this.readers.isEmpty()) {
reader = new CompositeMetricReader(
this.readers.toArray(new MetricReader[this.readers.size()]));
} }
if (reader != null) {
writers.putAll(this.writers);
MetricExporters exporters = new MetricExporters(reader, writers, this.metrics);
return exporters;
}
return new SchedulingConfigurer() {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
}
};
} }
} }

View File

@ -32,6 +32,7 @@ import org.springframework.messaging.MessageChannel;
* {@link MessageChannel}. * {@link MessageChannel}.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@Configuration @Configuration
@ConditionalOnClass(MessageChannel.class) @ConditionalOnClass(MessageChannel.class)
@ -46,4 +47,4 @@ public class MetricsChannelAutoConfiguration {
return new MessageChannelMetricWriter(channel); return new MessageChannelMetricWriter(channel);
} }
} }

View File

@ -35,6 +35,7 @@ import com.codahale.metrics.MetricRegistry;
* {@link EnableAutoConfiguration Auto-configuration} for Dropwizard-based metrics. * {@link EnableAutoConfiguration Auto-configuration} for Dropwizard-based metrics.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@Configuration @Configuration
@ConditionalOnClass(MetricRegistry.class) @ConditionalOnClass(MetricRegistry.class)
@ -60,4 +61,4 @@ public class MetricsDropwizardAutoConfiguration {
return new MetricReaderPublicMetrics(reader); return new MetricReaderPublicMetrics(reader);
} }
} }

View File

@ -80,7 +80,8 @@ public class PublicMetricsAutoConfiguration {
@Bean @Bean
public MetricReaderPublicMetrics metricReaderPublicMetrics() { public MetricReaderPublicMetrics metricReaderPublicMetrics() {
return new MetricReaderPublicMetrics(new CompositeMetricReader(this.metricReaders.toArray(new MetricReader[0]))); return new MetricReaderPublicMetrics(new CompositeMetricReader(
this.metricReaders.toArray(new MetricReader[0])));
} }
@Bean @Bean

View File

@ -77,7 +77,7 @@ public class MetricsEndpoint extends AbstractEndpoint<Map<String, Object>> {
result.put(metric.getName(), metric.getValue()); result.put(metric.getName(), metric.getValue());
} }
} }
catch (Exception e) { catch (Exception ex) {
// Could not evaluate metrics // Could not evaluate metrics
} }
} }

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.actuate.endpoint; package org.springframework.boot.actuate.endpoint;
import java.util.ArrayList; import java.util.ArrayList;
@ -25,12 +26,12 @@ import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.reader.MetricReader; import org.springframework.boot.actuate.metrics.reader.MetricReader;
/** /**
* A {@link MetricReader} that pulls all current values out of the {@link MetricsEndpoint} * {@link MetricReader} that pulls all current values out of the {@link MetricsEndpoint}.
* . No timestamp information is available, so there is no way to check if the values are * No timestamp information is available, so there is no way to check if the values are
* recent, and they all come out with the default (current time). * recent, and they all come out with the default (current time).
*
* @author Dave Syer
* *
* @author Dave Syer
* @since 1.3.0
*/ */
public class MetricsEndpointMetricReader implements MetricReader { public class MetricsEndpointMetricReader implements MetricReader {
@ -43,7 +44,7 @@ public class MetricsEndpointMetricReader implements MetricReader {
@Override @Override
public Metric<?> findOne(String metricName) { public Metric<?> findOne(String metricName) {
Metric<Number> metric = null; Metric<Number> metric = null;
Object value = endpoint.invoke().get(metricName); Object value = this.endpoint.invoke().get(metricName);
if (value != null) { if (value != null) {
metric = new Metric<Number>(metricName, (Number) value); metric = new Metric<Number>(metricName, (Number) value);
} }
@ -53,7 +54,7 @@ public class MetricsEndpointMetricReader implements MetricReader {
@Override @Override
public Iterable<Metric<?>> findAll() { public Iterable<Metric<?>> findAll() {
List<Metric<?>> metrics = new ArrayList<Metric<?>>(); List<Metric<?>> metrics = new ArrayList<Metric<?>>();
Map<String, Object> values = endpoint.invoke(); Map<String, Object> values = this.endpoint.invoke();
Date timestamp = new Date(); Date timestamp = new Date();
for (Entry<String, Object> entry : values.entrySet()) { for (Entry<String, Object> entry : values.entrySet()) {
String name = entry.getKey(); String name = entry.getKey();
@ -65,7 +66,7 @@ public class MetricsEndpointMetricReader implements MetricReader {
@Override @Override
public long count() { public long count() {
return endpoint.invoke().size(); return this.endpoint.invoke().size();
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2014-2015 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.actuate.metrics.aggregate; package org.springframework.boot.actuate.metrics.aggregate;
import java.util.HashSet; import java.util.HashSet;
@ -35,7 +36,7 @@ import org.springframework.util.StringUtils;
* value. * value.
* *
* @author Dave Syer * @author Dave Syer
* * @since 1.3.0
*/ */
public class AggregateMetricReader implements MetricReader { public class AggregateMetricReader implements MetricReader {
@ -52,7 +53,6 @@ public class AggregateMetricReader implements MetricReader {
/** /**
* The number of period-separated keys to remove from the start of the input metric * The number of period-separated keys to remove from the start of the input metric
* names before aggregating. * names before aggregating.
*
* @param truncate length of source metric prefixes * @param truncate length of source metric prefixes
*/ */
public void setTruncateKeyLength(int truncate) { public void setTruncateKeyLength(int truncate) {
@ -62,7 +62,6 @@ public class AggregateMetricReader implements MetricReader {
/** /**
* Prefix to apply to all output metrics. A period will be appended if no present in * Prefix to apply to all output metrics. A period will be appended if no present in
* the provided value. * the provided value.
*
* @param prefix the prefix to use default "aggregator.") * @param prefix the prefix to use default "aggregator.")
*/ */
public void setPrefix(String prefix) { public void setPrefix(String prefix) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,6 +25,7 @@ import org.springframework.lang.UsesJava8;
* Fast implementation of {@link CounterService} using {@link CounterBuffers}. * Fast implementation of {@link CounterService} using {@link CounterBuffers}.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@UsesJava8 @UsesJava8
public class BufferCounterService implements CounterService { public class BufferCounterService implements CounterService {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,6 +25,7 @@ import org.springframework.lang.UsesJava8;
* Fast implementation of {@link GaugeService} using {@link GaugeBuffers}. * Fast implementation of {@link GaugeService} using {@link GaugeBuffers}.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@UsesJava8 @UsesJava8
public class BufferGaugeService implements GaugeService { public class BufferGaugeService implements GaugeService {

View File

@ -33,6 +33,7 @@ import org.springframework.lang.UsesJava8;
* {@link GaugeBuffers}. * {@link GaugeBuffers}.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@UsesJava8 @UsesJava8
public class BufferMetricReader implements MetricReader, PrefixMetricReader { public class BufferMetricReader implements MetricReader, PrefixMetricReader {

View File

@ -28,6 +28,7 @@ import org.springframework.lang.UsesJava8;
* Fast writes to in-memory metrics store using {@link LongBuffer}. * Fast writes to in-memory metrics store using {@link LongBuffer}.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@UsesJava8 @UsesJava8
public class CounterBuffers { public class CounterBuffers {
@ -113,4 +114,5 @@ public class CounterBuffers {
} }
consumer.accept(adder); consumer.accept(adder);
} }
} }

View File

@ -20,6 +20,7 @@ package org.springframework.boot.actuate.metrics.buffer;
* Mutable buffer containing a double value and a timestamp. * Mutable buffer containing a double value and a timestamp.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public class DoubleBuffer { public class DoubleBuffer {
@ -47,4 +48,5 @@ public class DoubleBuffer {
public long getTimestamp() { public long getTimestamp() {
return this.timestamp; return this.timestamp;
} }
}
}

View File

@ -28,6 +28,7 @@ import org.springframework.lang.UsesJava8;
* Fast writes to in-memory metrics store using {@link DoubleBuffer}. * Fast writes to in-memory metrics store using {@link DoubleBuffer}.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@UsesJava8 @UsesJava8
public class GaugeBuffers { public class GaugeBuffers {
@ -94,4 +95,5 @@ public class GaugeBuffers {
} }
consumer.accept(value); consumer.accept(value);
} }
} }

View File

@ -24,6 +24,7 @@ import org.springframework.lang.UsesJava8;
* Mutable buffer containing a long adder (Java 8) and a timestamp. * Mutable buffer containing a long adder (Java 8) and a timestamp.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@UsesJava8 @UsesJava8
public class LongBuffer { public class LongBuffer {
@ -56,4 +57,5 @@ public class LongBuffer {
public void add(long delta) { public void add(long delta) {
this.adder.add(delta); this.adder.add(delta);
} }
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -33,26 +33,27 @@ import org.springframework.util.StringUtils;
* export). * export).
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public abstract class AbstractMetricExporter implements Exporter { public abstract class AbstractMetricExporter implements Exporter {
private static final Log logger = LogFactory.getLog(AbstractMetricExporter.class); private static final Log logger = LogFactory.getLog(AbstractMetricExporter.class);
private volatile AtomicBoolean processing = new AtomicBoolean(false); private final String prefix;
private Date earliestTimestamp = new Date(); private Date earliestTimestamp = new Date();
private boolean ignoreTimestamps = false; private boolean ignoreTimestamps = false;
private final String prefix; private boolean sendLatest = true;
private volatile AtomicBoolean processing = new AtomicBoolean(false);
private Date latestTimestamp = new Date(0L); private Date latestTimestamp = new Date(0L);
private boolean sendLatest = true;
public AbstractMetricExporter(String prefix) { public AbstractMetricExporter(String prefix) {
this.prefix = !StringUtils.hasText(prefix) ? "" : (prefix.endsWith(".") ? prefix this.prefix = (!StringUtils.hasText(prefix) ? "" : (prefix.endsWith(".") ? prefix
: prefix + "."); : prefix + "."));
} }
/** /**
@ -73,7 +74,6 @@ public abstract class AbstractMetricExporter implements Exporter {
/** /**
* Send only the data that changed since the last export. * Send only the data that changed since the last export.
*
* @param sendLatest the flag to set * @param sendLatest the flag to set
*/ */
public void setSendLatest(boolean sendLatest) { public void setSendLatest(boolean sendLatest) {
@ -82,47 +82,63 @@ public abstract class AbstractMetricExporter implements Exporter {
@Override @Override
public void export() { public void export() {
if (!this.processing.compareAndSet(false, true)) { if (this.processing.compareAndSet(false, true)) {
// skip a tick long latestTimestamp = System.currentTimeMillis();
return;
}
long latestTimestamp = 0;
try {
latestTimestamp = System.currentTimeMillis();
for (String group : groups()) {
Collection<Metric<?>> values = new ArrayList<Metric<?>>();
for (Metric<?> metric : next(group)) {
Metric<?> value = new Metric<Number>(this.prefix + metric.getName(),
metric.getValue(), metric.getTimestamp());
Date timestamp = metric.getTimestamp();
if (!this.ignoreTimestamps && this.earliestTimestamp.after(timestamp)) {
continue;
}
if (!this.ignoreTimestamps && this.sendLatest
&& this.latestTimestamp.after(timestamp)) {
continue;
}
values.add(value);
}
if (!values.isEmpty()) {
write(group, values);
}
}
}
catch (Exception e) {
logger.warn("Could not write to MetricWriter: " + e.getClass() + ": "
+ e.getMessage());
}
finally {
try { try {
exportGroups();
}
catch (Exception ex) {
logger.warn("Could not write to MetricWriter: " + ex.getClass() + ": "
+ ex.getMessage());
}
finally {
this.latestTimestamp = new Date(latestTimestamp); this.latestTimestamp = new Date(latestTimestamp);
flush(); flushQuietly();
this.processing.set(false);
} }
catch (Exception e) { }
logger.warn("Could not flush MetricWriter: " + e.getClass() + ": " }
+ e.getMessage());
private void exportGroups() {
for (String group : groups()) {
Collection<Metric<?>> values = new ArrayList<Metric<?>>();
for (Metric<?> metric : next(group)) {
Date timestamp = metric.getTimestamp();
if (canExportTimestamp(timestamp)) {
values.add(getPrefixedMetric(metric));
}
} }
this.processing.set(false); if (!values.isEmpty()) {
write(group, values);
}
}
}
private Metric<?> getPrefixedMetric(Metric<?> metric) {
String name = this.prefix + metric.getName();
return new Metric<Number>(name, metric.getValue(), metric.getTimestamp());
}
private boolean canExportTimestamp(Date timestamp) {
if (this.ignoreTimestamps) {
return true;
}
if (this.earliestTimestamp.after(timestamp)) {
return false;
}
if (this.sendLatest && this.latestTimestamp.after(timestamp)) {
return false;
}
return true;
}
private void flushQuietly() {
try {
flush();
}
catch (Exception ex) {
logger.warn("Could not flush MetricWriter: " + ex.getClass() + ": "
+ ex.getMessage());
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2013 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,6 +25,7 @@ package org.springframework.boot.actuate.metrics.export;
* it using a {@code @Scheduled} annotation in a Spring ApplicationContext. * it using a {@code @Scheduled} annotation in a Spring ApplicationContext.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public interface Exporter { public interface Exporter {

View File

@ -16,23 +16,33 @@
package org.springframework.boot.actuate.metrics.export; package org.springframework.boot.actuate.metrics.export;
import java.io.Flushable;
import java.lang.reflect.Method;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.reader.MetricReader; import org.springframework.boot.actuate.metrics.reader.MetricReader;
import org.springframework.boot.actuate.metrics.writer.CompositeMetricWriter;
import org.springframework.boot.actuate.metrics.writer.MetricWriter; import org.springframework.boot.actuate.metrics.writer.MetricWriter;
import org.springframework.boot.actuate.metrics.writer.WriterUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.PatternMatchUtils; import org.springframework.util.PatternMatchUtils;
import org.springframework.util.ReflectionUtils;
/** /**
* {@link Exporter} that "exports" by copying metric data from a source * {@link Exporter} that "exports" by copying metric data from a source
* {@link MetricReader} to a destination {@link MetricWriter}. * {@link MetricReader} to a destination {@link MetricWriter}.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public class MetricCopyExporter extends AbstractMetricExporter { public class MetricCopyExporter extends AbstractMetricExporter {
private static final Log logger = LogFactory.getLog(MetricCopyExporter.class);
private final MetricReader reader; private final MetricReader reader;
private final MetricWriter writer; private final MetricWriter writer;
@ -41,41 +51,53 @@ public class MetricCopyExporter extends AbstractMetricExporter {
private String[] excludes = new String[0]; private String[] excludes = new String[0];
/**
* Create a new {@link MetricCopyExporter} instance.
* @param reader the metric reader
* @param writer the metric writer
*/
public MetricCopyExporter(MetricReader reader, MetricWriter writer) { public MetricCopyExporter(MetricReader reader, MetricWriter writer) {
this(reader, writer, ""); this(reader, writer, "");
} }
public void setIncludes(String... includes) { /**
if (includes != null) { * Create a new {@link MetricCopyExporter} instance.
this.includes = includes; * @param reader the metric reader
} * @param writer the metric writer
} * @param prefix the name prefix
*/
public void setExcludes(String... excludes) {
if (excludes != null) {
this.excludes = excludes;
}
}
public MetricCopyExporter(MetricReader reader, MetricWriter writer, String prefix) { public MetricCopyExporter(MetricReader reader, MetricWriter writer, String prefix) {
super(prefix); super(prefix);
this.reader = reader; this.reader = reader;
this.writer = writer; this.writer = writer;
} }
/**
* Set the include patterns used to filter metrics.
* @param includes the include patterns
*/
public void setIncludes(String... includes) {
if (includes != null) {
this.includes = includes;
}
}
/**
* Set the exclude patterns used to filter metrics.
* @param excludes the exclude patterns
*/
public void setExcludes(String... excludes) {
if (excludes != null) {
this.excludes = excludes;
}
}
@Override @Override
protected Iterable<Metric<?>> next(String group) { protected Iterable<Metric<?>> next(String group) {
if ((this.includes == null || this.includes.length == 0) if (ObjectUtils.isEmpty(this.includes) && ObjectUtils.isEmpty(this.excludes)) {
&& (this.excludes == null || this.excludes.length == 0)) {
return this.reader.findAll(); return this.reader.findAll();
} }
return new Iterable<Metric<?>>() { return new PatternMatchingIterable(MetricCopyExporter.this.reader);
@Override
public Iterator<Metric<?>> iterator() {
return new PatternMatchingIterator(MetricCopyExporter.this.reader
.findAll().iterator());
}
};
} }
@Override @Override
@ -87,12 +109,52 @@ public class MetricCopyExporter extends AbstractMetricExporter {
@Override @Override
public void flush() { public void flush() {
WriterUtils.flush(this.writer); flush(this.writer);
}
private void flush(MetricWriter writer) {
if (writer instanceof CompositeMetricWriter) {
for (MetricWriter child : (CompositeMetricWriter) writer) {
flush(child);
}
}
try {
if (ClassUtils.isPresent("java.io.Flushable", null)) {
if (writer instanceof Flushable) {
((Flushable) writer).flush();
return;
}
}
Method method = ReflectionUtils.findMethod(writer.getClass(), "flush");
if (method != null) {
ReflectionUtils.invokeMethod(method, writer);
}
}
catch (Exception ex) {
logger.warn("Could not flush MetricWriter: " + ex.getClass() + ": "
+ ex.getMessage());
}
}
private class PatternMatchingIterable implements Iterable<Metric<?>> {
private final MetricReader reader;
public PatternMatchingIterable(MetricReader reader) {
this.reader = reader;
}
@Override
public Iterator<Metric<?>> iterator() {
return new PatternMatchingIterator(this.reader.findAll().iterator());
}
} }
private class PatternMatchingIterator implements Iterator<Metric<?>> { private class PatternMatchingIterator implements Iterator<Metric<?>> {
private Metric<?> buffer = null; private Metric<?> buffer = null;
private Iterator<Metric<?>> iterator; private Iterator<Metric<?>> iterator;
public PatternMatchingIterator(Iterator<Metric<?>> iterator) { public PatternMatchingIterator(Iterator<Metric<?>> iterator) {
@ -109,33 +171,24 @@ public class MetricCopyExporter extends AbstractMetricExporter {
} }
private Metric<?> findNext() { private Metric<?> findNext() {
Metric<?> metric = null; while (this.iterator.hasNext()) {
boolean matched = false; Metric<?> metric = this.iterator.next();
while (this.iterator.hasNext() && !matched) { if (isMatch(metric)) {
metric = this.iterator.next(); return metric;
if (MetricCopyExporter.this.includes == null
|| MetricCopyExporter.this.includes.length == 0) {
matched = true;
}
else {
for (String pattern : MetricCopyExporter.this.includes) {
if (PatternMatchUtils.simpleMatch(pattern, metric.getName())) {
matched = true;
break;
}
}
}
if (MetricCopyExporter.this.excludes != null) {
for (String pattern : MetricCopyExporter.this.excludes) {
if (PatternMatchUtils.simpleMatch(pattern, metric.getName())) {
matched = false;
break;
}
}
} }
} }
return matched ? metric : null; return null;
}
private boolean isMatch(Metric<?> metric) {
String[] includes = MetricCopyExporter.this.includes;
String[] excludes = MetricCopyExporter.this.excludes;
String name = metric.getName();
if (ObjectUtils.isEmpty(includes)
|| PatternMatchUtils.simpleMatch(includes, name)) {
return !PatternMatchUtils.simpleMatch(excludes, name);
}
return false;
} }
@Override @Override
@ -144,5 +197,6 @@ public class MetricCopyExporter extends AbstractMetricExporter {
this.buffer = null; this.buffer = null;
return metric; return metric;
} }
}; };
} }

View File

@ -27,55 +27,29 @@ import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* Configuration properties for metrics export.
*
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@ConfigurationProperties("spring.metrics.export") @ConfigurationProperties("spring.metrics.export")
public class MetricExportProperties extends Trigger { public class MetricExportProperties extends TriggerProperties {
/** /**
* Flag to disable all metric exports (assuming any MetricWriters are available). * Flag to disable all metric exports (assuming any MetricWriters are available).
*/ */
private boolean enabled = true; private boolean enabled = true;
private Map<String, SpecificTrigger> triggers = new LinkedHashMap<String, SpecificTrigger>(); private Map<String, SpecificTriggerProperties> triggers = new LinkedHashMap<String, SpecificTriggerProperties>();
private Redis redis = new Redis(); private Redis redis = new Redis();
/**
* Default values for trigger configuration for all writers. Can also be set by
* including a writer with <code>name="*"</code>.
*
* @return the default trigger configuration
*/
public Trigger getDefault() {
return this;
}
/**
* Configuration for triggers on individual named writers. Each value can individually
* specify a name pattern explicitly, or else the map key will be used if the name is
* not set.
*
* @return the writers
*/
public Map<String, SpecificTrigger> getTriggers() {
return this.triggers;
}
public Redis getRedis() {
return redis;
}
public void setRedis(Redis redis) {
this.redis = redis;
}
@PostConstruct @PostConstruct
public void setUpDefaults() { public void setUpDefaults() {
Trigger defaults = this; TriggerProperties defaults = this;
for (Entry<String, SpecificTrigger> entry : this.triggers.entrySet()) { for (Entry<String, SpecificTriggerProperties> entry : this.triggers.entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
SpecificTrigger value = entry.getValue(); SpecificTriggerProperties value = entry.getValue();
if (value.getNames() == null || value.getNames().length == 0) { if (value.getNames() == null || value.getNames().length == 0) {
value.setNames(new String[] { key }); value.setNames(new String[] { key });
} }
@ -86,7 +60,7 @@ public class MetricExportProperties extends Trigger {
if (defaults.getDelayMillis() == null) { if (defaults.getDelayMillis() == null) {
defaults.setDelayMillis(5000); defaults.setDelayMillis(5000);
} }
for (Trigger value : this.triggers.values()) { for (TriggerProperties value : this.triggers.values()) {
if (value.isSendLatest() == null) { if (value.isSendLatest() == null) {
value.setSendLatest(defaults.isSendLatest()); value.setSendLatest(defaults.isSendLatest());
} }
@ -96,47 +70,56 @@ public class MetricExportProperties extends Trigger {
} }
} }
@Override
public boolean isEnabled() { public boolean isEnabled() {
return this.enabled; return this.enabled;
} }
@Override
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
this.enabled = enabled; this.enabled = enabled;
} }
/**
* Configuration for triggers on individual named writers. Each value can individually
* specify a name pattern explicitly, or else the map key will be used if the name is
* not set.
* @return the writers
*/
public Map<String, SpecificTriggerProperties> getTriggers() {
return this.triggers;
}
public Redis getRedis() {
return this.redis;
}
public void setRedis(Redis redis) {
this.redis = redis;
}
/**
* Default values for trigger configuration for all writers. Can also be set by
* including a writer with {@code name="*"}.
* @return the default trigger configuration
*/
public TriggerProperties getDefault() {
return this;
}
/** /**
* Find a matching trigger configuration. * Find a matching trigger configuration.
* @param name the bean name to match * @param name the bean name to match
* @return a matching configuration if there is one * @return a matching configuration if there is one
*/ */
public Trigger findTrigger(String name) { public TriggerProperties findTrigger(String name) {
for (SpecificTrigger value : this.triggers.values()) { for (SpecificTriggerProperties value : this.triggers.values()) {
if (PatternMatchUtils.simpleMatch(value.getNames(), name)) { if (PatternMatchUtils.simpleMatch(value.getNames(), name)) {
return value; return value;
} }
} }
return this; return this;
} }
/**
* Trigger for specific bean names.
*/
public static class SpecificTrigger extends Trigger {
/**
* Names (or patterns) for bean names that this configuration applies to.
*/
private String[] names;
public String[] getNames() {
return this.names;
}
public void setNames(String[] names) {
this.names = names;
}
}
public static class Redis { public static class Redis {
@ -155,9 +138,9 @@ public class MetricExportProperties extends Trigger {
* system sharing a redis repository. * system sharing a redis repository.
*/ */
private String key = "keys.spring.metrics"; private String key = "keys.spring.metrics";
public String getPrefix() { public String getPrefix() {
return prefix; return this.prefix;
} }
public void setPrefix(String prefix) { public void setPrefix(String prefix) {
@ -165,7 +148,7 @@ public class MetricExportProperties extends Trigger {
} }
public String getKey() { public String getKey() {
return key; return this.key;
} }
public void setKey(String key) { public void setKey(String key) {
@ -187,74 +170,3 @@ public class MetricExportProperties extends Trigger {
} }
} }
class Trigger {
/**
* Delay in milliseconds between export ticks. Metrics are exported to external
* sources on a schedule with this delay.
*/
private Long delayMillis;
/**
* Flag to enable metric export (assuming a MetricWriter is available).
*/
private boolean enabled = true;
/**
* Flag to switch off any available optimizations based on not exporting unchanged
* metric values.
*/
private Boolean sendLatest;
/**
* List of patterns for metric names to include.
*/
private String[] includes;
/**
* List of patterns for metric names to exclude. Applied after the includes.
*/
private String[] excludes;
public String[] getIncludes() {
return this.includes;
}
public void setIncludes(String[] includes) {
this.includes = includes;
}
public void setExcludes(String[] excludes) {
this.excludes = excludes;
}
public String[] getExcludes() {
return this.excludes;
}
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Long getDelayMillis() {
return this.delayMillis;
}
public void setDelayMillis(long delayMillis) {
this.delayMillis = delayMillis;
}
public Boolean isSendLatest() {
return this.sendLatest;
}
public void setSendLatest(boolean sendLatest) {
this.sendLatest = sendLatest;
}
}

View File

@ -27,58 +27,68 @@ import org.springframework.scheduling.config.IntervalTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar; import org.springframework.scheduling.config.ScheduledTaskRegistrar;
/** /**
* {@link SchedulingConfigurer} to handle metrics {@link MetricCopyExporter export}.
*
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public class MetricExporters implements SchedulingConfigurer { public class MetricExporters implements SchedulingConfigurer {
private MetricExportProperties export; private final MetricReader reader;
private Map<String, MetricWriter> writers; private final Map<String, MetricWriter> writers;
private Map<String, Exporter> exporters = new HashMap<String, Exporter>(); private final MetricExportProperties properties;
private MetricReader reader; private final Map<String, Exporter> exporters = new HashMap<String, Exporter>();
public MetricExporters(MetricReader reader, Map<String, MetricWriter> writers, public MetricExporters(MetricReader reader, Map<String, MetricWriter> writers,
MetricExportProperties export) { MetricExportProperties properties) {
this.reader = reader; this.reader = reader;
this.export = export;
this.writers = writers; this.writers = writers;
this.properties = properties;
}
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
for (Entry<String, MetricWriter> entry : this.writers.entrySet()) {
String name = entry.getKey();
MetricWriter writer = entry.getValue();
TriggerProperties trigger = this.properties.findTrigger(name);
if (trigger != null) {
MetricCopyExporter exporter = getExporter(writer, trigger);
this.exporters.put(name, exporter);
ExportRunner runner = new ExportRunner(exporter);
IntervalTask task = new IntervalTask(runner, trigger.getDelayMillis(),
trigger.getDelayMillis());
taskRegistrar.addFixedDelayTask(task);
}
}
}
private MetricCopyExporter getExporter(MetricWriter writer, TriggerProperties trigger) {
MetricCopyExporter exporter = new MetricCopyExporter(this.reader, writer);
exporter.setIncludes(trigger.getIncludes());
exporter.setExcludes(trigger.getExcludes());
exporter.setSendLatest(trigger.isSendLatest());
return exporter;
} }
public Map<String, Exporter> getExporters() { public Map<String, Exporter> getExporters() {
return this.exporters; return this.exporters;
} }
@Override private static class ExportRunner implements Runnable {
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
for (Entry<String, MetricWriter> entry : this.writers.entrySet()) { private final MetricCopyExporter exporter;
String name = entry.getKey();
Trigger trigger = this.export.findTrigger(name);
if (trigger != null) { public ExportRunner(MetricCopyExporter exporter) {
this.exporter = exporter;
MetricWriter writer = entry.getValue(); }
final MetricCopyExporter exporter = new MetricCopyExporter(this.reader,
writer);
if (trigger.getIncludes() != null || trigger.getExcludes() != null) {
exporter.setIncludes(trigger.getIncludes());
exporter.setExcludes(trigger.getExcludes());
}
exporter.setSendLatest(trigger.isSendLatest());
this.exporters.put(name, exporter);
taskRegistrar.addFixedDelayTask(new IntervalTask(new Runnable() {
@Override
public void run() {
exporter.export();
}
}, trigger.getDelayMillis(), trigger.getDelayMillis()));
}
@Override
public void run() {
this.exporter.export();
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -30,6 +30,7 @@ import org.springframework.boot.actuate.metrics.writer.PrefixMetricWriter;
* all metrics whose name starts with a prefix (or all metrics if the prefix is empty). * all metrics whose name starts with a prefix (or all metrics if the prefix is empty).
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public class PrefixMetricGroupExporter extends AbstractMetricExporter { public class PrefixMetricGroupExporter extends AbstractMetricExporter {
@ -64,6 +65,7 @@ public class PrefixMetricGroupExporter extends AbstractMetricExporter {
} }
/** /**
* The groups to export.
* @param groups the groups to set * @param groups the groups to set
*/ */
public void setGroups(Set<String> groups) { public void setGroups(Set<String> groups) {

View File

@ -30,14 +30,14 @@ import org.springframework.boot.actuate.metrics.writer.PrefixMetricWriter;
/** /**
* Exporter or converter for {@link RichGauge} data to a metric-based back end. Each gauge * Exporter or converter for {@link RichGauge} data to a metric-based back end. Each gauge
* measurement is stored as a set of related metrics with a common prefix (the name of the * measurement is stored as a set of related metrics with a common prefix (the name of the
* gauge), and suffixes that describe the data. For example, a gauge called * gauge), and suffixes that describe the data. For example, a gauge called {@code foo} is
* <code>foo</code> is stored as * stored as {@code[foo.min, foo.max. foo.val, foo.count, foo.avg, foo.alpha]}. If the
* <code>[foo.min, foo.max. foo.val, foo.count, foo.avg, foo.alpha]</code>. If the
* {@link MetricWriter} provided is a {@link MultiMetricRepository} then the values for a * {@link MetricWriter} provided is a {@link MultiMetricRepository} then the values for a
* gauge will be stored as a group, and hence will be retrievable from the repository in a * gauge will be stored as a group, and hence will be retrievable from the repository in a
* single query (or optionally individually). * single query (or optionally individually).
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public class RichGaugeExporter extends AbstractMetricExporter { public class RichGaugeExporter extends AbstractMetricExporter {
@ -54,6 +54,7 @@ public class RichGaugeExporter extends AbstractMetricExporter {
private static final String ALPHA = ".alpha"; private static final String ALPHA = ".alpha";
private final RichGaugeReader reader; private final RichGaugeReader reader;
private final PrefixMetricWriter writer; private final PrefixMetricWriter writer;
public RichGaugeExporter(RichGaugeReader reader, PrefixMetricWriter writer) { public RichGaugeExporter(RichGaugeReader reader, PrefixMetricWriter writer) {

View File

@ -0,0 +1,40 @@
/*
* 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.export;
/**
* Trigger for specific names or patterns.
*
* @author Dave Syer
* @since 1.3.0
*/
public class SpecificTriggerProperties extends TriggerProperties {
/**
* Names (or patterns) for bean names that this configuration applies to.
*/
private String[] names;
public String[] getNames() {
return this.names;
}
public void setNames(String[] names) {
this.names = names;
}
}

View File

@ -0,0 +1,94 @@
/*
* 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.export;
/**
* Abstract base class for trigger properties.
*
* @author Dave Syer
* @since 1.3.0
*/
public abstract class TriggerProperties {
/**
* Delay in milliseconds between export ticks. Metrics are exported to external
* sources on a schedule with this delay.
*/
private Long delayMillis;
/**
* Flag to enable metric export (assuming a MetricWriter is available).
*/
private boolean enabled = true;
/**
* Flag to switch off any available optimizations based on not exporting unchanged
* metric values.
*/
private Boolean sendLatest;
/**
* List of patterns for metric names to include.
*/
private String[] includes;
/**
* List of patterns for metric names to exclude. Applied after the includes.
*/
private String[] excludes;
public String[] getIncludes() {
return this.includes;
}
public void setIncludes(String[] includes) {
this.includes = includes;
}
public void setExcludes(String[] excludes) {
this.excludes = excludes;
}
public String[] getExcludes() {
return this.excludes;
}
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Long getDelayMillis() {
return this.delayMillis;
}
public void setDelayMillis(long delayMillis) {
this.delayMillis = delayMillis;
}
public Boolean isSendLatest() {
return this.sendLatest;
}
public void setSendLatest(boolean sendLatest) {
this.sendLatest = sendLatest;
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.actuate.metrics.integration; package org.springframework.boot.actuate.metrics.integration;
import java.util.ArrayList; import java.util.ArrayList;
@ -26,14 +27,15 @@ import org.springframework.integration.support.management.Statistics;
import org.springframework.lang.UsesJava7; import org.springframework.lang.UsesJava7;
/** /**
* A {@link MetricReader} for Spring Integration metrics (as provided by spring-integration-jmx). * A {@link MetricReader} for Spring Integration metrics (as provided by
* * spring-integration-jmx).
* @author Dave Syer
* *
* @author Dave Syer
* @since 1.3.0
*/ */
@UsesJava7 @UsesJava7
public class SpringIntegrationMetricReader implements MetricReader { public class SpringIntegrationMetricReader implements MetricReader {
private final IntegrationMBeanExporter exporter; private final IntegrationMBeanExporter exporter;
public SpringIntegrationMetricReader(IntegrationMBeanExporter exporter) { public SpringIntegrationMetricReader(IntegrationMBeanExporter exporter) {
@ -47,23 +49,34 @@ public class SpringIntegrationMetricReader implements MetricReader {
@Override @Override
public Iterable<Metric<?>> findAll() { public Iterable<Metric<?>> findAll() {
IntegrationMBeanExporter exporter = this.exporter;
List<Metric<?>> metrics = new ArrayList<Metric<?>>(); List<Metric<?>> metrics = new ArrayList<Metric<?>>();
for (String name : exporter.getChannelNames()) { for (String name : exporter.getChannelNames()) {
metrics.addAll(getStatistics("integration.channel." + name + ".errorRate", exporter.getChannelErrorRate(name))); String prefix = "integration.channel." + name;
metrics.addAll(getStatistics("integration.channel." + name + ".sendRate", exporter.getChannelSendRate(name))); metrics.addAll(getStatistics(prefix + ".errorRate",
metrics.add(new Metric<Long>("integration.channel." + name + ".receiveCount", exporter.getChannelReceiveCountLong(name))); exporter.getChannelErrorRate(name)));
metrics.addAll(getStatistics(prefix + ".sendRate",
exporter.getChannelSendRate(name)));
metrics.add(new Metric<Long>(prefix + ".receiveCount", exporter
.getChannelReceiveCountLong(name)));
} }
for (String name : exporter.getHandlerNames()) { for (String name : exporter.getHandlerNames()) {
metrics.addAll(getStatistics("integration.handler." + name + ".duration", exporter.getHandlerDuration(name))); metrics.addAll(getStatistics("integration.handler." + name + ".duration",
exporter.getHandlerDuration(name)));
} }
metrics.add(new Metric<Long>("integration.activeHandlerCount", exporter.getActiveHandlerCountLong())); metrics.add(new Metric<Long>("integration.activeHandlerCount", exporter
metrics.add(new Metric<Integer>("integration.handlerCount", exporter.getHandlerCount())); .getActiveHandlerCountLong()));
metrics.add(new Metric<Integer>("integration.channelCount", exporter.getChannelCount())); metrics.add(new Metric<Integer>("integration.handlerCount", exporter
metrics.add(new Metric<Integer>("integration.queuedMessageCount", exporter.getQueuedMessageCount())); .getHandlerCount()));
return metrics; metrics.add(new Metric<Integer>("integration.channelCount", exporter
.getChannelCount()));
metrics.add(new Metric<Integer>("integration.queuedMessageCount", exporter
.getQueuedMessageCount()));
return metrics;
} }
private Collection<? extends Metric<?>> getStatistics(String name, Statistics statistic) { private Collection<? extends Metric<?>> getStatistics(String name,
Statistics statistic) {
List<Metric<?>> metrics = new ArrayList<Metric<?>>(); List<Metric<?>> metrics = new ArrayList<Metric<?>>();
metrics.add(new Metric<Double>(name + ".mean", statistic.getMean())); metrics.add(new Metric<Double>(name + ".mean", statistic.getMean()));
metrics.add(new Metric<Double>(name + ".max", statistic.getMax())); metrics.add(new Metric<Double>(name + ".max", statistic.getMax()));
@ -75,7 +88,9 @@ public class SpringIntegrationMetricReader implements MetricReader {
@Override @Override
public long count() { public long count() {
return exporter.getChannelCount()*11 + exporter.getHandlerCount()*5 + 4; int totalChannelCount = this.exporter.getChannelCount() * 11;
int totalHandlerCount = this.exporter.getHandlerCount() * 5;
return totalChannelCount + totalHandlerCount + 4;
} }
} }

View File

@ -33,6 +33,7 @@ import org.springframework.util.StringUtils;
* domain is copied from the input key and the type in the input key is discarded. * domain is copied from the input key and the type in the input key is discarded.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public class DefaultMetricNamingStrategy implements ObjectNamingStrategy { public class DefaultMetricNamingStrategy implements ObjectNamingStrategy {

View File

@ -21,6 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import javax.management.MalformedObjectNameException; import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -41,6 +42,7 @@ import org.springframework.jmx.export.naming.ObjectNamingStrategy;
* and <code>value</code> keys by splitting up the metric name on periods. * and <code>value</code> keys by splitting up the metric name on periods.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
@ManagedResource(description = "MetricWriter for pushing metrics to JMX MBeans.") @ManagedResource(description = "MetricWriter for pushing metrics to JMX MBeans.")
public class JmxMetricWriter implements MetricWriter { public class JmxMetricWriter implements MetricWriter {
@ -97,10 +99,9 @@ public class JmxMetricWriter implements MetricWriter {
try { try {
// We can unregister the MBean, but if this writer is on the end of an // We can unregister the MBean, but if this writer is on the end of an
// Exporter the chances are it will be re-registered almost immediately. // Exporter the chances are it will be re-registered almost immediately.
this.exporter.unregisterManagedResource(this.namingStrategy this.exporter.unregisterManagedResource(getName(name, value));
.getObjectName(value, getKey(name)));
} }
catch (MalformedObjectNameException e) { catch (MalformedObjectNameException ex) {
logger.warn("Could not unregister MBean for " + name); logger.warn("Could not unregister MBean for " + name);
} }
} }
@ -111,18 +112,19 @@ public class JmxMetricWriter implements MetricWriter {
this.values.putIfAbsent(name, new MetricValue()); this.values.putIfAbsent(name, new MetricValue());
MetricValue value = this.values.get(name); MetricValue value = this.values.get(name);
try { try {
this.exporter.registerManagedResource(value, this.exporter.registerManagedResource(value, getName(name, value));
this.namingStrategy.getObjectName(value, getKey(name)));
} }
catch (Exception e) { catch (Exception ex) {
// Could not register mbean, maybe just a race condition // Could not register mbean, maybe just a race condition
} }
} }
return this.values.get(name); return this.values.get(name);
} }
private String getKey(String name) { private ObjectName getName(String name, MetricValue value)
return String.format(this.domain + ":type=MetricValue,name=%s", name); throws MalformedObjectNameException {
String key = String.format(this.domain + ":type=MetricValue,name=%s", name);
return this.namingStrategy.getObjectName(value, key);
} }
@ManagedResource @ManagedResource

View File

@ -34,6 +34,7 @@ import org.springframework.util.ObjectUtils;
* (overwriting the default). * (overwriting the default).
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public class DefaultOpenTsdbNamingStrategy implements OpenTsdbNamingStrategy { public class DefaultOpenTsdbNamingStrategy implements OpenTsdbNamingStrategy {

View File

@ -19,7 +19,10 @@ package org.springframework.boot.actuate.metrics.opentsdb;
import java.util.Map; import java.util.Map;
/** /**
* OpenTSDB Data.
*
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public class OpenTsdbData { public class OpenTsdbData {

View File

@ -43,6 +43,7 @@ import org.springframework.web.client.RestTemplate;
* <code>@Scheduled</code>} task to flush periodically. * <code>@Scheduled</code>} task to flush periodically.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public class OpenTsdbMetricWriter implements MetricWriter { public class OpenTsdbMetricWriter implements MetricWriter {
@ -141,4 +142,4 @@ public class OpenTsdbMetricWriter implements MetricWriter {
set(new Metric<Long>(metricName, 0L)); set(new Metric<Long>(metricName, 0L));
} }
} }

View File

@ -20,7 +20,10 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
/** /**
* OpenTSDB Name.
*
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public class OpenTsdbName { public class OpenTsdbName {

View File

@ -17,10 +17,18 @@
package org.springframework.boot.actuate.metrics.opentsdb; package org.springframework.boot.actuate.metrics.opentsdb;
/** /**
* Strategy used to convert a metric name into an {@link OpenTsdbName}.
*
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public interface OpenTsdbNamingStrategy { public interface OpenTsdbNamingStrategy {
/**
* Convert the metric name into a {@link OpenTsdbName}
* @param metricName the name of the metric
* @return an Open TSDB name
*/
OpenTsdbName getName(String metricName); OpenTsdbName getName(String metricName);
} }

View File

@ -37,16 +37,16 @@ import com.timgroup.statsd.StatsDClientErrorHandler;
* a gauge. * a gauge.
* *
* @author Dave Syer * @author Dave Syer
* @since 1.3.0
*/ */
public class StatsdMetricWriter implements MetricWriter, Closeable { public class StatsdMetricWriter implements MetricWriter, Closeable {
private static Log logger = LogFactory.getLog(StatsdMetricWriter.class); private static final Log logger = LogFactory.getLog(StatsdMetricWriter.class);
private final NonBlockingStatsDClient client; private final NonBlockingStatsDClient client;
/** /**
* Create a new writer with the given parameters. * Create a new writer instance with the given parameters.
*
* @param host the hostname for the statsd server * @param host the hostname for the statsd server
* @param port the port for the statsd server * @param port the port for the statsd server
*/ */
@ -56,7 +56,6 @@ public class StatsdMetricWriter implements MetricWriter, Closeable {
/** /**
* Create a new writer with the given parameters. * Create a new writer with the given parameters.
*
* @param prefix the prefix to apply to all metric names (can be null) * @param prefix the prefix to apply to all metric names (can be null)
* @param host the hostname for the statsd server * @param host the hostname for the statsd server
* @param port the port for the statsd server * @param port the port for the statsd server
@ -101,11 +100,13 @@ public class StatsdMetricWriter implements MetricWriter, Closeable {
private static final class LoggingStatsdErrorHandler implements private static final class LoggingStatsdErrorHandler implements
StatsDClientErrorHandler { StatsDClientErrorHandler {
@Override @Override
public void handle(Exception e) { public void handle(Exception e) {
logger.debug("Failed to write metric. Exception: " + e.getClass() logger.debug("Failed to write metric. Exception: " + e.getClass()
+ ", message: " + e.getMessage()); + ", message: " + e.getMessage());
} }
} }
} }

View File

@ -65,4 +65,5 @@ public class DefaultCounterService implements CounterService {
this.names.put(metricName, name); this.names.put(metricName, name);
return name; return name;
} }
} }

View File

@ -57,4 +57,5 @@ public class DefaultGaugeService implements GaugeService {
this.names.put(metricName, name); this.names.put(metricName, name);
return name; return name;
} }
} }

View File

@ -1,59 +0,0 @@
/*
* 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.writer;
import java.io.Flushable;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.actuate.metrics.export.MetricCopyExporter;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* @author Dave Syer
*/
public class WriterUtils {
private static final Log logger = LogFactory.getLog(MetricCopyExporter.class);
public static void flush(MetricWriter writer) {
if (writer instanceof CompositeMetricWriter) {
for (MetricWriter element : (CompositeMetricWriter) writer) {
flush(element);
}
}
try {
if (ClassUtils.isPresent("java.io.Flushable", null)) {
if (writer instanceof Flushable) {
((Flushable) writer).flush();
return;
}
}
Method method = ReflectionUtils.findMethod(writer.getClass(), "flush");
if (method != null) {
ReflectionUtils.invokeMethod(method, writer);
}
}
catch (Exception e) {
logger.warn("Could not flush MetricWriter: " + e.getClass() + ": "
+ e.getMessage());
}
}
}

View File

@ -16,8 +16,6 @@
package org.springframework.boot.actuate.autoconfigure; package org.springframework.boot.actuate.autoconfigure;
import static org.junit.Assert.assertNotNull;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.mockito.Matchers; import org.mockito.Matchers;
@ -38,8 +36,10 @@ import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException; import org.springframework.messaging.MessagingException;
import org.springframework.messaging.SubscribableChannel; import org.springframework.messaging.SubscribableChannel;
import static org.junit.Assert.assertNotNull;
/** /**
* Tests for {@link MetricRepositoryAutoConfiguration}. * Tests for {@link MetricExportAutoConfiguration}.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Dave Syer * @author Dave Syer
@ -88,15 +88,15 @@ public class MetricExportAutoConfigurationTests {
@Test @Test
public void exportMetricsEndpoint() { public void exportMetricsEndpoint() {
this.context = new AnnotationConfigApplicationContext(WriterConfig.class, this.context = new AnnotationConfigApplicationContext(WriterConfig.class,
MetricEndpointConfiguration.class, MetricEndpointConfiguration.class, MetricExportAutoConfiguration.class,
MetricExportAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
MetricExporters exporters = this.context.getBean(MetricExporters.class); MetricExporters exporters = this.context.getBean(MetricExporters.class);
MetricCopyExporter exporter = (MetricCopyExporter) exporters.getExporters().get( MetricCopyExporter exporter = (MetricCopyExporter) exporters.getExporters().get(
"writer"); "writer");
exporter.setIgnoreTimestamps(true); exporter.setIgnoreTimestamps(true);
exporter.export(); exporter.export();
MetricsEndpointMetricReader reader = this.context.getBean("endpointReader", MetricsEndpointMetricReader.class); MetricsEndpointMetricReader reader = this.context.getBean("endpointReader",
MetricsEndpointMetricReader.class);
Mockito.verify(reader, Mockito.atLeastOnce()).findAll(); Mockito.verify(reader, Mockito.atLeastOnce()).findAll();
} }

View File

@ -16,12 +16,6 @@
package org.springframework.boot.actuate.autoconfigure; package org.springframework.boot.actuate.autoconfigure;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.actuate.metrics.CounterService; import org.springframework.boot.actuate.metrics.CounterService;
@ -39,6 +33,12 @@ import org.springframework.context.annotation.Configuration;
import com.codahale.metrics.Gauge; import com.codahale.metrics.Gauge;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
/** /**
* Tests for {@link MetricRepositoryAutoConfiguration}. * Tests for {@link MetricRepositoryAutoConfiguration}.
* *

View File

@ -27,6 +27,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
/** /**
* Tests for {@link AggregateMetricReader}.
*
* @author Dave Syer * @author Dave Syer
*/ */
public class AggregateMetricReaderTests { public class AggregateMetricReaderTests {

View File

@ -164,4 +164,5 @@ public class BufferGaugeServiceSpeedTests {
} }
watch.stop(); watch.stop();
} }
} }

View File

@ -61,4 +61,5 @@ public class CounterBuffersTests {
public void findNonExistent() { public void findNonExistent() {
assertNull(this.buffers.find("foo")); assertNull(this.buffers.find("foo"));
} }
} }

View File

@ -44,6 +44,7 @@ import static org.junit.Assert.assertEquals;
/** /**
* Speed tests for {@link CounterService}. * Speed tests for {@link CounterService}.
*
* @author Dave Syer * @author Dave Syer
*/ */
@RunWith(Theories.class) @RunWith(Theories.class)
@ -162,4 +163,5 @@ public class CounterServiceSpeedTests {
} }
watch.stop(); watch.stop();
} }
} }

View File

@ -126,4 +126,5 @@ public class DefaultGaugeServiceSpeedTests {
System.err.println("Read(" + count + ")=" + watch.getLastTaskTimeMillis() + "ms"); System.err.println("Read(" + count + ")=" + watch.getLastTaskTimeMillis() + "ms");
assertTrue(0 < total.longValue()); assertTrue(0 < total.longValue());
} }
} }

View File

@ -20,7 +20,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.actuate.metrics.dropwizard.DropwizardMetricServices;
import com.codahale.metrics.Gauge; import com.codahale.metrics.Gauge;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
@ -114,13 +113,15 @@ public class DropwizardMetricServicesTests {
} }
public static class WriterThread extends Thread { public static class WriterThread extends Thread {
private int index; private int index;
private boolean failed; private boolean failed;
private DropwizardMetricServices writer; private DropwizardMetricServices writer;
public WriterThread(ThreadGroup group, int index, DropwizardMetricServices writer) { public WriterThread(ThreadGroup group, int index, DropwizardMetricServices writer) {
super(group, "Writer-" + index); super(group, "Writer-" + index);
this.index = index; this.index = index;
this.writer = writer; this.writer = writer;
} }
@ -143,5 +144,7 @@ public class DropwizardMetricServicesTests {
} }
} }
} }
} }
} }

View File

@ -25,12 +25,16 @@ import org.springframework.boot.actuate.metrics.repository.InMemoryMetricReposit
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
/** /**
* Tests for {@link MetricCopyExporter}.
*
* @author Dave Syer * @author Dave Syer
*/ */
public class MetricCopyExporterTests { public class MetricCopyExporterTests {
private final InMemoryMetricRepository writer = new InMemoryMetricRepository(); private final InMemoryMetricRepository writer = new InMemoryMetricRepository();
private final InMemoryMetricRepository reader = new InMemoryMetricRepository(); private final InMemoryMetricRepository reader = new InMemoryMetricRepository();
private final MetricCopyExporter exporter = new MetricCopyExporter(this.reader, private final MetricCopyExporter exporter = new MetricCopyExporter(this.reader,
this.writer); this.writer);

View File

@ -29,14 +29,20 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
/** /**
* Tests for {@link MetricExporters}.
*
* @author Dave Syer * @author Dave Syer
*/ */
public class MetricExportersTests { public class MetricExportersTests {
private MetricExporters exporters; private MetricExporters exporters;
private MetricExportProperties export = new MetricExportProperties(); private MetricExportProperties export = new MetricExportProperties();
private Map<String, MetricWriter> writers = new LinkedHashMap<String, MetricWriter>(); private Map<String, MetricWriter> writers = new LinkedHashMap<String, MetricWriter>();
private MetricReader reader = Mockito.mock(MetricReader.class); private MetricReader reader = Mockito.mock(MetricReader.class);
private MetricWriter writer = Mockito.mock(MetricWriter.class); private MetricWriter writer = Mockito.mock(MetricWriter.class);
@Test @Test

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2013 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,12 +25,16 @@ import org.springframework.boot.actuate.metrics.rich.InMemoryRichGaugeRepository
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
/** /**
* Tests for {@link RichGaugeExporter}.
*
* @author Dave Syer * @author Dave Syer
*/ */
public class RichGaugeExporterTests { public class RichGaugeExporterTests {
private final InMemoryRichGaugeRepository reader = new InMemoryRichGaugeRepository(); private final InMemoryRichGaugeRepository reader = new InMemoryRichGaugeRepository();
private final InMemoryMetricRepository writer = new InMemoryMetricRepository(); private final InMemoryMetricRepository writer = new InMemoryMetricRepository();
private final RichGaugeExporter exporter = new RichGaugeExporter(this.reader, private final RichGaugeExporter exporter = new RichGaugeExporter(this.reader,
this.writer); this.writer);

View File

@ -1,6 +1,20 @@
package org.springframework.boot.actuate.metrics.integration; /*
* 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.
*/
import static org.junit.Assert.assertTrue; package org.springframework.boot.actuate.metrics.integration;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -17,22 +31,29 @@ import org.springframework.integration.monitor.IntegrationMBeanExporter;
import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertTrue;
/**
* Tests for {@link SpringIntegrationMetricReader}.
*
* @author Dave Syer
*/
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes=TestConfiguration.class) @SpringApplicationConfiguration(classes = TestConfiguration.class)
@IntegrationTest("spring.jmx.enabled=true") @IntegrationTest("spring.jmx.enabled=true")
@DirtiesContext @DirtiesContext
public class SpringIntegrationMetricReaderTests { public class SpringIntegrationMetricReaderTests {
@Autowired @Autowired
private SpringIntegrationMetricReader reader; private SpringIntegrationMetricReader reader;
@Test @Test
public void test() { public void test() {
assertTrue(reader.count()>0); assertTrue(this.reader.count() > 0);
} }
@Configuration @Configuration
@Import({JmxAutoConfiguration.class, IntegrationAutoConfiguration.class}) @Import({ JmxAutoConfiguration.class, IntegrationAutoConfiguration.class })
protected static class TestConfiguration { protected static class TestConfiguration {
@Bean @Bean
public SpringIntegrationMetricReader reader(IntegrationMBeanExporter exporter) { public SpringIntegrationMetricReader reader(IntegrationMBeanExporter exporter) {

View File

@ -23,6 +23,8 @@ import org.junit.Test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
/** /**
* Tests for {@link DefaultMetricNamingStrategy}.
*
* @author Dave Syer * @author Dave Syer
*/ */
public class DefaultMetricNamingStrategyTests { public class DefaultMetricNamingStrategyTests {

View File

@ -21,7 +21,6 @@ import java.util.Map;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Matchers;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -29,9 +28,13 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestOperations;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
/** /**
* Tests for {@link OpenTsdbMetricWriter}.
*
* @author Dave Syer * @author Dave Syer
*/ */
public class OpenTsdbMetricWriterTests { public class OpenTsdbMetricWriterTests {
@ -48,25 +51,19 @@ public class OpenTsdbMetricWriterTests {
@Test @Test
public void postSuccessfullyOnFlush() { public void postSuccessfullyOnFlush() {
this.writer.set(new Metric<Double>("foo", 2.4)); this.writer.set(new Metric<Double>("foo", 2.4));
given( given(this.restTemplate.postForEntity(anyString(), any(Object.class), anyMap()))
this.restTemplate.postForEntity(Matchers.anyString(),
Matchers.any(Object.class), anyMap()))
.willReturn(emptyResponse()); .willReturn(emptyResponse());
this.writer.flush(); this.writer.flush();
verify(this.restTemplate).postForEntity(Matchers.anyString(), verify(this.restTemplate).postForEntity(anyString(), any(Object.class), anyMap());
Matchers.any(Object.class), anyMap());
} }
@Test @Test
public void flushAutomaticlly() { public void flushAutomaticlly() {
given( given(this.restTemplate.postForEntity(anyString(), any(Object.class), anyMap()))
this.restTemplate.postForEntity(Matchers.anyString(),
Matchers.any(Object.class), anyMap()))
.willReturn(emptyResponse()); .willReturn(emptyResponse());
this.writer.setBufferSize(0); this.writer.setBufferSize(0);
this.writer.set(new Metric<Double>("foo", 2.4)); this.writer.set(new Metric<Double>("foo", 2.4));
verify(this.restTemplate).postForEntity(Matchers.anyString(), verify(this.restTemplate).postForEntity(anyString(), any(Object.class), anyMap());
Matchers.any(Object.class), anyMap());
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@ -76,7 +73,7 @@ public class OpenTsdbMetricWriterTests {
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
private Class<Map> anyMap() { private Class<Map> anyMap() {
return Matchers.any(Class.class); return any(Class.class);
} }
} }

View File

@ -99,6 +99,7 @@ public class StatsdMetricWriterTests {
private static final class DummyStatsDServer { private static final class DummyStatsDServer {
private final List<String> messagesReceived = new ArrayList<String>(); private final List<String> messagesReceived = new ArrayList<String>();
private final DatagramSocket server; private final DatagramSocket server;
public DummyStatsDServer(int port) { public DummyStatsDServer(int port) {
@ -141,5 +142,7 @@ public class StatsdMetricWriterTests {
public List<String> messagesReceived() { public List<String> messagesReceived() {
return new ArrayList<String>(this.messagesReceived); return new ArrayList<String>(this.messagesReceived);
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2013 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2013 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2013 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2014 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
Spring Boot sample with Redis export for metrics. = Spring Boot sample with Redis export for metrics.
Start redis, e.g. with [Docker Compose]() Start redis, e.g. with [Docker Compose]()

View File

@ -27,9 +27,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
/**
* @author Dave Syer
*/
@Configuration @Configuration
public class AggregateMetricsConfiguration { public class AggregateMetricsConfiguration {
@ -45,8 +42,8 @@ public class AggregateMetricsConfiguration {
} }
private MetricReader globalMetricsForAggregation() { private MetricReader globalMetricsForAggregation() {
return new RedisMetricRepository(this.connectionFactory, return new RedisMetricRepository(this.connectionFactory, this.export.getRedis()
this.export.getRedis().getAggregatePrefix(), this.export.getRedis().getKey()); .getAggregatePrefix(), this.export.getRedis().getKey());
} }
private MetricReader aggregatesMetricReader() { private MetricReader aggregatesMetricReader() {

View File

@ -42,8 +42,8 @@ public class SampleRedisExportApplication {
@ExportMetricWriter @ExportMetricWriter
public RedisMetricRepository redisMetricWriter( public RedisMetricRepository redisMetricWriter(
RedisConnectionFactory connectionFactory) { RedisConnectionFactory connectionFactory) {
return new RedisMetricRepository(connectionFactory, this.export.getRedis().getPrefix(), return new RedisMetricRepository(connectionFactory, this.export.getRedis()
this.export.getRedis().getKey()); .getPrefix(), this.export.getRedis().getKey());
} }
@Bean @Bean