GH-1079 Removed old metrics infrustructure

Resolves #1079
This commit is contained in:
Oleg Zhurakousky
2018-02-22 15:20:25 -05:00
parent 28c22787fe
commit cc9cc92a1b
13 changed files with 0 additions and 1055 deletions

View File

@@ -103,7 +103,6 @@
<module>spring-cloud-stream-schema</module>
<module>spring-cloud-stream-schema-server</module>
<module>spring-cloud-stream-tools</module>
<!--<module>spring-cloud-stream-metrics</module>-->
</modules>
<build>
<pluginManagement>

View File

@@ -1,39 +0,0 @@
<?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>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-metrics</artifactId>
<description>Emitter module to publish boot metrics</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-parent</artifactId>
<version>2.0.0.M2</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -1,78 +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.Collection;
import java.util.Date;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.boot.actuate.metrics.Metric;
/**
* @author Vinicius Carvalho
*/
public class ApplicationMetrics {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC")
private final Date createdTime;
private String name;
private Collection<Metric<?>> metrics;
private Map<String, Object> properties;
@JsonCreator
public ApplicationMetrics(@JsonProperty("name") String name,
@JsonProperty("metrics") Collection<Metric<?>> metrics) {
this.name = name;
this.metrics = metrics;
this.createdTime = new Date();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection<Metric<?>> getMetrics() {
return metrics;
}
public void setMetrics(Collection<Metric<?>> metrics) {
this.metrics = metrics;
}
public Date getCreatedTime() {
return createdTime;
}
public Map<String, Object> getProperties() {
return properties;
}
public void setProperties(Map<String, Object> properties) {
this.properties = properties;
}
}

View File

@@ -1,92 +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 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(),
filter());
appMetrics.setProperties(this.properties.getExportProperties());
source.send(MessageBuilder.withPayload(appMetrics).build());
}
/**
* Copy of similarly named method in {@link MetricCopyExporter}.
*/
protected Collection<Metric<?>> filter() {
Collection<Metric<?>> result = new ArrayList<>();
Iterable<Metric<?>> 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;
}
}

View File

@@ -1,187 +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.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.boot.actuate.metrics.export.MetricExportProperties;
import org.springframework.boot.actuate.metrics.export.TriggerProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.cloud.stream.metrics.config.BinderMetricsAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.PatternMatchUtils;
/**
* @author Vinicius Carvalho
* @author Janne Valkealahti
*/
@ConfigurationProperties(prefix = "spring.cloud.stream.metrics")
public class ApplicationMetricsProperties
implements EnvironmentAware, ApplicationContextAware {
private static final Bindable<Map<String, String>> STRING_STRING_MAP = Bindable
.mapOf(String.class, String.class);
private final MetricExportProperties metricExportProperties;
private String prefix = "";
@Value("${spring.application.name:${vcap.application.name:${spring.config.name:application}}}")
private String key;
private String metricName;
private String[] properties;
private Environment environment;
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<String, Object> exportProperties = null;
public ApplicationMetricsProperties(MetricExportProperties metricExportProperties) {
Assert.notNull(metricExportProperties, "'metricsExportProperties' cannot be null");
this.metricExportProperties = metricExportProperties;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public TriggerProperties getTrigger() {
return metricExportProperties
.findTrigger(BinderMetricsAutoConfiguration.APPLICATION_METRICS_EXPORTER_TRIGGER_NAME);
}
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 String[] getProperties() {
return properties;
}
public void setProperties(String[] properties) {
this.properties = properties;
}
public Map<String, Object> getExportProperties() {
if (this.exportProperties == null) {
this.exportProperties = buildExportProperties();
}
return this.exportProperties;
}
public String getMetricName() {
if (this.metricName == null) {
this.metricName = resolveMetricName();
}
return metricName;
}
private String resolveMetricName() {
return this.prefix + this.key;
}
private boolean isMatch(String name, String[] includes, String[] excludes) {
if (ObjectUtils.isEmpty(includes)
|| PatternMatchUtils.simpleMatch(includes, name)) {
return !PatternMatchUtils.simpleMatch(excludes, name);
}
return false;
}
private Map<String, Object> buildExportProperties() {
Map<String, Object> props = new HashMap<>();
if (!ObjectUtils.isEmpty(this.properties)) {
Map<String, String> target = bindProperties();
BeanExpressionResolver beanExpressionResolver = ((ConfigurableApplicationContext) applicationContext)
.getBeanFactory().getBeanExpressionResolver();
BeanExpressionContext expressionContext = new BeanExpressionContext(
((ConfigurableApplicationContext) applicationContext).getBeanFactory(), null);
for (Entry<String, String> entry : target.entrySet()) {
if (isMatch(entry.getKey(), this.properties, null)) {
String stringValue = ObjectUtils.nullSafeToString(entry.getValue());
Object exportedValue = null;
if (stringValue != null) {
exportedValue = stringValue.startsWith("#{")
? beanExpressionResolver.evaluate(
environment.resolvePlaceholders(stringValue), expressionContext)
: environment.resolvePlaceholders(stringValue);
}
props.put(entry.getKey(), exportedValue);
}
}
}
return props;
}
private Map<String, String> bindProperties() {
Map<String, String> target;
BindResult<Map<String, String>> bindResult = Binder.get(environment).bind("", STRING_STRING_MAP);
if (bindResult.isBound()) {
target = bindResult.get();
}
else {
target = new HashMap<>();
}
return target;
}
}

View File

@@ -1,105 +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.config;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.actuate.autoconfigure.MetricExportAutoConfiguration;
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
import org.springframework.boot.actuate.metrics.export.Exporter;
import org.springframework.boot.actuate.metrics.export.MetricExporters;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
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.ApplicationMetricsExporter;
import org.springframework.cloud.stream.metrics.ApplicationMetricsProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
/**
* Autoconfiguration registering an {@link Exporter} that publishes application metrics
* over the {@link Emitter#applicationMetrics()} channel.
*
* @author Vinicius Carvalho
* @author Marius Bogoevici
*
*/
@Configuration
@ConditionalOnClass(Binder.class)
@EnableBinding(Emitter.class)
@EnableConfigurationProperties(ApplicationMetricsProperties.class)
@AutoConfigureAfter(MetricExportAutoConfiguration.class)
@ConditionalOnProperty("spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS
+ ".destination")
public class BinderMetricsAutoConfiguration {
public static final String APPLICATION_METRICS_EXPORTER_TRIGGER_NAME = "application";
public static Log log = LogFactory.getLog(BinderMetricsAutoConfiguration.class);
/**
* Postprocessor for installing the {@link ApplicationMetricsExporter} as an exporter
* under the name {@code application}.
* @param endpoint the metrics endpoint (lazy reference to prevent early
* initialization)
* @param emitter the emitter bound interface
* @param properties application metrics properties
* @return
*/
@Bean
public static BeanPostProcessor metricExportersBeanPostProcessor(final @Lazy MetricsEndpoint endpoint,
final Emitter emitter, final ApplicationMetricsProperties properties) {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String name) throws BeansException {
if (bean instanceof MetricExporters) {
Map<String, Exporter> exporters = ((MetricExporters) bean).getExporters();
if (!exporters.containsKey(APPLICATION_METRICS_EXPORTER_TRIGGER_NAME)) {
exporters.put(APPLICATION_METRICS_EXPORTER_TRIGGER_NAME,
new ApplicationMetricsExporter(endpoint, emitter.applicationMetrics(), properties));
}
else {
log.warn("Could not register ApplicationMetricExporter: "
+ exporters.get(APPLICATION_METRICS_EXPORTER_TRIGGER_NAME)
+ " was already registered as " + APPLICATION_METRICS_EXPORTER_TRIGGER_NAME);
}
}
return bean;
}
};
}
@Bean
public MetricJsonSerializer metricJsonSerializer() {
return new MetricJsonSerializer();
}
}

View File

@@ -1,39 +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.config;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
/**
* @author Vinicius Carvalho
*/
public class BinderMetricsEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Map<String, Object> propertiesToAdd = new HashMap<>();
propertiesToAdd.put("spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".contentType",
"application/json");
environment.getPropertySources()
.addLast(new MapPropertySource("binderMetricsDefaultProperties", propertiesToAdd));
}
}

View File

@@ -1,32 +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.config;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
/**
* @author Vinicius Carvalho
*/
public interface Emitter {
String APPLICATION_METRICS = "applicationMetrics";
@Output(APPLICATION_METRICS)
MessageChannel applicationMetrics();
}

View File

@@ -1,104 +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.config;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.jackson.JsonComponent;
/**
* @author Vinicius Carvalho
* @author Oleg Zhurakousky
*/
@JsonComponent
public class MetricJsonSerializer {
private static final BlockingQueue<DateFormat> formatters = new LinkedBlockingQueue<DateFormat>();
private static DateFormat defaultDateFormat() {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df;
}
public static class Serializer extends JsonSerializer<Metric<?>> {
@Override
public void serialize(Metric<?> metric, JsonGenerator json,
SerializerProvider serializerProvider) throws IOException {
json.writeStartObject();
json.writeStringField("name", metric.getName());
json.writeNumberField("value", metric.getValue().doubleValue());
DateFormat df = formatters.poll();
if (df == null) {
df = defaultDateFormat();
}
try {
json.writeStringField("timestamp", df.format(metric.getTimestamp()));
json.writeEndObject();
}
finally {
formatters.offer(df);
}
}
}
public static class Deserializer extends JsonDeserializer<Metric<?>> {
@Override
public Metric<?> deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = p.getCodec().readTree(p);
String name = node.get("name").asText();
Number value = node.get("value").asDouble();
Date timestamp = null;
DateFormat df = formatters.poll();
if (df == null) {
df = defaultDateFormat();
}
try {
timestamp = df.parse(node.get("timestamp").asText());
}
catch (ParseException e) {
// ignore timestamp parsing errors
}
finally {
formatters.offer(df);
}
Metric<Number> metric = new Metric<>(name, value, timestamp);
return metric;
}
}
}

View File

@@ -1,4 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.stream.metrics.config.BinderMetricsAutoConfiguration
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.stream.metrics.config.BinderMetricsEnvironmentPostProcessor

View File

@@ -1,321 +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.Collection;
import java.util.concurrent.TimeUnit;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.assertj.core.api.Assertions;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
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;
import org.springframework.util.CollectionUtils;
/**
* @author Vinicius Carvalho
* @author Janne Valkealahti
*/
public class ApplicationMetricsExporterTests {
@BeforeClass
public static void setSystemProps() {
System.setProperty("spring.test.env.syntax", "testing");
}
@AfterClass
public static void unsetSystemProps() {
System.clearProperty("spring.test.env.syntax");
}
@Test(expected = NoSuchBeanDefinitionException.class)
public void checkDisabledConfiguration() throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(
BinderExporterApplication.class, "--server.port=0", "--spring.jmx.enabled=false");
try {
applicationContext.getBean(Emitter.class);
}
catch (Exception e) {
throw e;
}
finally {
applicationContext.close();
}
}
@Test
public void defaultIncludes() throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(
BinderExporterApplication.class, "--server.port=0",
"--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo");
Emitter emitterSource = applicationContext.getBean(Emitter.class);
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
.poll(10, TimeUnit.SECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
ApplicationMetrics applicationMetrics = mapper
.readValue((byte[]) message.getPayload(), ApplicationMetrics.class);
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
applicationMetrics.getMetrics()));
Assert.assertEquals("application", applicationMetrics.getName());
Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
applicationContext.close();
}
@Test
public void customAppNameAndIndex() 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.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo");
Emitter emitterSource = applicationContext.getBean(Emitter.class);
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
.poll(10, TimeUnit.SECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) message.getPayload(),
ApplicationMetrics.class);
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
applicationMetrics.getMetrics()));
Assert.assertTrue(contains("mem", applicationMetrics.getMetrics()));
Assert.assertEquals("foo", applicationMetrics.getName());
Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
applicationContext.close();
}
@Test
public void usingPrefix() throws Exception {
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.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo");
Emitter emitterSource = applicationContext.getBean(Emitter.class);
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
.poll(10, TimeUnit.SECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
ApplicationMetrics applicationMetrics = mapper
.readValue((byte[]) message.getPayload(), ApplicationMetrics.class);
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
applicationMetrics.getMetrics()));
Assert.assertTrue(contains("mem", applicationMetrics.getMetrics()));
Assert.assertEquals("foo.application", applicationMetrics.getName());
Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
applicationContext.close();
}
@Test
public void includesExcludesDefaultConfig() throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(
BinderExporterApplication.class, "--server.port=0",
"--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo",
"--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.applicationMetrics())
.poll(10, TimeUnit.SECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
ApplicationMetrics applicationMetrics = mapper
.readValue((byte[]) 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();
}
@Test
public void includesExcludesWithApplicationMetricsConfiguration() throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(
BinderExporterApplication.class, "--server.port=0",
"--spring.jmx.enabled=false",
"--spring.metrics.export.triggers.application.delay-millis=500",
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo",
"--spring.metrics.export.triggers.application.includes=mem**",
"--spring.metrics.export.triggers.application.excludes=integration**");
Emitter emitterSource = applicationContext.getBean(Emitter.class);
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
.poll(10, TimeUnit.SECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) 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();
}
@Test
public void includesExcludesWithProperties() throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(
BinderExporterApplication.class, "--server.port=0",
"--spring.jmx.enabled=false", "--spring.metrics.export.delay-millis=500",
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo",
"--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.applicationMetrics())
.poll(10, TimeUnit.SECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) message.getPayload(),
ApplicationMetrics.class);
Assert.assertFalse(contains("mem", 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"));
applicationContext.close();
}
@Test
public void propertiesWithPlaceholdersAndExpressions() throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(
BinderExporterApplication.class,
"--server.port=0",
"--spring.jmx.enabled=false",
"--PLATFORM_APP_NAME=123-name-foo",
"--PLATFORM_APP_ID=123-id-bar",
"--spring.cloud.application.guid=${PLATFORM_APP_NAME}.${PLATFORM_APP_ID}",
"--spring.cloud.application.guid.expression=#{'${PLATFORM_APP_NAME}' + '..' + '${PLATFORM_APP_ID}'}",
"--spring.cloud.application.guid.default.prop=${app.name.not.found:time-source}",
"--spring.cloud.application.guid.default.env=${APP_NAME_NOT_FOUND:time-source}",
"--spring.metrics.export.delay-millis=500",
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo",
"--spring.metrics.export.includes=integration**",
"--spring.cloud.stream.metrics.properties=spring**");
Emitter emitterSource = applicationContext.getBean(Emitter.class);
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
.poll(10, TimeUnit.SECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) message.getPayload(),
ApplicationMetrics.class);
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
applicationMetrics.getMetrics()));
Assertions.assertThat(applicationMetrics.getProperties().get("spring.cloud.application.guid"))
.isEqualTo("123-name-foo.123-id-bar");
Assertions.assertThat(applicationMetrics.getProperties().get("spring.cloud.application.guid.expression"))
.isEqualTo("123-name-foo..123-id-bar");
Assertions.assertThat(applicationMetrics.getProperties().get("spring.cloud.application.guid.default.prop"))
.isEqualTo("time-source");
Assertions.assertThat(applicationMetrics.getProperties().get("spring.cloud.application.guid.default.env"))
.isEqualTo("time-source");
Assert.assertFalse(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
Assert.assertTrue(applicationMetrics.getProperties().get("spring.test.env.syntax").equals("testing"));
applicationContext.close();
}
@Test
public void propertiesFromLowerPrioritySourcesOverridden() throws Exception {
System.setProperty("spring.cloud.application.guid.test.metrics", "lowPriority");
try {
ConfigurableApplicationContext applicationContext = SpringApplication.run(
BinderExporterApplication.class,
"--server.port=0",
"--spring.jmx.enabled=false",
"--spring.cloud.application.guid.test.metrics=highPriority",
"--spring.metrics.export.delay-millis=500",
"--spring.cloud.stream.bindings." + Emitter.APPLICATION_METRICS + ".destination=foo",
"--spring.metrics.export.includes=integration**",
"--spring.cloud.stream.metrics.properties=spring**");
Emitter emitterSource = applicationContext.getBean(Emitter.class);
MessageCollector collector = applicationContext.getBean(MessageCollector.class);
Message<?> message = collector.forChannel(emitterSource.applicationMetrics())
.poll(10, TimeUnit.SECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) message.getPayload(),
ApplicationMetrics.class);
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
applicationMetrics.getMetrics()));
Assertions.assertThat(applicationMetrics.getProperties().get("spring.cloud.application.guid.test.metrics"))
.isEqualTo("highPriority");
applicationContext.close();
}
finally {
System.clearProperty("spring.cloud.application.guid.test.metrics");
}
}
@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.bindings." + Emitter.APPLICATION_METRICS + ".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.applicationMetrics())
.poll(10, TimeUnit.SECONDS);
Assert.assertNotNull(message);
ObjectMapper mapper = applicationContext.getBean(ObjectMapper.class);
ApplicationMetrics applicationMetrics = mapper.readValue((byte[]) message.getPayload(),
ApplicationMetrics.class);
Assert.assertTrue(contains("integration.channel.errorChannel.errorRate.mean",
applicationMetrics.getMetrics()));
Assert.assertTrue(contains("mem", applicationMetrics.getMetrics()));
Assert.assertEquals("foobarfoo", applicationMetrics.getName());
Assert.assertTrue(CollectionUtils.isEmpty(applicationMetrics.getProperties()));
applicationContext.close();
}
private boolean contains(String metric, Collection<Metric<?>> metrics) {
boolean contains = false;
for (Metric<?> entry : metrics) {
contains = entry.getName().equals(metric);
if (contains) {
break;
}
}
return contains;
}
@EnableAutoConfiguration
public static class BinderExporterApplication {
}
}

View File

@@ -1,53 +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.config;
import java.io.StringWriter;
import java.util.Date;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import org.json.JSONObject;
import org.junit.Test;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.cloud.stream.metrics.config.MetricJsonSerializer.Serializer;
import static org.junit.Assert.assertEquals;
/**
* @author Oleg Zhurakousky
*/
public class MetricJsonSerializerTests {
@Test
public void validateAlwaysGMTDateAndFormat() throws Exception {
Date date = new Date(1493060197188L); // Mon Apr 24 14:56:37 EDT 2017
Metric<Number> metric = new Metric<Number>("Hello", 123, date);
JsonFactory factory = new JsonFactory();
StringWriter writer = new StringWriter();
JsonGenerator jsonGenerator = factory.createGenerator(writer);
Serializer ser = new Serializer();
ser.serialize(metric, jsonGenerator, null);
jsonGenerator.flush();
JSONObject json = new JSONObject(writer.toString());
String serializedTimestamp = json.getString("timestamp");
assertEquals("2017-04-24T18:56:37.188Z", serializedTimestamp);
}
}