Commit 5edc404a authored by Dave Syer's avatar Dave Syer Committed by Andy Wilkinson

Add support for includes and excludes patterns in MetricCopyExporter

Also rename Codahale* to Dropwizard* and move them to a new package
parent 53a61474
......@@ -63,22 +63,21 @@ import com.codahale.metrics.MetricRegistry;
* periodic basis) using an {@link Exporter}, most implementations of which have
* optimizations for sending data to remote repositories.
* <p>
* If Spring Messaging is on the classpath a {@link MessageChannel} called
* "metricsChannel" is also created (unless one already exists) and all metric update
* events are published additionally as messages on that channel. Additional analysis or
* actions can be taken by clients subscribing to that channel.
* If Spring Messaging is on the classpath and a {@link MessageChannel} called
* "metricsChannel" is also available, all metric update events are published additionally
* as messages on that channel. Additional analysis or actions can be taken by clients
* subscribing to that channel.
* <p>
* In addition if Codahale's metrics library is on the classpath a {@link MetricRegistry}
* will be created and wired up to the counter and gauge services in addition to the basic
* repository. Users can create Codahale metrics by prefixing their metric names with the
* appropriate type (e.g. "histogram.*", "meter.*") and sending them to the standard
* <code>GaugeService</code> or <code>CounterService</code>.
* In addition if Dropwizard's metrics library is on the classpath a
* {@link MetricRegistry} will be created and the default counter and gauge services will
* switch to using it instead of the default repository. Users can create "special"
* Dropwizard metrics by prefixing their metric names with the appropriate type (e.g.
* "histogram.*", "meter.*". "timer.*") and sending them to the <code>GaugeService</code>
* or <code>CounterService</code>.
* <p>
* By default all metric updates go to all {@link MetricWriter} instances in the
* application context. To change this behaviour define your own metric writer bean called
* "primaryMetricWriter", mark it <code>@Primary</code>, and this one will receive all
* updates from the default counter and gauge services. Alternatively you can provide your
* own counter and gauge services and wire them to whichever writer you choose.
* application context via a {@link MetricCopyExporter} firing every 5 seconds (disable
* this by setting <code>spring.metrics.export.enabled=false</code>).
*
* @see GaugeService
* @see CounterService
......
......@@ -20,8 +20,8 @@ import org.springframework.boot.actuate.endpoint.MetricReaderPublicMetrics;
import org.springframework.boot.actuate.endpoint.PublicMetrics;
import org.springframework.boot.actuate.metrics.CounterService;
import org.springframework.boot.actuate.metrics.GaugeService;
import org.springframework.boot.actuate.metrics.dropwizard.DropwizardMetricServices;
import org.springframework.boot.actuate.metrics.reader.MetricRegistryMetricReader;
import org.springframework.boot.actuate.metrics.writer.DropwizardMetricServices;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
......
......@@ -56,21 +56,21 @@ public class MetricsMvcEndpoint extends EndpointMvcAdapter {
/**
* {@link NamePatternFilter} for the Map source.
*/
private class NamePatternMapFilter extends NamePatternFilter<Map<String, Object>> {
private class NamePatternMapFilter extends NamePatternFilter<Map<String, ?>> {
public NamePatternMapFilter(Map<String, Object> source) {
public NamePatternMapFilter(Map<String, ?> source) {
super(source);
}
@Override
protected void getNames(Map<String, Object> source, NameCallback callback) {
protected void getNames(Map<String, ?> source, NameCallback callback) {
for (String name : source.keySet()) {
callback.addName(name);
}
}
@Override
protected Object getValue(Map<String, Object> source, String name) {
protected Object getValue(Map<String, ?> source, String name) {
Object value = source.get(name);
if (value == null) {
throw new NoSuchMetricException("No such metric: " + name);
......
/*
* 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");
* you may not use this file except in compliance with the License.
......@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.metrics.writer;
package org.springframework.boot.actuate.metrics.dropwizard;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
......
/*
* 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.
*/
/**
* Metrics integration with Dropwizard Metrics.
*/
package org.springframework.boot.actuate.metrics.dropwizard;
/*
* 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");
* you may not use this file except in compliance with the License.
......@@ -17,10 +17,12 @@
package org.springframework.boot.actuate.metrics.export;
import java.util.Collection;
import java.util.Iterator;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.reader.MetricReader;
import org.springframework.boot.actuate.metrics.writer.MetricWriter;
import org.springframework.util.PatternMatchUtils;
/**
* {@link Exporter} that "exports" by copying metric data from a source
......@@ -34,10 +36,22 @@ public class MetricCopyExporter extends AbstractMetricExporter {
private final MetricWriter writer;
private String[] includes = new String[0];
private String[] excludes = new String[0];
public MetricCopyExporter(MetricReader reader, MetricWriter writer) {
this(reader, writer, "");
}
public void setIncludes(String... includes) {
this.includes = includes;
}
public void setExcludes(String... excludes) {
this.excludes = excludes;
}
public MetricCopyExporter(MetricReader reader, MetricWriter writer, String prefix) {
super(prefix);
this.reader = reader;
......@@ -46,7 +60,16 @@ public class MetricCopyExporter extends AbstractMetricExporter {
@Override
protected Iterable<Metric<?>> next(String group) {
return this.reader.findAll();
if (this.includes.length == 0 && this.excludes.length == 0) {
return this.reader.findAll();
}
return new Iterable<Metric<?>>() {
@Override
public Iterator<Metric<?>> iterator() {
return new PatternMatchingIterator(MetricCopyExporter.this.reader
.findAll().iterator());
}
};
}
@Override
......@@ -56,4 +79,56 @@ public class MetricCopyExporter extends AbstractMetricExporter {
}
}
private class PatternMatchingIterator implements Iterator<Metric<?>> {
private Metric<?> buffer = null;
private Iterator<Metric<?>> iterator;
public PatternMatchingIterator(Iterator<Metric<?>> iterator) {
this.iterator = iterator;
}
@Override
public boolean hasNext() {
if (this.buffer != null) {
return true;
}
this.buffer = findNext();
return this.buffer != null;
}
private Metric<?> findNext() {
Metric<?> metric = null;
boolean matched = false;
while (this.iterator.hasNext() && !matched) {
metric = this.iterator.next();
if (MetricCopyExporter.this.includes.length == 0) {
matched = true;
}
else {
for (String pattern : MetricCopyExporter.this.includes) {
if (PatternMatchUtils.simpleMatch(pattern, metric.getName())) {
matched = true;
break;
}
}
}
for (String pattern : MetricCopyExporter.this.excludes) {
if (PatternMatchUtils.simpleMatch(pattern, metric.getName())) {
matched = false;
break;
}
}
}
return matched ? metric : null;
}
@Override
public Metric<?> next() {
Metric<?> metric = this.buffer;
this.buffer = null;
return metric;
}
};
}
......@@ -15,7 +15,7 @@
*/
/**
* Metrics integration with Dropwizard Metrics.
* Support for writing metrics
*/
package org.springframework.boot.actuate.metrics.writer;
......@@ -25,10 +25,10 @@ import org.springframework.boot.actuate.metrics.GaugeService;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.buffer.BufferCounterService;
import org.springframework.boot.actuate.metrics.buffer.BufferGaugeService;
import org.springframework.boot.actuate.metrics.dropwizard.DropwizardMetricServices;
import org.springframework.boot.actuate.metrics.export.MetricCopyExporter;
import org.springframework.boot.actuate.metrics.reader.MetricReader;
import org.springframework.boot.actuate.metrics.reader.PrefixMetricReader;
import org.springframework.boot.actuate.metrics.writer.DropwizardMetricServices;
import org.springframework.boot.actuate.metrics.writer.MetricWriter;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.aop.AopAutoConfiguration;
......
......@@ -34,9 +34,9 @@ import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
import org.springframework.boot.actuate.metrics.CounterService;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.dropwizard.DropwizardMetricServices;
import org.springframework.boot.actuate.metrics.reader.MetricReader;
import org.springframework.boot.actuate.metrics.reader.MetricRegistryMetricReader;
import org.springframework.boot.actuate.metrics.writer.DropwizardMetricServices;
import org.springframework.lang.UsesJava8;
import org.springframework.util.StopWatch;
......
......@@ -14,12 +14,13 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.metrics.writer;
package org.springframework.boot.actuate.metrics.dropwizard;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.springframework.boot.actuate.metrics.dropwizard.DropwizardMetricServices;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.MetricRegistry;
......
/*
* 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");
* you may not use this file except in compliance with the License.
......@@ -41,6 +41,33 @@ public class MetricCopyExporterTests {
assertEquals(1, this.writer.count());
}
@Test
public void exportIncludes() {
this.exporter.setIncludes("*");
this.reader.set(new Metric<Number>("foo", 2.3));
this.exporter.export();
assertEquals(1, this.writer.count());
}
@Test
public void exportExcludesWithIncludes() {
this.exporter.setIncludes("*");
this.exporter.setExcludes("foo");
this.reader.set(new Metric<Number>("foo", 2.3));
this.reader.set(new Metric<Number>("bar", 2.4));
this.exporter.export();
assertEquals(1, this.writer.count());
}
@Test
public void exportExcludesDefaultIncludes() {
this.exporter.setExcludes("foo");
this.reader.set(new Metric<Number>("foo", 2.3));
this.reader.set(new Metric<Number>("bar", 2.4));
this.exporter.export();
assertEquals(1, this.writer.count());
}
@Test
public void timestamp() {
this.reader.set(new Metric<Number>("foo", 2.3));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment