Add support for metric export to OpenTSDB
This commit is contained in:
parent
18928a62df
commit
60a4943520
|
|
@ -134,6 +134,7 @@ public class MetricRepositoryAutoConfiguration {
|
|||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ConditionalOnMissingBean
|
||||
public BufferMetricReader metricReader(CounterBuffers counters,
|
||||
GaugeBuffers gauges) {
|
||||
|
|
@ -181,7 +182,7 @@ public class MetricRepositoryAutoConfiguration {
|
|||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnBean(MetricWriter.class)
|
||||
public MetricCopyExporter messageChannelMetricExporter(MetricReader reader) {
|
||||
public MetricCopyExporter metricWritersMetricExporter(MetricReader reader) {
|
||||
List<MetricWriter> writers = new ArrayList<MetricWriter>(this.writers);
|
||||
if (this.actuatorMetricRepository != null
|
||||
&& writers.contains(this.actuatorMetricRepository)) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import java.util.Collections;
|
|||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
|
@ -34,6 +36,8 @@ import org.springframework.util.StringUtils;
|
|||
*/
|
||||
public abstract class AbstractMetricExporter implements Exporter {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AbstractMetricExporter.class);
|
||||
|
||||
private volatile AtomicBoolean processing = new AtomicBoolean(false);
|
||||
|
||||
private Date earliestTimestamp = new Date();
|
||||
|
|
@ -86,11 +90,25 @@ public abstract class AbstractMetricExporter implements Exporter {
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("Could not write to MetricWriter: " + e.getClass() + ": "
|
||||
+ e.getMessage());
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
flush();
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("Could not flush MetricWriter: " + e.getClass() + ": "
|
||||
+ e.getMessage());
|
||||
}
|
||||
this.processing.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a group of metrics to iterate over in the form of a set of Strings (e.g.
|
||||
* prefixes). If the metrics to be exported partition into groups identified by a
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ 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.boot.actuate.metrics.writer.WriterUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
|
|
@ -79,6 +80,11 @@ public class MetricCopyExporter extends AbstractMetricExporter {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
WriterUtils.flush(this.writer);
|
||||
}
|
||||
|
||||
private class PatternMatchingIterator implements Iterator<Metric<?>> {
|
||||
|
||||
private Metric<?> buffer = null;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.opentsdb;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A naming strategy that just passes through the metric name, together with tags from a
|
||||
* set of static values. Open TSDB requires at least one tag, so one is always added for
|
||||
* you: the {@value #PREFIX_KEY} key is added with a unique value "spring.X" where X is an
|
||||
* object hash code ID for this (the naming stategy). In most cases this will be unique
|
||||
* enough to allow aggregation of the underlying metrics in Open TSDB, but normally it is
|
||||
* best to provide your own tags, including a prefix if you know one (overwriting the
|
||||
* default).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class DefaultOpenTsdbNamingStrategy implements OpenTsdbNamingStrategy {
|
||||
|
||||
public static final String PREFIX_KEY = "prefix";
|
||||
|
||||
/**
|
||||
* Tags to apply to every metric. Open TSDB requires at least one tag, so a "prefix"
|
||||
* tag is added for you by default.
|
||||
*/
|
||||
private Map<String, String> tags = new LinkedHashMap<String, String>();
|
||||
|
||||
private Map<String, OpenTsdbName> cache = new HashMap<String, OpenTsdbName>();
|
||||
|
||||
public DefaultOpenTsdbNamingStrategy() {
|
||||
this.tags.put(PREFIX_KEY,
|
||||
"spring." + ObjectUtils.getIdentityHexString(this));
|
||||
}
|
||||
|
||||
public void setTags(Map<String, String> staticTags) {
|
||||
this.tags.putAll(staticTags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenTsdbName getName(String name) {
|
||||
if (this.cache.containsKey(name)) {
|
||||
return this.cache.get(name);
|
||||
}
|
||||
OpenTsdbName value = new OpenTsdbName(name);
|
||||
value.setTags(this.tags);
|
||||
this.cache.put(name, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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.opentsdb;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class OpenTsdbData {
|
||||
|
||||
private OpenTsdbName name;
|
||||
|
||||
private Long timestamp;
|
||||
|
||||
private Number value;
|
||||
|
||||
protected OpenTsdbData() {
|
||||
this.name = new OpenTsdbName();
|
||||
}
|
||||
|
||||
public OpenTsdbData(String metric, Number value) {
|
||||
this(metric, value, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public OpenTsdbData(String metric, Number value, Long timestamp) {
|
||||
this(new OpenTsdbName(metric), value, timestamp);
|
||||
}
|
||||
|
||||
public OpenTsdbData(OpenTsdbName name, Number value, Long timestamp) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getMetric() {
|
||||
return this.name.getMetric();
|
||||
}
|
||||
|
||||
public void setMetric(String metric) {
|
||||
this.name.setMetric(metric);
|
||||
}
|
||||
|
||||
public Long getTimestamp() {
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(Long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public Number getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setValue(Number value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Map<String, String> getTags() {
|
||||
return this.name.getTags();
|
||||
}
|
||||
|
||||
public void setTags(Map<String, String> tags) {
|
||||
this.name.setTags(tags);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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.opentsdb;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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.writer.Delta;
|
||||
import org.springframework.boot.actuate.metrics.writer.MetricWriter;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* A {@link MetricWriter} for the Open TSDB database (version 2.0), writing metrics to the
|
||||
* HTTP endpoint provided by the server. Data are buffered according to the
|
||||
* {@link #setBufferSize(int) bufferSize} property, and only flushed automatically when
|
||||
* the buffer size is reached. Users should either manually {@link #flush()} after writing
|
||||
* a batch of data if that makes sense, or consider adding a {@link Scheduled
|
||||
* <code>@Scheduled</code>} task to flush periodically.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class OpenTsdbHttpMetricWriter implements MetricWriter {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(OpenTsdbHttpMetricWriter.class);
|
||||
|
||||
private RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
/**
|
||||
* URL for POSTing data. Defaults to http://localhost:4242/api/put.
|
||||
*/
|
||||
private String url = "http://localhost:4242/api/put";
|
||||
|
||||
/**
|
||||
* Buffer size to fill before posting data to server.
|
||||
*/
|
||||
private int bufferSize = 64;
|
||||
|
||||
/**
|
||||
* The media type to use to serialize and accept responses from the server. Defaults
|
||||
* to "application/json".
|
||||
*/
|
||||
private MediaType mediaType = MediaType.APPLICATION_JSON;
|
||||
|
||||
private List<OpenTsdbData> buffer = new ArrayList<OpenTsdbData>(this.bufferSize);
|
||||
|
||||
private OpenTsdbNamingStrategy namingStrategy = new DefaultOpenTsdbNamingStrategy();
|
||||
|
||||
public RestTemplate getRestTemplate() {
|
||||
return this.restTemplate;
|
||||
}
|
||||
|
||||
public void setRestTemplate(RestTemplate restTemplate) {
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public void setBufferSize(int bufferSize) {
|
||||
this.bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void setMediaType(MediaType mediaType) {
|
||||
this.mediaType = mediaType;
|
||||
}
|
||||
|
||||
public void setNamingStrategy(OpenTsdbNamingStrategy namingStrategy) {
|
||||
this.namingStrategy = namingStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increment(Delta<?> delta) {
|
||||
throw new UnsupportedOperationException("Counters not supported via increment");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Metric<?> value) {
|
||||
OpenTsdbData data = new OpenTsdbData(
|
||||
this.namingStrategy.getName(value.getName()), value.getValue(), value
|
||||
.getTimestamp().getTime());
|
||||
this.buffer.add(data);
|
||||
if (this.buffer.size() >= this.bufferSize) {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the buffer without waiting for it to fill any further.
|
||||
*/
|
||||
public void flush() {
|
||||
if (this.buffer.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<OpenTsdbData> temp = new ArrayList<OpenTsdbData>();
|
||||
synchronized (this.buffer) {
|
||||
temp.addAll(this.buffer);
|
||||
this.buffer.clear();
|
||||
}
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(this.mediaType));
|
||||
headers.setContentType(this.mediaType);
|
||||
HttpEntity<List<OpenTsdbData>> request = new HttpEntity<List<OpenTsdbData>>(temp,
|
||||
headers);
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> response = this.restTemplate.postForEntity(this.url, request,
|
||||
Map.class);
|
||||
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||
logger.warn("Cannot write metrics (discarded " + temp.size() + " values): "
|
||||
+ response.getBody());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(String metricName) {
|
||||
set(new Metric<Long>(metricName, 0L));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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.opentsdb;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class OpenTsdbName {
|
||||
|
||||
private String metric;
|
||||
|
||||
private Map<String, String> tags = new LinkedHashMap<String, String>();
|
||||
|
||||
protected OpenTsdbName() {
|
||||
}
|
||||
|
||||
public OpenTsdbName(String metric) {
|
||||
this.metric = metric;
|
||||
}
|
||||
|
||||
public String getMetric() {
|
||||
return this.metric;
|
||||
}
|
||||
|
||||
public void setMetric(String metric) {
|
||||
this.metric = metric;
|
||||
}
|
||||
|
||||
public Map<String, String> getTags() {
|
||||
return this.tags;
|
||||
}
|
||||
|
||||
public void setTags(Map<String, String> tags) {
|
||||
this.tags.putAll(tags);
|
||||
}
|
||||
|
||||
public void tag(String name, String value) {
|
||||
this.tags.put(name, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.opentsdb;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public interface OpenTsdbNamingStrategy {
|
||||
|
||||
OpenTsdbName getName(String metricName);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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 OpenTSDB.
|
||||
*/
|
||||
package org.springframework.boot.actuate.metrics.opentsdb;
|
||||
|
||||
|
|
@ -18,6 +18,7 @@ package org.springframework.boot.actuate.metrics.writer;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
|
|
@ -28,7 +29,7 @@ import org.springframework.boot.actuate.metrics.Metric;
|
|||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class CompositeMetricWriter implements MetricWriter {
|
||||
public class CompositeMetricWriter implements MetricWriter, Iterable<MetricWriter> {
|
||||
|
||||
private final List<MetricWriter> writers = new ArrayList<MetricWriter>();
|
||||
|
||||
|
|
@ -40,6 +41,11 @@ public class CompositeMetricWriter implements MetricWriter {
|
|||
this.writers.addAll(writers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<MetricWriter> iterator() {
|
||||
return this.writers.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increment(Delta<?> delta) {
|
||||
for (MetricWriter writer : this.writers) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -957,6 +957,38 @@ MetricWriter metricWriter() {
|
|||
|
||||
|
||||
|
||||
[[production-ready-metric-writers-export-to-open-tdsb]]
|
||||
==== Example: Export to Open TSDB
|
||||
If you provide a `@Bean` of type `OpenTsdbHttpMetricWriter` the metrics are exported to
|
||||
http://opentsdb.net/[Open TSDB] for aggregation. The `OpenTsdbHttpMetricWriter` has a
|
||||
`url` property that you need to set to the Open TSDB "/put" endpoint, e.g.
|
||||
`http://localhost:4242/api/put`). It also has a `namingStrategy` that you can customize
|
||||
or configure to make the metrics match the data structure you need on the server. By
|
||||
default it just passes through the metric name as an Open TSDB metric name and adds a tag
|
||||
"prefix" with value "spring.X" where "X" is the object hash of the default naming
|
||||
strategy. Thus, after running the application and generating some metrics (e.g. by pinging
|
||||
the home page) you can inspect the metrics in the TDB UI (http://localhost:4242 by
|
||||
default). Example:
|
||||
|
||||
----
|
||||
curl localhost:4242/api/query?start=1h-ago&m=max:counter.status.200.root
|
||||
[
|
||||
{
|
||||
"metric": "counter.status.200.root",
|
||||
"tags": {
|
||||
"prefix": "spring.b968a76"
|
||||
},
|
||||
"aggregateTags": [],
|
||||
"dps": {
|
||||
"1430492872": 2,
|
||||
"1430492875": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
----
|
||||
|
||||
|
||||
|
||||
[[production-ready-metric-writers-export-to-statsd]]
|
||||
==== Example: Export to Statsd
|
||||
If you provide a `@Bean` of type `StatsdMetricWriter` the metrics are exported to a
|
||||
|
|
@ -975,7 +1007,7 @@ private int port;
|
|||
|
||||
@Bean
|
||||
MetricWriter metricWriter() {
|
||||
return new StatsdMetricWriter(prefix, host, port);
|
||||
return new StatsdMetricWriter(prefix, host, port);
|
||||
}
|
||||
----
|
||||
|
||||
|
|
@ -991,7 +1023,7 @@ tool that understands JMX (e.g. JConsole or JVisualVM). Example:
|
|||
----
|
||||
@Bean
|
||||
MetricWriter metricWriter(MBeanExporter exporter) {
|
||||
return new JmxMetricWriter(exporter);
|
||||
return new JmxMetricWriter(exporter);
|
||||
}
|
||||
----
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
<module>spring-boot-sample-jta-bitronix</module>
|
||||
<module>spring-boot-sample-jta-jndi</module>
|
||||
<module>spring-boot-sample-liquibase</module>
|
||||
<module>spring-boot-sample-metrics-opentsdb</module>
|
||||
<module>spring-boot-sample-metrics-redis</module>
|
||||
<module>spring-boot-sample-parent-context</module>
|
||||
<module>spring-boot-sample-profile</module>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
Spring Boot sample with Open TSDB export for metrics.
|
||||
|
||||
Start opentsdb, e.g. with [Docker Compose]()
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
$ docker-compose up
|
||||
----
|
||||
|
||||
Run the app and ping the home page (http://localhost:8080) a few times. Go and look at
|
||||
the result in the TDB UI, e.g.
|
||||
|
||||
[source,indent=0]
|
||||
----
|
||||
$ curl localhost:4242/api/query?start=1h-ago&m=max:counter.status.200.root
|
||||
[
|
||||
{
|
||||
"metric": "counter.status.200.root",
|
||||
"tags": {
|
||||
"prefix": "spring.b968a76"
|
||||
},
|
||||
"aggregateTags": [],
|
||||
"dps": {
|
||||
"1430492872": 2,
|
||||
"1430492875": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
----
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
opentsdb:
|
||||
image: lancope/opentsdb
|
||||
ports:
|
||||
- "4242:4242"
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-samples</artifactId>
|
||||
<version>1.3.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-sample-metrics-opentsdb</artifactId>
|
||||
<name>spring-boot-sample-metrics-opentsdb</name>
|
||||
<description>Spring Boot Actuator Sample</description>
|
||||
<url>http://projects.spring.io/spring-boot/</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>http://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2012-2013 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 sample.metrics.opentsdb;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "service", ignoreUnknownFields = false)
|
||||
public class HelloWorldService {
|
||||
|
||||
private String name = "World";
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getHelloMessage() {
|
||||
return "Hello " + this.name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2012-2013 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 sample.metrics.opentsdb;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Description;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@Description("A controller for handling requests for hello messages")
|
||||
public class SampleController {
|
||||
|
||||
@Autowired
|
||||
private HelloWorldService helloWorldService;
|
||||
|
||||
@RequestMapping(value = "/", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Map<String, String> hello() {
|
||||
return Collections.singletonMap("message",
|
||||
this.helloWorldService.getHelloMessage());
|
||||
}
|
||||
|
||||
protected static class Message {
|
||||
|
||||
@NotBlank(message = "Message value cannot be empty")
|
||||
private String value;
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2012-2013 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 sample.metrics.opentsdb;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.actuate.metrics.opentsdb.DefaultOpenTsdbNamingStrategy;
|
||||
import org.springframework.boot.actuate.metrics.opentsdb.OpenTsdbHttpMetricWriter;
|
||||
import org.springframework.boot.actuate.metrics.opentsdb.OpenTsdbNamingStrategy;
|
||||
import org.springframework.boot.actuate.metrics.writer.MetricWriter;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SampleOpenTsdbExportApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(SampleOpenTsdbExportApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("metrics.export")
|
||||
public MetricWriter openTsdbMetricWriter() {
|
||||
OpenTsdbHttpMetricWriter writer = new OpenTsdbHttpMetricWriter();
|
||||
writer.setNamingStrategy(namingStrategy());
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("metrics.names")
|
||||
public OpenTsdbNamingStrategy namingStrategy() {
|
||||
return new DefaultOpenTsdbNamingStrategy();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
service.name: Phil
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2012-2014 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 sample.metrics.opentsdb;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
||||
/**
|
||||
* Basic integration tests for {@link SampleOpenTsdbExportApplication}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = SampleOpenTsdbExportApplication.class)
|
||||
@WebAppConfiguration
|
||||
@IntegrationTest("server.port=0")
|
||||
@DirtiesContext
|
||||
public class SampleOpenTsdbExportApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue