diff --git a/spring-cloud-stream-metrics/pom.xml b/spring-cloud-stream-metrics/pom.xml
index 037b3410f..115e6b2fa 100644
--- a/spring-cloud-stream-metrics/pom.xml
+++ b/spring-cloud-stream-metrics/pom.xml
@@ -29,6 +29,11 @@
spring-cloud-stream-test-support
test
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
diff --git a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/config/metrics/StreamMetricsProperties.java b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/config/metrics/StreamMetricsProperties.java
deleted file mode 100644
index 7becb0f37..000000000
--- a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/config/metrics/StreamMetricsProperties.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2017 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.cloud.stream.config.metrics;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.util.StringUtils;
-
-/**
- * @author Vinicius Carvalho
- */
-@ConfigurationProperties(prefix = "spring.cloud.stream.metrics")
-public class StreamMetricsProperties {
-
- private String prefix;
-
- @Value("${spring.application.name:${vcap.application.name:${spring.config.name:application}}}")
- private String key;
-
- private String metricName;
-
- private String[] includes = new String[] { "integration**" };
-
- private String[] excludes;
-
- private String[] properties;
-
- private Long delayMillis;
-
- public String[] getIncludes() {
- return includes;
- }
-
- public void setIncludes(String[] includes) {
- this.includes = includes;
- }
-
- public String[] getExcludes() {
- return excludes;
- }
-
- public void setExcludes(String[] excludes) {
- this.excludes = excludes;
- }
-
- public Long getDelayMillis() {
- return delayMillis;
- }
-
- public void setDelayMillis(Long delayMillis) {
- this.delayMillis = delayMillis;
- }
-
- public String getPrefix() {
- return prefix;
- }
-
- public void setPrefix(String prefix) {
- this.prefix = prefix;
- }
-
- public String getKey() {
- return key;
- }
-
- public void setKey(String key) {
- this.key = key;
- }
-
- public String[] getProperties() {
- return properties;
- }
-
- public void setProperties(String[] properties) {
- this.properties = properties;
- }
-
- public String getMetricName() {
- if (this.metricName == null) {
- this.metricName = resolveMetricName();
- }
- return metricName;
- }
-
- private String resolveMetricName() {
- StringBuffer name = new StringBuffer(this.key);
- if (!StringUtils.isEmpty(this.prefix)) {
- String prefix = this.prefix;
- if (prefix.lastIndexOf(".") == -1) {
- prefix += ".";
- }
- name.insert(0, prefix);
- }
- return name.toString();
- }
-}
diff --git a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/ApplicationMetrics.java b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/ApplicationMetrics.java
index 646364d40..97ea7cbd2 100644
--- a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/ApplicationMetrics.java
+++ b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/ApplicationMetrics.java
@@ -38,13 +38,14 @@ public class ApplicationMetrics {
private int instanceIndex;
- private Collection metrics;
+ private Collection> metrics;
private Map properties;
@JsonCreator
- public ApplicationMetrics(@JsonProperty("name") String name, @JsonProperty("instanceIndex") int instanceIndex,
- @JsonProperty("metrics") Collection metrics) {
+ public ApplicationMetrics(@JsonProperty("name") String name,
+ @JsonProperty("instanceIndex") int instanceIndex,
+ @JsonProperty("metrics") Collection> metrics) {
this.name = name;
this.instanceIndex = instanceIndex;
this.metrics = metrics;
@@ -67,11 +68,11 @@ public class ApplicationMetrics {
this.instanceIndex = instanceIndex;
}
- public Collection getMetrics() {
+ public Collection> getMetrics() {
return metrics;
}
- public void setMetrics(Collection metrics) {
+ public void setMetrics(Collection> metrics) {
this.metrics = metrics;
}
diff --git a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/ApplicationMetricsExporter.java b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/ApplicationMetricsExporter.java
new file mode 100644
index 000000000..8a2b8f39f
--- /dev/null
+++ b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/ApplicationMetricsExporter.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2017 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.cloud.stream.metrics;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
+import org.springframework.boot.actuate.endpoint.MetricsEndpointMetricReader;
+import org.springframework.boot.actuate.metrics.Metric;
+import org.springframework.boot.actuate.metrics.export.Exporter;
+import org.springframework.boot.actuate.metrics.export.MetricCopyExporter;
+import org.springframework.integration.support.MessageBuilder;
+import org.springframework.messaging.MessageChannel;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.PatternMatchUtils;
+
+/**
+ *
+ * Component that sends {@link ApplicationMetrics} from
+ * {@link MetricsEndpointMetricReader} downstream via the configured metrics channel.
+ *
+ * It uses the Spring Boot support for {@link Exporter} to periodically emit messages
+ * polled from the endpoint.
+ *
+ * @author Vinicius Carvalho
+ */
+public class ApplicationMetricsExporter implements Exporter {
+
+ private MessageChannel source;
+
+ private ApplicationMetricsProperties properties;
+
+ private MetricsEndpointMetricReader metricsReader;
+
+ public ApplicationMetricsExporter(MetricsEndpoint endpoint, MessageChannel source,
+ ApplicationMetricsProperties properties) {
+ this.source = source;
+ this.properties = properties;
+ this.metricsReader = new MetricsEndpointMetricReader(endpoint);
+ }
+
+ @Override
+ public void export() {
+ ApplicationMetrics appMetrics = new ApplicationMetrics(
+ this.properties.getMetricName(), this.properties.getInstanceIndex(),
+ filter());
+ appMetrics.setProperties(this.properties.getExportProperties());
+ source.send(MessageBuilder.withPayload(appMetrics).build());
+ }
+
+ /**
+ * Copy of similarly named method in {@link MetricCopyExporter}.
+ */
+ protected Collection> filter() {
+ Collection> result = new ArrayList<>();
+ Iterable> metrics = metricsReader.findAll();
+ for (Metric> metric : metrics) {
+ if (isMatch(metric.getName(), this.properties.getTrigger().getIncludes(),
+ this.properties.getTrigger().getExcludes())) {
+ result.add(metric);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copy of similarly named method in {@link MetricCopyExporter}.
+ */
+ private boolean isMatch(String name, String[] includes, String[] excludes) {
+ if (ObjectUtils.isEmpty(includes)
+ || PatternMatchUtils.simpleMatch(includes, name)) {
+ return !PatternMatchUtils.simpleMatch(excludes, name);
+ }
+ return false;
+ }
+
+}
diff --git a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/ApplicationMetricsProperties.java b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/ApplicationMetricsProperties.java
new file mode 100644
index 000000000..59139ce7a
--- /dev/null
+++ b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/ApplicationMetricsProperties.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2017 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.cloud.stream.metrics;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.actuate.metrics.export.MetricExportProperties;
+import org.springframework.boot.actuate.metrics.export.TriggerProperties;
+import org.springframework.boot.bind.RelaxedNames;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.core.env.EnumerablePropertySource;
+import org.springframework.core.env.PropertySource;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.PatternMatchUtils;
+
+/**
+ * @author Vinicius Carvalho
+ */
+@ConfigurationProperties(prefix = "spring.cloud.stream.metrics")
+public class ApplicationMetricsProperties
+ implements ApplicationListener {
+
+ private String prefix = "";
+
+ @Value("${spring.application.name:${vcap.application.name:${spring.config.name:application}}}")
+ private String key;
+
+ @Value("${INSTANCE_INDEX:${CF_INSTANCE_INDEX:0}}")
+ private int instanceIndex;
+
+ private String metricName;
+
+ private String[] properties;
+
+ private MetricExportProperties export;
+
+ public TriggerProperties getTrigger() {
+ return export.findTrigger("application");
+ }
+
+ public ApplicationMetricsProperties(MetricExportProperties export) {
+ this.export = export;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public void setPrefix(String prefix) {
+ if (!prefix.endsWith(".")) {
+ prefix += ".";
+ }
+ this.prefix = prefix;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public int getInstanceIndex() {
+ return instanceIndex;
+ }
+
+ public void setInstanceIndex(int instanceIndex) {
+ this.instanceIndex = instanceIndex;
+ }
+
+ public String[] getProperties() {
+ return properties;
+ }
+
+ public void setProperties(String[] properties) {
+ this.properties = properties;
+ }
+
+ /**
+ * List of properties that are going to be appended to each message. This gets
+ * populate by onApplicationEvent, once the context refreshes to avoid overhead of
+ * doing per message basis.
+ */
+ private Map exportProperties = new HashMap<>();
+
+ public Map getExportProperties() {
+ return exportProperties;
+ }
+
+ public String getMetricName() {
+ if (this.metricName == null) {
+ this.metricName = resolveMetricName();
+ }
+ return metricName;
+ }
+
+ private String resolveMetricName() {
+ return this.prefix + this.key;
+ }
+
+ /**
+ * Iterates over all property sources from this application context and copies the
+ * ones listed in {@link ApplicationMetricsProperties} includes.
+ */
+ @Override
+ public void onApplicationEvent(ContextRefreshedEvent event) {
+ ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) event
+ .getSource();
+ if (!ObjectUtils.isEmpty(this.properties)) {
+ for (PropertySource> source : ctx.getEnvironment().getPropertySources()) {
+ if (source instanceof EnumerablePropertySource) {
+ EnumerablePropertySource> e = (EnumerablePropertySource>) source;
+ for (String propertyName : e.getPropertyNames()) {
+ RelaxedNames relaxedNames = new RelaxedNames(propertyName);
+ relaxedLoop: for (String relaxedPropertyName : relaxedNames) {
+ if (isMatch(relaxedPropertyName, this.properties, null)) {
+ this.exportProperties.put(
+ RelaxedPropertiesUtils
+ .findCanonicalFormat(relaxedNames),
+ source.getProperty(propertyName));
+ break relaxedLoop;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private boolean isMatch(String name, String[] includes, String[] excludes) {
+ if (ObjectUtils.isEmpty(includes)
+ || PatternMatchUtils.simpleMatch(includes, name)) {
+ return !PatternMatchUtils.simpleMatch(excludes, name);
+ }
+ return false;
+ }
+
+}
diff --git a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/BinderMetricsEmitter.java b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/BinderMetricsEmitter.java
deleted file mode 100644
index 516302002..000000000
--- a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/BinderMetricsEmitter.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2017 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.cloud.stream.metrics;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
-import org.springframework.boot.actuate.endpoint.MetricsEndpointMetricReader;
-import org.springframework.boot.actuate.metrics.Metric;
-import org.springframework.boot.actuate.metrics.export.MetricCopyExporter;
-import org.springframework.boot.bind.RelaxedNames;
-import org.springframework.cloud.stream.config.BindingServiceProperties;
-import org.springframework.cloud.stream.config.metrics.StreamMetricsProperties;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.ApplicationListener;
-import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.context.event.ContextRefreshedEvent;
-import org.springframework.core.env.EnumerablePropertySource;
-import org.springframework.core.env.PropertySource;
-import org.springframework.integration.support.MessageBuilder;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.util.ObjectUtils;
-import org.springframework.util.PatternMatchUtils;
-
-/**
- *
- * Component that sends metrics from {@link MetricsEndpointMetricReader} downstream via
- * the configured metrics channel.
- *
- * It uses {@link Scheduled} support to periodially emit messages polled from the
- * endpoint.
- *
- * @author Vinicius Carvalho
- */
-public class BinderMetricsEmitter implements ApplicationListener, ApplicationContextAware {
-
- @Autowired
- private Emitter source;
-
- @Autowired
- private StreamMetricsProperties properties;
-
- @Autowired
- private BindingServiceProperties bindingServiceProperties;
-
- private MetricsEndpointMetricReader metricsReader;
-
- private ApplicationContext applicationContext;
-
- /**
- * List of properties that are going to be appended to each message. This gets
- * populate by onApplicationEvent, once the context refreshes to avoid overhead of
- * doing per message basis.
- */
- private Map whitelistedProperties;
-
- public BinderMetricsEmitter(MetricsEndpoint endpoint) {
- this.metricsReader = new MetricsEndpointMetricReader(endpoint);
- this.whitelistedProperties = new HashMap<>();
- }
-
- @Scheduled(fixedRateString = "${spring.cloud.stream.metrics.delay-millis:5000}")
- public void sendMetrics() {
- ApplicationMetrics appMetrics = new ApplicationMetrics(this.properties.getMetricName(),
- this.bindingServiceProperties.getInstanceIndex(), filter());
- appMetrics.setProperties(whitelistedProperties);
- source.metrics().send(MessageBuilder.withPayload(appMetrics).build());
- }
-
- /**
- * Copy of similarly named method in {@link MetricCopyExporter}.
- */
- protected Collection filter() {
- Collection result = new ArrayList<>();
- Iterable> metrics = metricsReader.findAll();
- for (Metric metric : metrics) {
- if (isMatch(metric.getName(), this.properties.getIncludes(), this.properties.getExcludes())) {
- result.add(metric);
- }
- }
- return result;
- }
-
- /**
- * Copy of similarly named method in {@link MetricCopyExporter}.
- */
- private boolean isMatch(String name, String[] includes, String[] excludes) {
- if (ObjectUtils.isEmpty(includes) || PatternMatchUtils.simpleMatch(includes, name)) {
- return !PatternMatchUtils.simpleMatch(excludes, name);
- }
- return false;
- }
-
- /**
- * Iterates over all property sources from this application context and copies the
- * ones listed in {@link StreamMetricsProperties} includes.
- */
- @Override
- public void onApplicationEvent(ContextRefreshedEvent event) {
- ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) event.getSource();
- if (!ObjectUtils.isEmpty(this.properties.getProperties())) {
- for (PropertySource source : ctx.getEnvironment().getPropertySources()) {
- if (source instanceof EnumerablePropertySource) {
- EnumerablePropertySource e = (EnumerablePropertySource) source;
- for (String propertyName : e.getPropertyNames()) {
- RelaxedNames relaxedNames = new RelaxedNames(propertyName);
- relaxedLoop: for (String relaxedPropertyName : relaxedNames) {
- if (isMatch(relaxedPropertyName, this.properties.getProperties(), null)) {
- whitelistedProperties.put(RelaxedPropertiesUtils.findCanonicalFormat(relaxedNames),
- source.getProperty(propertyName));
- break relaxedLoop;
- }
- }
- }
- }
- }
- }
- }
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- this.applicationContext = applicationContext;
- }
-}
diff --git a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/RelaxedPropertiesUtils.java b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/RelaxedPropertiesUtils.java
index 91f7d8d1f..fc03ccdef 100644
--- a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/RelaxedPropertiesUtils.java
+++ b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/RelaxedPropertiesUtils.java
@@ -27,19 +27,19 @@ import org.springframework.util.StringUtils;
*
* @author Vinicius Carvalho
*/
-public class RelaxedPropertiesUtils {
+class RelaxedPropertiesUtils {
private static final Pattern HYPHEN_LOWER = Pattern.compile("-_|_-|__|\\.-|\\._");
- private static final Pattern SEPARATED_TO_CAMEL_CASE_PATTERN = Pattern.compile("[_\\-.]");
+ private static final Pattern SEPARATED_TO_CAMEL_CASE_PATTERN = Pattern
+ .compile("[_\\-.]");
private static final char[] SUFFIXES = new char[] { '_', '-', '.' };
/**
* Searches relaxed names and tries to find a best match for a canonical form using
- * dot notation.
- * For example, if a new list was built with JAVA_HOME as property, the return of this
- * method would be {@code java.home}.
+ * dot notation. For example, if a new list was built with JAVA_HOME as property, the
+ * return of this method would be {@code java.home}.
*
* Relaxed names generate a long list of variations of a property, it can be tricky
* trying to infer the correct format, which sometimes may not even exist in dot
diff --git a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/config/metrics/BinderMetricsAutoConfiguration.java b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/BinderMetricsAutoConfiguration.java
similarity index 67%
rename from spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/config/metrics/BinderMetricsAutoConfiguration.java
rename to spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/BinderMetricsAutoConfiguration.java
index 498f8a8ae..2c6f261a9 100644
--- a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/config/metrics/BinderMetricsAutoConfiguration.java
+++ b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/BinderMetricsAutoConfiguration.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.cloud.stream.config.metrics;
+package org.springframework.cloud.stream.metrics.config;
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -22,32 +22,31 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.binder.Binder;
-import org.springframework.cloud.stream.metrics.BinderMetricsEmitter;
-import org.springframework.cloud.stream.metrics.BootMetricJsonSerializer;
-import org.springframework.cloud.stream.metrics.Emitter;
+import org.springframework.cloud.stream.metrics.ApplicationMetricsExporter;
+import org.springframework.cloud.stream.metrics.ApplicationMetricsProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.scheduling.annotation.EnableScheduling;
/**
* @author Vinicius Carvalho
*/
@Configuration
@ConditionalOnClass(Binder.class)
-@EnableScheduling
@EnableBinding(Emitter.class)
-@EnableConfigurationProperties(StreamMetricsProperties.class)
-@ConditionalOnProperty("spring.cloud.stream.bindings." + Emitter.METRICS_CHANNEL_NAME + ".destination")
+@EnableConfigurationProperties(ApplicationMetricsProperties.class)
+@ConditionalOnProperty("spring.cloud.stream.bindings." + Emitter.METRICS_CHANNEL_NAME
+ + ".destination")
public class BinderMetricsAutoConfiguration {
@Bean
- public BinderMetricsEmitter binderMetricsExporter(MetricsEndpoint endpoint) {
- return new BinderMetricsEmitter(endpoint);
+ public ApplicationMetricsExporter aggregateMetricsExporter(MetricsEndpoint endpoint,
+ Emitter emitter, ApplicationMetricsProperties properties) {
+ return new ApplicationMetricsExporter(endpoint, emitter.metrics(), properties);
}
@Bean
- public BootMetricJsonSerializer metricJsonSerializer() {
- return new BootMetricJsonSerializer();
+ public MetricJsonSerializer metricJsonSerializer() {
+ return new MetricJsonSerializer();
}
}
diff --git a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/config/metrics/BinderMetricsEnvironmentPostProcessor.java b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/BinderMetricsEnvironmentPostProcessor.java
similarity index 71%
rename from spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/config/metrics/BinderMetricsEnvironmentPostProcessor.java
rename to spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/BinderMetricsEnvironmentPostProcessor.java
index cb2d32da5..2b53b1506 100644
--- a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/config/metrics/BinderMetricsEnvironmentPostProcessor.java
+++ b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/BinderMetricsEnvironmentPostProcessor.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.cloud.stream.config.metrics;
+package org.springframework.cloud.stream.metrics.config;
import java.util.HashMap;
import java.util.Map;
@@ -29,10 +29,15 @@ import org.springframework.core.env.MapPropertySource;
*/
public class BinderMetricsEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
- public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
+ public void postProcessEnvironment(ConfigurableEnvironment environment,
+ SpringApplication application) {
Map propertiesToAdd = new HashMap<>();
- propertiesToAdd.put("spring.cloud.stream.bindings.streamMetrics.contentType", "application/json");
- environment.getPropertySources()
- .addLast(new MapPropertySource("binderMetricsDefaultProperties", propertiesToAdd));
+ propertiesToAdd.put("spring.cloud.stream.bindings.streamMetrics.contentType",
+ "application/json");
+ propertiesToAdd.put("spring.cloud.stream.metrics.instanceIndex",
+ "${spring.cloud.stream.instanceIndex:${INSTANCE_INDEX:${CF_INSTANCE_INDEX:0}}}");
+ propertiesToAdd.put("spring.metrics.export.includes", "integration**");
+ environment.getPropertySources().addLast(
+ new MapPropertySource("binderMetricsDefaultProperties", propertiesToAdd));
}
}
diff --git a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/Emitter.java b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/Emitter.java
similarity index 94%
rename from spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/Emitter.java
rename to spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/Emitter.java
index cc19c1614..138f67d7c 100644
--- a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/Emitter.java
+++ b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/Emitter.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.cloud.stream.metrics;
+package org.springframework.cloud.stream.metrics.config;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
diff --git a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/BootMetricJsonSerializer.java b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/MetricJsonSerializer.java
similarity index 82%
rename from spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/BootMetricJsonSerializer.java
rename to spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/MetricJsonSerializer.java
index 81be6a0f6..918a11dd3 100644
--- a/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/BootMetricJsonSerializer.java
+++ b/spring-cloud-stream-metrics/src/main/java/org/springframework/cloud/stream/metrics/config/MetricJsonSerializer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.cloud.stream.metrics;
+package org.springframework.cloud.stream.metrics.config;
import java.io.IOException;
import java.text.DateFormat;
@@ -38,15 +38,15 @@ import org.springframework.boot.jackson.JsonComponent;
* @author Vinicius Carvalho
*/
@JsonComponent
-public class BootMetricJsonSerializer {
+public class MetricJsonSerializer {
final static DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
- public static class Serializer extends JsonSerializer {
+ public static class Serializer extends JsonSerializer> {
@Override
- public void serialize(Metric metric, JsonGenerator json, SerializerProvider serializerProvider)
- throws IOException {
+ public void serialize(Metric> metric, JsonGenerator json,
+ SerializerProvider serializerProvider) throws IOException {
json.writeStartObject();
json.writeStringField("name", metric.getName());
json.writeNumberField("value", metric.getValue().doubleValue());
@@ -55,10 +55,10 @@ public class BootMetricJsonSerializer {
}
}
- public static class Deserializer extends JsonDeserializer {
+ public static class Deserializer extends JsonDeserializer> {
@Override
- public Metric deserialize(JsonParser p, DeserializationContext ctxt)
+ public Metric> deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = p.getCodec().readTree(p);
String name = node.get("name").asText();
@@ -70,7 +70,7 @@ public class BootMetricJsonSerializer {
}
catch (ParseException e) {
}
- Metric metric = new Metric(name, value, timestamp);
+ Metric metric = new Metric(name, value, timestamp);
return metric;
}
diff --git a/spring-cloud-stream-metrics/src/main/resources/META-INF/spring.factories b/spring-cloud-stream-metrics/src/main/resources/META-INF/spring.factories
index 2555b7f54..9b9369892 100644
--- a/spring-cloud-stream-metrics/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-stream-metrics/src/main/resources/META-INF/spring.factories
@@ -1,4 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- org.springframework.cloud.stream.config.metrics.BinderMetricsAutoConfiguration
+ org.springframework.cloud.stream.metrics.config.BinderMetricsAutoConfiguration
org.springframework.boot.env.EnvironmentPostProcessor=\
- org.springframework.cloud.stream.config.metrics.BinderMetricsEnvironmentPostProcessor
\ No newline at end of file
+ org.springframework.cloud.stream.metrics.config.BinderMetricsEnvironmentPostProcessor
\ No newline at end of file
diff --git a/spring-cloud-stream-metrics/src/test/java/org/springframework/cloud/stream/metrics/BinderMetricsEmitterTests.java b/spring-cloud-stream-metrics/src/test/java/org/springframework/cloud/stream/metrics/ApplicationMetricsExporterTests.java
similarity index 59%
rename from spring-cloud-stream-metrics/src/test/java/org/springframework/cloud/stream/metrics/BinderMetricsEmitterTests.java
rename to spring-cloud-stream-metrics/src/test/java/org/springframework/cloud/stream/metrics/ApplicationMetricsExporterTests.java
index e9c34e518..17748c5fe 100644
--- a/spring-cloud-stream-metrics/src/test/java/org/springframework/cloud/stream/metrics/BinderMetricsEmitterTests.java
+++ b/spring-cloud-stream-metrics/src/test/java/org/springframework/cloud/stream/metrics/ApplicationMetricsExporterTests.java
@@ -20,6 +20,7 @@ import java.util.Collection;
import java.util.concurrent.TimeUnit;
import com.fasterxml.jackson.databind.ObjectMapper;
+
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -29,6 +30,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.cloud.stream.metrics.config.Emitter;
import org.springframework.cloud.stream.test.binder.MessageCollector;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.messaging.Message;
@@ -37,7 +39,7 @@ import org.springframework.util.CollectionUtils;
/**
* @author Vinicius Carvalho
*/
-public class BinderMetricsEmitterTests {
+public class ApplicationMetricsExporterTests {
@BeforeClass
public static void setSystemProps() {
@@ -51,8 +53,9 @@ public class BinderMetricsEmitterTests {
@Test(expected = NoSuchBeanDefinitionException.class)
public void checkDisabledConfiguration() throws Exception {
- ConfigurableApplicationContext applicationContext = SpringApplication.run(BinderExporterApplication.class,
- "--server.port=0", "--spring.jmx.enabled=false", "--spring.cloud.stream.metrics.delay-millis=500");
+ ConfigurableApplicationContext applicationContext = SpringApplication.run(
+ BinderExporterApplication.class, "--server.port=0",
+ "--spring.jmx.enabled=false");
try {
applicationContext.getBean(Emitter.class);
}
@@ -67,17 +70,20 @@ public class BinderMetricsEmitterTests {
@Test
public void defaultIncludes() throws Exception {
- ConfigurableApplicationContext applicationContext = SpringApplication.run(BinderExporterApplication.class,
- "--server.port=0", "--spring.jmx.enabled=false", "--spring.cloud.stream.metrics.delay-millis=500",
+ ConfigurableApplicationContext applicationContext = SpringApplication.run(
+ BinderExporterApplication.class, "--server.port=0",
+ "--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
"--spring.cloud.stream.bindings.streamMetrics.destination=foo");
Emitter emitterSource = applicationContext.getBean(Emitter.class);
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
- Message message = collector.forChannel(emitterSource.metrics()).poll(1000, TimeUnit.MILLISECONDS);
+ Message> message = collector.forChannel(emitterSource.metrics()).poll(1000,
+ TimeUnit.MILLISECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
- ApplicationMetrics applicationMetrics = mapper.readValue((String) message.getPayload(),
- ApplicationMetrics.class);
- Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean", applicationMetrics.getMetrics()));
+ ApplicationMetrics applicationMetrics = mapper
+ .readValue((String) message.getPayload(), ApplicationMetrics.class);
+ Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
+ applicationMetrics.getMetrics()));
Assert.assertFalse(contains("mem", applicationMetrics.getMetrics()));
Assert.assertEquals("application", applicationMetrics.getName());
Assert.assertEquals(0, applicationMetrics.getInstanceIndex());
@@ -87,18 +93,21 @@ public class BinderMetricsEmitterTests {
@Test
public void customAppNameAndIndex() throws Exception {
- ConfigurableApplicationContext applicationContext = SpringApplication.run(BinderExporterApplication.class,
- "--server.port=0", "--spring.jmx.enabled=false", "--spring.cloud.stream.metrics.delay-millis=500",
+ ConfigurableApplicationContext applicationContext = SpringApplication.run(
+ BinderExporterApplication.class, "--server.port=0",
+ "--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
"--spring.application.name=foo", "--spring.cloud.stream.instanceIndex=1",
"--spring.cloud.stream.bindings.streamMetrics.destination=foo");
Emitter emitterSource = applicationContext.getBean(Emitter.class);
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
- Message message = collector.forChannel(emitterSource.metrics()).poll(1000, TimeUnit.MILLISECONDS);
+ Message> message = collector.forChannel(emitterSource.metrics()).poll(1000,
+ TimeUnit.MILLISECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
- ApplicationMetrics applicationMetrics = mapper.readValue((String) message.getPayload(),
- ApplicationMetrics.class);
- Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean", applicationMetrics.getMetrics()));
+ ApplicationMetrics applicationMetrics = mapper
+ .readValue((String) message.getPayload(), ApplicationMetrics.class);
+ Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
+ applicationMetrics.getMetrics()));
Assert.assertFalse(contains("mem", applicationMetrics.getMetrics()));
Assert.assertEquals("foo", applicationMetrics.getName());
Assert.assertEquals(1, applicationMetrics.getInstanceIndex());
@@ -108,18 +117,22 @@ public class BinderMetricsEmitterTests {
@Test
public void usingPrefix() throws Exception {
- ConfigurableApplicationContext applicationContext = SpringApplication.run(BinderExporterApplication.class,
- "--server.port=0", "--spring.jmx.enabled=false", "--spring.cloud.stream.metrics.delay-millis=500",
- "--spring.cloud.stream.metrics.prefix=foo", "--spring.cloud.stream.instanceIndex=1",
+ ConfigurableApplicationContext applicationContext = SpringApplication.run(
+ BinderExporterApplication.class, "--server.port=0",
+ "--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
+ "--spring.cloud.stream.metrics.prefix=foo",
+ "--spring.cloud.stream.instanceIndex=1",
"--spring.cloud.stream.bindings.streamMetrics.destination=foo");
Emitter emitterSource = applicationContext.getBean(Emitter.class);
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
- Message message = collector.forChannel(emitterSource.metrics()).poll(1000, TimeUnit.MILLISECONDS);
+ Message> message = collector.forChannel(emitterSource.metrics()).poll(1000,
+ TimeUnit.MILLISECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
- ApplicationMetrics applicationMetrics = mapper.readValue((String) message.getPayload(),
- ApplicationMetrics.class);
- Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean", applicationMetrics.getMetrics()));
+ ApplicationMetrics applicationMetrics = mapper
+ .readValue((String) message.getPayload(), ApplicationMetrics.class);
+ Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
+ applicationMetrics.getMetrics()));
Assert.assertFalse(contains("mem", applicationMetrics.getMetrics()));
Assert.assertEquals("foo.application", applicationMetrics.getName());
Assert.assertEquals(1, applicationMetrics.getInstanceIndex());
@@ -129,19 +142,22 @@ public class BinderMetricsEmitterTests {
@Test
public void includesExcludes() throws Exception {
- ConfigurableApplicationContext applicationContext = SpringApplication.run(BinderExporterApplication.class,
- "--server.port=0", "--spring.jmx.enabled=false", "--spring.cloud.stream.metrics.delay-millis=500",
+ ConfigurableApplicationContext applicationContext = SpringApplication.run(
+ BinderExporterApplication.class, "--server.port=0",
+ "--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
"--spring.cloud.stream.bindings.streamMetrics.destination=foo",
- "--spring.cloud.stream.metrics.includes=mem**", "--spring.cloud.stream.metrics.excludes=integration**");
+ "--spring.metrics.export.includes=mem**",
+ "--spring.metrics.export.excludes=integration**");
Emitter emitterSource = applicationContext.getBean(Emitter.class);
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
- Message message = collector.forChannel(emitterSource.metrics()).poll(1000, TimeUnit.MILLISECONDS);
+ Message> message = collector.forChannel(emitterSource.metrics()).poll(1000,
+ TimeUnit.MILLISECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
- ApplicationMetrics applicationMetrics = mapper.readValue((String) message.getPayload(),
- ApplicationMetrics.class);
- Assert.assertFalse(
- contains("integration.channel.errorChannel.errorRate.mean", applicationMetrics.getMetrics()));
+ ApplicationMetrics applicationMetrics = mapper
+ .readValue((String) message.getPayload(), ApplicationMetrics.class);
+ Assert.assertFalse(contains("integration.channel.errorChannel.errorRate.mean",
+ applicationMetrics.getMetrics()));
Assert.assertTrue(contains("mem", applicationMetrics.getMetrics()));
Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
applicationContext.close();
@@ -149,50 +165,57 @@ public class BinderMetricsEmitterTests {
@Test
public void includesExcludesWithProperties() throws Exception {
- ConfigurableApplicationContext applicationContext = SpringApplication.run(BinderExporterApplication.class,
- "--server.port=0", "--spring.jmx.enabled=false", "--spring.cloud.stream.metrics.delay-millis=500",
+ ConfigurableApplicationContext applicationContext = SpringApplication.run(
+ BinderExporterApplication.class, "--server.port=0",
+ "--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
"--spring.cloud.stream.bindings.streamMetrics.destination=foo",
- "--spring.cloud.stream.metrics.includes=integration**",
+ "--spring.metrics.export.includes=integration**",
"--spring.cloud.stream.metrics.properties=java**,spring.test.env**");
Emitter emitterSource = applicationContext.getBean(Emitter.class);
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
- Message message = collector.forChannel(emitterSource.metrics()).poll(1000, TimeUnit.MILLISECONDS);
+ Message> message = collector.forChannel(emitterSource.metrics()).poll(1000,
+ TimeUnit.MILLISECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
- ApplicationMetrics applicationMetrics = mapper.readValue((String) message.getPayload(),
- ApplicationMetrics.class);
+ ApplicationMetrics applicationMetrics = mapper
+ .readValue((String) message.getPayload(), ApplicationMetrics.class);
Assert.assertFalse(contains("mem", applicationMetrics.getMetrics()));
- Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean", applicationMetrics.getMetrics()));
+ Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
+ applicationMetrics.getMetrics()));
Assert.assertFalse(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
- Assert.assertTrue(applicationMetrics.getProperties().get("spring.test.env.syntax").equals("testing"));
+ Assert.assertTrue(applicationMetrics.getProperties().get("spring.test.env.syntax")
+ .equals("testing"));
applicationContext.close();
}
- @Test
- public void overrideAppName() throws Exception {
- ConfigurableApplicationContext applicationContext = SpringApplication.run(BinderExporterApplication.class,
- "--server.port=0", "--spring.jmx.enabled=false", "--spring.cloud.stream.metrics.delay-millis=500",
- "--spring.application.name=foo", "--spring.cloud.stream.instanceIndex=1",
- "--spring.cloud.stream.bindings.streamMetrics.destination=foo",
- "--spring.cloud.stream.metrics.key=foobarfoo");
- Emitter emitterSource = applicationContext.getBean(Emitter.class);
- MessageCollector collector = applicationContext.getBean(MessageCollector.class);
- Message message = collector.forChannel(emitterSource.metrics()).poll(1000, TimeUnit.MILLISECONDS);
- Assert.assertNotNull(message);
- ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
- ApplicationMetrics applicationMetrics = mapper.readValue((String) message.getPayload(),
- ApplicationMetrics.class);
- Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean", applicationMetrics.getMetrics()));
- Assert.assertFalse(contains("mem", applicationMetrics.getMetrics()));
- Assert.assertEquals("foobarfoo", applicationMetrics.getName());
- Assert.assertEquals(1, applicationMetrics.getInstanceIndex());
- Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
- applicationContext.close();
- }
+ @Test
+ public void overrideAppName() throws Exception {
+ ConfigurableApplicationContext applicationContext = SpringApplication.run(
+ BinderExporterApplication.class, "--server.port=0",
+ "--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
+ "--spring.application.name=foo", "--spring.cloud.stream.instanceIndex=1",
+ "--spring.cloud.stream.bindings.streamMetrics.destination=foo",
+ "--spring.cloud.stream.metrics.key=foobarfoo");
+ Emitter emitterSource = applicationContext.getBean(Emitter.class);
+ MessageCollector collector = applicationContext.getBean(MessageCollector.class);
+ Message> message = collector.forChannel(emitterSource.metrics()).poll(1000,
+ TimeUnit.MILLISECONDS);
+ Assert.assertNotNull(message);
+ ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
+ ApplicationMetrics applicationMetrics = mapper
+ .readValue((String) message.getPayload(), ApplicationMetrics.class);
+ Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
+ applicationMetrics.getMetrics()));
+ Assert.assertFalse(contains("mem", applicationMetrics.getMetrics()));
+ Assert.assertEquals("foobarfoo", applicationMetrics.getName());
+ Assert.assertEquals(1, applicationMetrics.getInstanceIndex());
+ Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
+ applicationContext.close();
+ }
- private boolean contains(String metric, Collection metrics) {
+ private boolean contains(String metric, Collection> metrics) {
boolean contains = false;
- for (Metric entry : metrics) {
+ for (Metric> entry : metrics) {
contains = entry.getName().equals(metric);
if (contains) {
break;