diff --git a/spring-cloud-task-core/pom.xml b/spring-cloud-task-core/pom.xml
index 1d177bc4..140e4916 100755
--- a/spring-cloud-task-core/pom.xml
+++ b/spring-cloud-task-core/pom.xml
@@ -106,6 +106,15 @@
spring-boot-autoconfigure-processor
true
+
+ io.micrometer
+ micrometer-core
+
+
+ io.pivotal.cfenv
+ java-cfenv-test-support
+ test
+
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/CloudFoundryMicrometerTagsConfiguration.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/CloudFoundryMicrometerTagsConfiguration.java
new file mode 100644
index 00000000..0c3d3fc3
--- /dev/null
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/CloudFoundryMicrometerTagsConfiguration.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2019-2019 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
+ *
+ * https://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.task.configuration;
+
+import io.micrometer.core.instrument.MeterRegistry;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.task.metrics.fork.MeterRegistryCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+/**
+ * Micrometer common tags for Cloud Foundry deployment properties. Based on the CF
+ * application environment variables:
+ * https://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html
+ *
+ * Tags are set only if the "cloud" Spring profile is set. The "cloud" profile is
+ * activated automatically when an application is deployed in CF:
+ * https://docs.cloudfoundry.org/buildpacks/java/configuring-service-connections/spring-service-bindings.html#cloud-profiles
+ *
+ * Use the spring.cloud.task.metrics.cf.tags.enabled=false property to disable inserting
+ * those tags.
+ *
+ * @author Christian Tzolov
+ */
+@Configuration
+@Profile("cloud")
+@ConditionalOnProperty(name = "spring.cloud.task.metrics.cf.tags.enabled",
+ havingValue = "true", matchIfMissing = true)
+public class CloudFoundryMicrometerTagsConfiguration {
+
+ @Value("${vcap.application.org_name:default}")
+ private String organizationName;
+
+ @Value("${vcap.application.space_id:unknown}")
+ private String spaceId;
+
+ @Value("${vcap.application.space_name:unknown}")
+ private String spaceName;
+
+ @Value("${vcap.application.application_name:unknown}")
+ private String applicationName;
+
+ @Value("${vcap.application.application_id:unknown}")
+ private String applicationId;
+
+ @Value("${vcap.application.application_version:unknown}")
+ private String applicationVersion;
+
+ @Value("${vcap.application.instance_index:0}")
+ private String instanceIndex;
+
+ @Bean
+ public MeterRegistryCustomizer cloudFoundryMetricsCommonTags() {
+ return registry -> registry.config().commonTags("cf.org.name", organizationName)
+ .commonTags("cf.space.id", spaceId).commonTags("cf.space.name", spaceName)
+ .commonTags("cf.app.id", applicationId)
+ .commonTags("cf.app.name", applicationName)
+ .commonTags("cf.app.version", applicationVersion)
+ .commonTags("cf.instance.index", instanceIndex);
+ }
+
+}
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SpringCloudTaskMicrometerCommonTagsConfiguration.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SpringCloudTaskMicrometerCommonTagsConfiguration.java
new file mode 100644
index 00000000..b7bfc2ab
--- /dev/null
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SpringCloudTaskMicrometerCommonTagsConfiguration.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019-2019 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
+ *
+ * https://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.task.configuration;
+
+import io.micrometer.core.instrument.MeterRegistry;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.task.metrics.fork.MeterRegistryCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Auto configuration extends the micrometer metrics with additional tags such as: task
+ * name, application name, instance index and guids. Later are necessary to allow
+ * discrimination and aggregation of app metrics by external metrics collection and
+ * visualizaiton tools.
+ *
+ * Use the spring.cloud.task.metrics.common.tags.enabled=false property to disable
+ * inserting those tags.
+ *
+ * @author Christian Tzolov
+ */
+@Configuration
+@ConditionalOnProperty(name = "spring.cloud.task.metrics.common.tags.enabled",
+ havingValue = "true", matchIfMissing = true)
+public class SpringCloudTaskMicrometerCommonTagsConfiguration {
+
+ @Value("${spring.cloud.task.name:unknown}")
+ private String taskName;
+
+ @Value("${spring.cloud.task.executionid:unknown}")
+ private String taskExecutionId;
+
+ @Value("${spring.cloud.task.external-execution-id:unknown}")
+ private String taskExternalExecutionId;
+
+ @Value("${spring.cloud.task.parent-execution-id:unknown}")
+ private String taskParentExecutionId;
+
+ @Bean
+ public MeterRegistryCustomizer metricsCommonTags() {
+ return registry -> registry.config().commonTags("task.name", taskName)
+ .commonTags("task.execution.id", taskExecutionId)
+ .commonTags("task.external.execution.id", taskExternalExecutionId)
+ .commonTags("task.parent.execution.id", taskParentExecutionId);
+ }
+
+}
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java
index cc151362..b2580996 100644
--- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java
@@ -88,6 +88,8 @@ public class TaskLifecycleListener implements ApplicationListener startupListenerList = new ArrayList<>(
this.taskExecutionListeners);
@@ -334,6 +338,7 @@ public class TaskLifecycleListener implements ApplicationListener
+ * Customizers are guaranteed to be applied before any {@link Meter} is registered with
+ * the registry.
+ *
+ * @author Michael Minella
+ */
+@FunctionalInterface
+public interface MeterRegistryCustomizer {
+
+ /**
+ * Customize the given {@code registry}.
+ * @param registry the registry to customize
+ */
+ void customize(T registry);
+
+}
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/metrics/fork/MetricsAutoConfiguration.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/metrics/fork/MetricsAutoConfiguration.java
new file mode 100644
index 00000000..d2b2ccc1
--- /dev/null
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/metrics/fork/MetricsAutoConfiguration.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2019-2019 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
+ *
+ * https://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.task.metrics.fork;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import io.micrometer.core.annotation.Timed;
+import io.micrometer.core.instrument.Clock;
+import io.micrometer.core.instrument.MeterRegistry;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.util.LambdaSafe;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Forked and stripped down version of the
+ * org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration form
+ * spring-boot-actuator
+ *
+ * {@link EnableAutoConfiguration Auto-configuration} for Micrometer-based metrics.
+ *
+ * @author Michael Minella
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnClass(Timed.class)
+@AutoConfigureBefore(name = {
+ "org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration" })
+public class MetricsAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public Clock micrometerClockFork() {
+ return Clock.SYSTEM;
+ }
+
+ @Bean
+ public static MeterRegistryPostProcessor meterRegistryPostProcessorFork(
+ ObjectProvider> meterRegistryCustomizers) {
+ return new MeterRegistryPostProcessor(meterRegistryCustomizers);
+ }
+
+ /**
+ * Forked and stripped down version of the
+ * org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryPostProcessor
+ * form spring-boot-actuator
+ *
+ * {@link BeanPostProcessor} that delegates to a lazily created
+ * {@link MeterRegistryConfigurer} to post-process {@link MeterRegistry} beans.
+ *
+ */
+ static class MeterRegistryPostProcessor implements BeanPostProcessor {
+
+ private final ObjectProvider> meterRegistryCustomizers;
+
+ private volatile MeterRegistryConfigurer configurer;
+
+ MeterRegistryPostProcessor(
+ ObjectProvider> meterRegistryCustomizers) {
+ this.meterRegistryCustomizers = meterRegistryCustomizers;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+ if (bean instanceof MeterRegistry) {
+ getConfigurer().configure((MeterRegistry) bean);
+ }
+ return bean;
+ }
+
+ private MeterRegistryConfigurer getConfigurer() {
+ if (this.configurer == null) {
+ this.configurer = new MeterRegistryConfigurer(
+ this.meterRegistryCustomizers);
+ }
+ return this.configurer;
+ }
+
+ }
+
+ /**
+ * Forked and stripped down version of the
+ * org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryConfigurer form
+ * spring-boot-actuator
+ *
+ * Configurer to apply {@link MeterRegistryCustomizer customizers} to
+ * {@link MeterRegistry meter registries}.
+ *
+ */
+ static class MeterRegistryConfigurer {
+
+ private final ObjectProvider> customizers;
+
+ MeterRegistryConfigurer(ObjectProvider> customizers) {
+ this.customizers = customizers;
+ }
+
+ void configure(MeterRegistry registry) {
+ customize(registry);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void customize(MeterRegistry registry) {
+ LambdaSafe
+ .callbacks(MeterRegistryCustomizer.class,
+ asOrderedList(this.customizers), registry)
+ .withLogger(MeterRegistryConfigurer.class)
+ .invoke((customizer) -> customizer.customize(registry));
+ }
+
+ private List asOrderedList(ObjectProvider provider) {
+ return provider.orderedStream().collect(Collectors.toList());
+ }
+
+ }
+
+}
diff --git a/spring-cloud-task-core/src/main/resources/META-INF/spring.factories b/spring-cloud-task-core/src/main/resources/META-INF/spring.factories
index 243ca91b..aeba503d 100644
--- a/spring-cloud-task-core/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-task-core/src/main/resources/META-INF/spring.factories
@@ -1,3 +1,7 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.cloud.task.configuration.SingleTaskConfiguration,\
-org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration\
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.springframework.cloud.task.configuration.SingleTaskConfiguration,\
+org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration,\
+org.springframework.cloud.task.configuration.CloudFoundryMicrometerTagsConfiguration,\
+org.springframework.cloud.task.configuration.SpringCloudTaskMicrometerCommonTagsConfiguration,\
+org.springframework.cloud.task.metrics.fork.MetricsAutoConfiguration\
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/AbstractMicrometerTest.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/AbstractMicrometerTest.java
new file mode 100644
index 00000000..97bc286d
--- /dev/null
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/AbstractMicrometerTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2019-2019 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
+ *
+ * https://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.task.micrometer;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import io.micrometer.core.instrument.Clock;
+import io.micrometer.core.instrument.Meter;
+import io.micrometer.core.instrument.Metrics;
+import io.micrometer.core.instrument.simple.SimpleConfig;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import io.pivotal.cfenv.test.CfEnvTestUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.StreamUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Christian Tzolov
+ * @author Soby Chacko
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest(classes = { AbstractMicrometerTest.AutoConfigurationApplication.class })
+@DirtiesContext
+public class AbstractMicrometerTest {
+
+ @Autowired
+ protected SimpleMeterRegistry simpleMeterRegistry;
+
+ @Autowired
+ protected ConfigurableApplicationContext context;
+
+ protected Meter meter;
+
+ @Before
+ public void before() {
+ Metrics.globalRegistry.getMeters().forEach(Metrics.globalRegistry::remove);
+ assertThat(simpleMeterRegistry).isNotNull();
+ meter = simpleMeterRegistry.find("spring.integration.handlers").meter();
+ assertThat(meter).isNotNull().withFailMessage(
+ "The spring.integration.handlers meter must be present in SpringBoot apps!");
+ }
+
+ @After
+ public void after() {
+ Metrics.globalRegistry.getMeters().forEach(Metrics.globalRegistry::remove);
+ }
+
+ @BeforeClass
+ public static void setup() throws IOException {
+ String serviceJson = StreamUtils.copyToString(new DefaultResourceLoader()
+ .getResource("classpath:/micrometer/pcf-scs-info.json").getInputStream(),
+ Charset.forName("UTF-8"));
+ CfEnvTestUtils.mockVcapServicesFromString(serviceJson);
+ }
+
+ @SpringBootApplication
+ public static class AutoConfigurationApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AutoConfigurationApplication.class, args);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public SimpleMeterRegistry simpleMeterRegistry(SimpleConfig config, Clock clock) {
+ return new SimpleMeterRegistry(config, clock);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public SimpleConfig simpleConfig() {
+ return key -> null;
+ }
+
+ }
+
+}
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/CloudFoundryMicrometerTagsConfigurationTest.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/CloudFoundryMicrometerTagsConfigurationTest.java
new file mode 100644
index 00000000..17385606
--- /dev/null
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/CloudFoundryMicrometerTagsConfigurationTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2019-2019 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
+ *
+ * https://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.task.micrometer;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.TestPropertySource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Christian Tzolov
+ */
+@RunWith(Enclosed.class)
+public class CloudFoundryMicrometerTagsConfigurationTest {
+
+ @ActiveProfiles("cloud")
+ public static class ActiveCloudProfileDefaultValues extends AbstractMicrometerTest {
+
+ @Test
+ public void testDefaultTagValues() {
+ assertThat(meter.getId().getTag("cf.org.name")).isEqualTo("default");
+ assertThat(meter.getId().getTag("cf.space.id")).isEqualTo("unknown");
+ assertThat(meter.getId().getTag("cf.space.name")).isEqualTo("unknown");
+ assertThat(meter.getId().getTag("cf.app.name")).isEqualTo("unknown");
+ assertThat(meter.getId().getTag("cf.app.id")).isEqualTo("unknown");
+ assertThat(meter.getId().getTag("cf.app.version")).isEqualTo("unknown");
+ assertThat(meter.getId().getTag("cf.instance.index")).isEqualTo("0");
+ }
+
+ }
+
+ @TestPropertySource(properties = { "vcap.application.org_name=PivotalOrg",
+ "vcap.application.space_id=SpringSpaceId",
+ "vcap.application.space_name=SpringSpace",
+ "vcap.application.application_name=App123",
+ "vcap.application.application_id=123guid",
+ "vcap.application.application_version=2.0",
+ "vcap.application.instance_index=123" })
+ @ActiveProfiles("cloud")
+ public static class ActiveCloudProfile extends AbstractMicrometerTest {
+
+ @Test
+ public void testPresetTagValues() {
+ assertThat(meter.getId().getTag("cf.org.name")).isEqualTo("PivotalOrg");
+ assertThat(meter.getId().getTag("cf.space.id")).isEqualTo("SpringSpaceId");
+ assertThat(meter.getId().getTag("cf.space.name")).isEqualTo("SpringSpace");
+ assertThat(meter.getId().getTag("cf.app.name")).isEqualTo("App123");
+ assertThat(meter.getId().getTag("cf.app.id")).isEqualTo("123guid");
+ assertThat(meter.getId().getTag("cf.app.version")).isEqualTo("2.0");
+ assertThat(meter.getId().getTag("cf.instance.index")).isEqualTo("123");
+ }
+
+ }
+
+ @TestPropertySource(properties = { "vcap.application.org_name=PivotalOrg",
+ "vcap.application.space_id=SpringSpaceId",
+ "vcap.application.space_name=SpringSpace",
+ "vcap.application.application_name=App123",
+ "vcap.application.application_id=123guid",
+ "vcap.application.application_version=2.0",
+ "vcap.application.instance_index=123" })
+ public static class InactiveCloudProfile extends AbstractMicrometerTest {
+
+ @Test
+ public void testDisabledTagValues() {
+ assertThat(meter.getId().getTag("cf.org.name")).isNull();
+ assertThat(meter.getId().getTag("cf.space.id")).isNull();
+ assertThat(meter.getId().getTag("cf.space.name")).isNull();
+ assertThat(meter.getId().getTag("cf.app.name")).isNull();
+ assertThat(meter.getId().getTag("cf.app.id")).isNull();
+ assertThat(meter.getId().getTag("cf.app.version")).isNull();
+ assertThat(meter.getId().getTag("cf.instance.index")).isNull();
+ }
+
+ }
+
+ @TestPropertySource(
+ properties = { "spring.cloud.task.metrics.cf.tags.enabled=false" })
+ @ActiveProfiles("cloud")
+ public static class ActiveCloudProfileDisabledProperty extends InactiveCloudProfile {
+
+ }
+
+}
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/SpringCloudTaskMicrometerCommonTagsConfigurationTest.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/SpringCloudTaskMicrometerCommonTagsConfigurationTest.java
new file mode 100644
index 00000000..d00c013e
--- /dev/null
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/SpringCloudTaskMicrometerCommonTagsConfigurationTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019-2019 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
+ *
+ * https://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.task.micrometer;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import org.springframework.test.context.TestPropertySource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Christian Tzolov
+ */
+@RunWith(Enclosed.class)
+public class SpringCloudTaskMicrometerCommonTagsConfigurationTest {
+
+ public static class TestDefaultTagValues extends AbstractMicrometerTest {
+
+ @Test
+ public void testDefaultTagValues() {
+ assertThat(meter.getId().getTag("task.name")).isEqualTo("unknown");
+ assertThat(meter.getId().getTag("task.execution.id")).isEqualTo("unknown");
+ assertThat(meter.getId().getTag("task.parent.execution.id"))
+ .isEqualTo("unknown");
+ assertThat(meter.getId().getTag("task.external.execution.id"))
+ .isEqualTo("unknown");
+ }
+
+ }
+
+ @TestPropertySource(properties = { "spring.cloud.task.name=myTask",
+ "spring.cloud.task.executionid=123",
+ "spring.cloud.task.parent-execution-id=999",
+ "spring.cloud.task.external-execution-id=696" })
+ public static class TestPresetTagValues extends AbstractMicrometerTest {
+
+ @Test
+ public void testPresetTagValues() {
+ assertThat(meter.getId().getTag("task.name")).isEqualTo("myTask");
+ assertThat(meter.getId().getTag("task.execution.id")).isEqualTo("123");
+ assertThat(meter.getId().getTag("task.parent.execution.id")).isEqualTo("999");
+ assertThat(meter.getId().getTag("task.external.execution.id"))
+ .isEqualTo("696");
+ }
+
+ }
+
+ @TestPropertySource(
+ properties = { "spring.cloud.task.metrics.common.tags.enabled=false" })
+ public static class TestDisabledTagValues extends AbstractMicrometerTest {
+
+ @Test
+ public void testDefaultTagValues() {
+ assertThat(meter.getId().getTag("task.name")).isNull();
+ assertThat(meter.getId().getTag("task.execution.id")).isNull();
+ assertThat(meter.getId().getTag("task.parent.execution.id")).isNull();
+ assertThat(meter.getId().getTag("task.external.execution.id")).isNull();
+ }
+
+ }
+
+}
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/TaskMetricsTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/TaskMetricsTests.java
new file mode 100644
index 00000000..942197f7
--- /dev/null
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/TaskMetricsTests.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2019-2019 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
+ *
+ * https://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.task.micrometer;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+import io.micrometer.core.instrument.LongTaskTimer;
+import io.micrometer.core.instrument.Metrics;
+import io.micrometer.core.instrument.Timer;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.springframework.cloud.task.listener.TaskMetrics;
+import org.springframework.cloud.task.repository.TaskExecution;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Christian Tzolov
+ */
+public class TaskMetricsTests {
+
+ private TaskMetrics taskMetrics;
+
+ private SimpleMeterRegistry simpleMeterRegistry;
+
+ @Before
+ public void before() {
+ Metrics.globalRegistry.getMeters().forEach(Metrics.globalRegistry::remove);
+ simpleMeterRegistry = new SimpleMeterRegistry();
+ Metrics.addRegistry(simpleMeterRegistry);
+ taskMetrics = new TaskMetrics();
+ }
+
+ @After
+ public void after() {
+ Metrics.globalRegistry.getMeters().forEach(Metrics.globalRegistry::remove);
+ }
+
+ @Test
+ public void successfulTask() {
+
+ TaskExecution taskExecution = new TaskExecution(123L, 0, "myTask72", new Date(),
+ new Date(), null, new ArrayList<>(), null, null, -1L);
+
+ // Start Task
+ taskMetrics.onTaskStartup(taskExecution);
+
+ //// Test Long Task Timer while the task is running.
+ LongTaskTimer longTaskTimer = simpleMeterRegistry
+ .find(TaskMetrics.SPRING_CLOUD_TASK_ACTIVE_METER).longTaskTimer();
+ assertThat(longTaskTimer)
+ .withFailMessage("LongTask timer should be created on Task start")
+ .isNotNull();
+ // assertThat(longTaskTimer.activeTasks()).isEqualTo(1);
+ assertThat(longTaskTimer.getId().getTag(TaskMetrics.TASK_NAME_TAG))
+ .isEqualTo("myTask72");
+ assertThat(longTaskTimer.getId().getTag(TaskMetrics.TASK_EXECUTION_ID_TAG))
+ .isEqualTo("123");
+
+ // Finish Task
+ taskMetrics.onTaskEnd(taskExecution);
+
+ // Test Timer
+ Timer taskTimer = simpleMeterRegistry.find(TaskMetrics.SPRING_CLOUD_TASK_METER)
+ .timer();
+ assertThat(taskTimer).isNotNull();
+ // assertThat(taskTimer.count()).isEqualTo(1L);
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_NAME_TAG))
+ .isEqualTo("myTask72");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_EXECUTION_ID_TAG))
+ .isEqualTo("123");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_EXTERNAL_EXECUTION_ID_TAG))
+ .isEqualTo("unknown");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_PARENT_EXECUTION_ID_TAG))
+ .isEqualTo("-1");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_EXIT_CODE_TAG))
+ .isEqualTo("0");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_EXCEPTION_TAG))
+ .isEqualTo("none");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_STATUS_TAG))
+ .isEqualTo(TaskMetrics.STATUS_SUCCESS);
+
+ // Test Long Task Timer after the task has completed.
+ // LongTaskTimer longTaskTimer = simpleMeterRegistry
+ // .find(TaskMetrics.SPRING_CLOUD_TASK_ACTIVE_METER).longTaskTimer();
+ assertThat(longTaskTimer.activeTasks()).isEqualTo(0);
+ assertThat(longTaskTimer.getId().getTag(TaskMetrics.TASK_NAME_TAG))
+ .isEqualTo("myTask72");
+ assertThat(longTaskTimer.getId().getTag(TaskMetrics.TASK_EXECUTION_ID_TAG))
+ .isEqualTo("123");
+ }
+
+ @Test
+ public void failingTask() {
+
+ TaskExecution taskExecution = new TaskExecution(123L, 0, "myTask", new Date(),
+ new Date(), null, new ArrayList<>(), null, null, -1L);
+
+ // Start Task
+ taskMetrics.onTaskStartup(taskExecution);
+
+ // Test Long Task Timer while the task is running.
+ LongTaskTimer longTaskTimer = simpleMeterRegistry
+ .find(TaskMetrics.SPRING_CLOUD_TASK_ACTIVE_METER).longTaskTimer();
+ assertThat(longTaskTimer)
+ .withFailMessage("LongTask timer should be created on Task start")
+ .isNotNull();
+ assertThat(longTaskTimer.activeTasks()).isEqualTo(1);
+ assertThat(longTaskTimer.getId().getTag(TaskMetrics.TASK_NAME_TAG))
+ .isEqualTo("myTask");
+ assertThat(longTaskTimer.getId().getTag(TaskMetrics.TASK_EXECUTION_ID_TAG))
+ .isEqualTo("123");
+
+ taskMetrics.onTaskFailed(taskExecution, new RuntimeException("Test"));
+
+ // Finish Task. TaskLifecycleListen calls onTaskEnd after the onTaskFailed. Make
+ // sure that the counter status
+ // is not affected by this.
+ taskMetrics.onTaskEnd(taskExecution);
+
+ Timer taskTimer = simpleMeterRegistry.find(TaskMetrics.SPRING_CLOUD_TASK_METER)
+ .timer();
+ assertThat(taskTimer).isNotNull();
+
+ assertThat(taskTimer).isNotNull();
+ // assertThat(taskTimer.count()).isEqualTo(1L);
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_NAME_TAG))
+ .isEqualTo("myTask");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_EXECUTION_ID_TAG))
+ .isEqualTo("123");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_EXTERNAL_EXECUTION_ID_TAG))
+ .isEqualTo("unknown");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_PARENT_EXECUTION_ID_TAG))
+ .isEqualTo("-1");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_EXIT_CODE_TAG))
+ .isEqualTo("0");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_EXCEPTION_TAG))
+ .isEqualTo("RuntimeException");
+ assertThat(taskTimer.getId().getTag(TaskMetrics.TASK_STATUS_TAG))
+ .isEqualTo(TaskMetrics.STATUS_FAILURE);
+
+ // Test Long Task Timer after the task has completed.
+ assertThat(longTaskTimer.activeTasks()).isEqualTo(0);
+ assertThat(longTaskTimer.getId().getTag(TaskMetrics.TASK_NAME_TAG))
+ .isEqualTo("myTask");
+ assertThat(longTaskTimer.getId().getTag(TaskMetrics.TASK_EXECUTION_ID_TAG))
+ .isEqualTo("123");
+ }
+
+}
diff --git a/spring-cloud-task-core/src/test/resources/micrometer/pcf-scs-info.json b/spring-cloud-task-core/src/test/resources/micrometer/pcf-scs-info.json
new file mode 100644
index 00000000..adede92b
--- /dev/null
+++ b/spring-cloud-task-core/src/test/resources/micrometer/pcf-scs-info.json
@@ -0,0 +1,13 @@
+{
+ "sso":[{
+ "name": "sso",
+ "label": "sso",
+ "plan": "notfree",
+ "tags": ["configuration"],
+ "credentials":{
+ "uri": "https://pivotal.io",
+ "client_id": "fakeClientId",
+ "client_secret": "fakeSecret",
+ "access_token_uri": "token"
+ }
+ }]}
diff --git a/spring-cloud-task-dependencies/pom.xml b/spring-cloud-task-dependencies/pom.xml
index 9f34f679..e06c3d7c 100644
--- a/spring-cloud-task-dependencies/pom.xml
+++ b/spring-cloud-task-dependencies/pom.xml
@@ -14,6 +14,10 @@
+
+ 1.0.1.RELEASE
+
+
@@ -36,6 +40,11 @@
spring-cloud-task-stream
2.2.0.BUILD-SNAPSHOT
+
+ io.pivotal.cfenv
+ java-cfenv-test-support
+ ${java-cfenv-boot.version}
+