/* * 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 */ 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((String) 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((String) 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((String) 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((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(); } @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((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(); } @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((String) 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((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 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((String) 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((String) 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 { } }