Handle placeholders and SpEL in metrics properties

Fix #907

- Placeholders are replaced and expressions are evaluated
  before on attached properties

Add test for default value
This commit is contained in:
Marius Bogoevici
2017-04-10 17:17:32 -04:00
committed by Vinicius Carvalho
parent d6fe841a63
commit ab76178b82
2 changed files with 63 additions and 9 deletions

View File

@@ -20,6 +20,8 @@ import java.util.HashMap;
import java.util.Map;
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.bind.RelaxedNames;
@@ -28,8 +30,10 @@ import org.springframework.cloud.stream.metrics.config.BinderMetricsAutoConfigur
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.PatternMatchUtils;
@@ -49,14 +53,15 @@ public class ApplicationMetricsProperties
private String[] properties;
private MetricExportProperties export;
private final MetricExportProperties metricExportProperties;
public TriggerProperties getTrigger() {
return export.findTrigger(BinderMetricsAutoConfiguration.APPLICATION_METRICS_EXPORTER_TRIGGER_NAME);
return metricExportProperties.findTrigger(BinderMetricsAutoConfiguration.APPLICATION_METRICS_EXPORTER_TRIGGER_NAME);
}
public ApplicationMetricsProperties(MetricExportProperties export) {
this.export = export;
public ApplicationMetricsProperties(MetricExportProperties metricExportProperties) {
Assert.notNull(metricExportProperties, "'metricsExportProperties' cannot be null");
this.metricExportProperties = metricExportProperties;
}
public String getPrefix() {
@@ -114,20 +119,31 @@ public class ApplicationMetricsProperties
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) event
.getSource();
ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) event.getSource();
ConfigurableEnvironment environment = ctx.getEnvironment();
BeanExpressionResolver beanExpressionResolver = ctx.getBeanFactory().getBeanExpressionResolver();
BeanExpressionContext expressionContext = new BeanExpressionContext(ctx.getBeanFactory(), null);
if (!ObjectUtils.isEmpty(this.properties)) {
for (PropertySource<?> source : ctx.getEnvironment().getPropertySources()) {
for (PropertySource<?> source : environment.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)) {
Object value = source.getProperty(propertyName);
String stringValue = ObjectUtils.nullSafeToString(value);
Object exportedValue = null;
if (value != null) {
exportedValue = stringValue.startsWith("#{")
? beanExpressionResolver.evaluate(
environment.resolvePlaceholders(stringValue), expressionContext)
: environment.resolvePlaceholders(stringValue);
}
this.exportProperties.put(
RelaxedPropertiesUtils
.findCanonicalFormat(relaxedNames),
source.getProperty(propertyName));
exportedValue);
break relaxedLoop;
}
}

View File

@@ -20,7 +20,7 @@ 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;
@@ -204,6 +204,44 @@ public class ApplicationMetricsExporterTests {
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(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()));
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 overrideAppName() throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(