Add support for metric export to OpenTSDB

pull/2938/merge
Dave Syer 10 years ago committed by Andy Wilkinson
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,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…
Cancel
Save