Updating task metrics to micrometer 1.10
Changes include: * Use Observable instead of metrics * Update the setting of lowCardinalityTag to the correct events. * Update the docs * Remove EXTERNAL_EXECUTION_ID * Utilize registry provided by boot instead of globalregistry * Set the handler until Boot does this as shown on line 80 of TaskLifecycleConfiguration. * Uses Observability long task timer Updated to latest changes in Micrometer Observability Updated based on code review and api change Finished removing the metrics registry Updated based on code review Readded cloud foundry keys to observations Renamed metrics to observations where applicable Updated metric sample to be observation sample Updated to set defaults and migrate tests to infrastructure Updated based on code review Remove duplicate keyvalues from task observation Added DocumentedObservation to create the observation Migrated code to use the LowerCardinality KeyNames from the DocumentedObservation Test cleanup Updated code based on code review Exception is handled by the error in the observation vs logging it as a task metric key value Updated to use ObservationConvention Updated to handle user defined convention vs default Removed the snapshot versions of observations Removed unnecessary dependencies Checkpoint tests fail after re-adding 1.10-SNAPSHOT Replaced TimeObservationHandler with DefaultMeterObservationHandler Updated to set micrometer to latest milestone Updated to rename TaskValuesProvider variables to ObservationConvention
This commit is contained in:
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* 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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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 mockit.Mock;
|
||||
import mockit.MockUp;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
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.junit.jupiter.SpringExtension;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
* @author Soby Chacko
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(classes = { AbstractMicrometerTest.AutoConfigurationApplication.class })
|
||||
@DirtiesContext
|
||||
public class AbstractMicrometerTest {
|
||||
|
||||
@Autowired
|
||||
protected SimpleMeterRegistry simpleMeterRegistry;
|
||||
|
||||
@Autowired
|
||||
protected ConfigurableApplicationContext context;
|
||||
|
||||
protected Meter meter;
|
||||
|
||||
@BeforeEach
|
||||
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!");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() {
|
||||
Metrics.globalRegistry.getMeters().forEach(Metrics.globalRegistry::remove);
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
String serviceJson = StreamUtils.copyToString(new DefaultResourceLoader()
|
||||
.getResource("classpath:/micrometer/pcf-scs-info.json").getInputStream(),
|
||||
Charset.forName("UTF-8"));
|
||||
mockVcapServicesFromString(serviceJson);
|
||||
}
|
||||
|
||||
public static MockUp<?> mockVcapServicesFromString(String serviceJson) {
|
||||
final Map<String, String> env = System.getenv();
|
||||
return new MockUp<System>() {
|
||||
@Mock
|
||||
public String getenv(String name) {
|
||||
if (name.equalsIgnoreCase("VCAP_SERVICES")) {
|
||||
return serviceJson;
|
||||
}
|
||||
else {
|
||||
return name.equalsIgnoreCase("VCAP_APPLICATION")
|
||||
? "{\"instance_id\":\"123\"}" : (String) env.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Mock
|
||||
public Map getenv() {
|
||||
Map<String, String> finalMap = new HashMap();
|
||||
finalMap.putAll(env);
|
||||
finalMap.put("VCAP_SERVICES", serviceJson);
|
||||
return finalMap;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* 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.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
@Nested
|
||||
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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* 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.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
*/
|
||||
@Nested
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* 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.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.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;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
Metrics.globalRegistry.getMeters().forEach(Metrics.globalRegistry::remove);
|
||||
simpleMeterRegistry = new SimpleMeterRegistry();
|
||||
Metrics.addRegistry(simpleMeterRegistry);
|
||||
taskMetrics = new TaskMetrics();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
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(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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Copyright 2019-2022 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.Tags;
|
||||
import io.micrometer.core.instrument.observation.TimerObservationHandler;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import io.micrometer.core.tck.MeterRegistryAssert;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.ObservationHandler;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.observation.tck.ObservationRegistryAssert;
|
||||
import io.micrometer.observation.tck.TestObservationRegistry;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.task.configuration.TaskObservationCloudKeyValues;
|
||||
import org.springframework.cloud.task.listener.TaskExecutionObservation;
|
||||
import org.springframework.cloud.task.listener.TaskObservations;
|
||||
import org.springframework.cloud.task.repository.TaskExecution;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.task.listener.TaskObservations.UNKNOWN;
|
||||
|
||||
/**
|
||||
* @author Christian Tzolov
|
||||
* @author Glenn Renfro
|
||||
*/
|
||||
public class TaskObservationsTests {
|
||||
|
||||
public static final String PREFIX = "spring.cloud.task";
|
||||
|
||||
private TaskObservations taskObservations;
|
||||
|
||||
private SimpleMeterRegistry simpleMeterRegistry;
|
||||
|
||||
private ObservationRegistry observationRegistry;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
this.simpleMeterRegistry = new SimpleMeterRegistry();
|
||||
this.observationRegistry = TestObservationRegistry.create();
|
||||
ObservationHandler<Observation.Context> timerObservationHandler = new TimerObservationHandler(this.simpleMeterRegistry);
|
||||
this.observationRegistry.observationConfig().observationHandler(timerObservationHandler);
|
||||
this.taskObservations = new TaskObservations(this.observationRegistry, null, null);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() {
|
||||
this.simpleMeterRegistry.clear();
|
||||
ObservationRegistryAssert.assertThat(this.observationRegistry).doesNotHaveAnyRemainingCurrentObservation();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successfulTaskTest() {
|
||||
|
||||
TaskExecution taskExecution = startupObservationForBasicTests("myTask72", 123L);
|
||||
|
||||
LongTaskTimer longTaskTimer = initializeBasicTest("myTask72", "123");
|
||||
|
||||
// Finish Task
|
||||
taskObservations.onTaskEnd(taskExecution);
|
||||
|
||||
verifyDefaultKeyValues();
|
||||
TaskExecutionObservation.TASK_ACTIVE.getDefaultConvention();
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags("spring.cloud.task",
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_STATUS.getKeyName(), TaskObservations.STATUS_SUCCESS));
|
||||
|
||||
verifyLongTaskTimerAfterStop(longTaskTimer, "myTask72", "123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultTaskTest() {
|
||||
|
||||
TaskExecution taskExecution = new TaskExecution(123L, 0, null, new Date(),
|
||||
new Date(), null, new ArrayList<>(), null, null, null);
|
||||
|
||||
// Start Task
|
||||
taskObservations.onTaskStartup(taskExecution);
|
||||
|
||||
LongTaskTimer longTaskTimer = initializeBasicTest(UNKNOWN, "123");
|
||||
|
||||
|
||||
// Finish Task
|
||||
taskObservations.onTaskEnd(taskExecution);
|
||||
|
||||
// Test Timer
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_NAME.getKeyName(), UNKNOWN));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.getKeyName(), "123"));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_PARENT_EXECUTION_ID.getKeyName(), UNKNOWN));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXTERNAL_EXECUTION_ID.getKeyName(), UNKNOWN));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXIT_CODE.getKeyName(), "0"));
|
||||
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_STATUS.getKeyName(), TaskObservations.STATUS_SUCCESS));
|
||||
|
||||
verifyLongTaskTimerAfterStop(longTaskTimer, "unknown", "123");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failingTask() {
|
||||
|
||||
TaskExecution taskExecution = startupObservationForBasicTests("myTask72", 123L);
|
||||
|
||||
LongTaskTimer longTaskTimer = initializeBasicTest("myTask72", "123");
|
||||
|
||||
taskObservations.onTaskFailed(new RuntimeException("Test"));
|
||||
|
||||
// Finish Task. TaskLifecycleListen calls onTaskEnd after the onTaskFailed. Make
|
||||
// sure that the counter status
|
||||
// is not affected by this.
|
||||
taskExecution.setExitCode(1);
|
||||
taskObservations.onTaskEnd(taskExecution);
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_NAME.getKeyName(), "myTask72"));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.getKeyName(), "123"));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_PARENT_EXECUTION_ID.getKeyName(), "-1"));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXIT_CODE.getKeyName(), "1"));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_STATUS.getKeyName(), TaskObservations.STATUS_FAILURE));
|
||||
|
||||
verifyLongTaskTimerAfterStop(longTaskTimer, "myTask72", "123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void taskWithCloudKeyValues() {
|
||||
final String APPLICATION_ID = "123";
|
||||
final String APPLICATION_NAME = "APP123";
|
||||
final String SPACE_ID = "123";
|
||||
final String SPACE_NAME = "SPACE123";
|
||||
final String APPLICATION_VERSION = "APPV123";
|
||||
final String INSTANCE_INDEX = "55";
|
||||
final String ORGANIZATION_NAME = "ORG123";
|
||||
TaskObservationCloudKeyValues taskObservationCloudKeyValues = new TaskObservationCloudKeyValues();
|
||||
taskObservationCloudKeyValues.setApplicationId(APPLICATION_ID);
|
||||
taskObservationCloudKeyValues.setApplicationName(APPLICATION_NAME);
|
||||
taskObservationCloudKeyValues.setSpaceId(SPACE_ID);
|
||||
taskObservationCloudKeyValues.setSpaceName(SPACE_NAME);
|
||||
taskObservationCloudKeyValues.setApplicationVersion(APPLICATION_VERSION);
|
||||
taskObservationCloudKeyValues.setInstanceIndex(INSTANCE_INDEX);
|
||||
taskObservationCloudKeyValues.setOrganizationName(ORGANIZATION_NAME);
|
||||
this.taskObservations = new TaskObservations(this.observationRegistry, taskObservationCloudKeyValues, null);
|
||||
|
||||
TaskExecution taskExecution = startupObservationForBasicTests("myTask72", 123L);
|
||||
|
||||
LongTaskTimer longTaskTimer = initializeBasicTest("myTask72", "123");
|
||||
|
||||
// Finish Task
|
||||
taskObservations.onTaskEnd(taskExecution);
|
||||
|
||||
verifyDefaultKeyValues();
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_ORG_NAME.getKeyName(), ORGANIZATION_NAME));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_SPACE_ID.getKeyName(), SPACE_ID));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_SPACE_NAME.getKeyName(), SPACE_NAME));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_NAME.getKeyName(), APPLICATION_NAME));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_ID.getKeyName(), APPLICATION_ID));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_VERSION.getKeyName(), APPLICATION_VERSION));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_INSTANCE_INDEX.getKeyName(), INSTANCE_INDEX));
|
||||
|
||||
// Test Timer
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_NAME.getKeyName(), "myTask72"));
|
||||
|
||||
verifyLongTaskTimerAfterStop(longTaskTimer, "myTask72", "123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloudVariablesUninitialized() {
|
||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(
|
||||
CloudConfigurationForDefaultValues.class));
|
||||
applicationContextRunner.run((context) -> {
|
||||
TaskObservationCloudKeyValues taskObservationCloudKeyValues = context
|
||||
.getBean(TaskObservationCloudKeyValues.class);
|
||||
|
||||
assertThat(taskObservationCloudKeyValues)
|
||||
.as("taskObservationCloudKeyValues should not be null").isNotNull();
|
||||
|
||||
this.taskObservations = new TaskObservations(this.observationRegistry, taskObservationCloudKeyValues, null);
|
||||
|
||||
TaskExecution taskExecution = startupObservationForBasicTests("myTask72", 123L);
|
||||
|
||||
LongTaskTimer longTaskTimer = initializeBasicTest("myTask72", "123");
|
||||
|
||||
// Finish Task
|
||||
taskObservations.onTaskEnd(taskExecution);
|
||||
|
||||
verifyDefaultKeyValues();
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_ORG_NAME.getKeyName(), "default"));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_SPACE_ID.getKeyName(), UNKNOWN));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_SPACE_NAME.getKeyName(), UNKNOWN));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_NAME.getKeyName(), UNKNOWN));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_ID.getKeyName(), UNKNOWN));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_VERSION.getKeyName(), UNKNOWN));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_INSTANCE_INDEX.getKeyName(), "0"));
|
||||
|
||||
// Test Timer
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_NAME.getKeyName(), "myTask72"));
|
||||
|
||||
verifyLongTaskTimerAfterStop(longTaskTimer, "myTask72", "123");
|
||||
});
|
||||
}
|
||||
|
||||
private TaskExecution startupObservationForBasicTests(String taskName, long taskExecutionId) {
|
||||
TaskExecution taskExecution = new TaskExecution(taskExecutionId, 0, taskName, new Date(),
|
||||
new Date(), null, new ArrayList<>(), null, "-1", -1L);
|
||||
|
||||
// Start Task
|
||||
taskObservations.onTaskStartup(taskExecution);
|
||||
return taskExecution;
|
||||
}
|
||||
|
||||
private LongTaskTimer initializeBasicTest(String taskName, String executionId) {
|
||||
// Test Long Task Timer while the task is running.
|
||||
LongTaskTimer longTaskTimer = simpleMeterRegistry
|
||||
.find(TaskExecutionObservation.TASK_ACTIVE.getPrefix() + ".active").longTaskTimer();
|
||||
System.out.println(simpleMeterRegistry.getMetersAsString());
|
||||
assertThat(longTaskTimer)
|
||||
.withFailMessage("LongTask timer should be created on Task start")
|
||||
.isNotNull();
|
||||
assertThat(longTaskTimer.activeTasks()).isEqualTo(1);
|
||||
assertThat(longTaskTimer.getId().getTag(TaskExecutionObservation.TaskKeyValues.TASK_NAME.getKeyName()))
|
||||
.isEqualTo(taskName);
|
||||
assertThat(longTaskTimer.getId().getTag(TaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.getKeyName()))
|
||||
.isEqualTo(executionId);
|
||||
return longTaskTimer;
|
||||
}
|
||||
|
||||
private void verifyDefaultKeyValues() {
|
||||
// Test Timer
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_NAME.getKeyName(), "myTask72"));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.getKeyName(), "123"));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_PARENT_EXECUTION_ID.getKeyName(), "-1"));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXIT_CODE.getKeyName(), "0"));
|
||||
|
||||
MeterRegistryAssert.assertThat(this.simpleMeterRegistry)
|
||||
.hasTimerWithNameAndTags(PREFIX,
|
||||
Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_STATUS.getKeyName(), TaskObservations.STATUS_SUCCESS));
|
||||
}
|
||||
|
||||
private void verifyLongTaskTimerAfterStop(LongTaskTimer longTaskTimer, String taskName, String executionId) {
|
||||
// Test Long Task Timer after the task has completed.
|
||||
assertThat(longTaskTimer.activeTasks()).isEqualTo(0);
|
||||
assertThat(longTaskTimer.getId().getTag(TaskExecutionObservation.TaskKeyValues.TASK_NAME.getKeyName()))
|
||||
.isEqualTo(taskName);
|
||||
assertThat(longTaskTimer.getId().getTag(TaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.getKeyName()))
|
||||
.isEqualTo(executionId);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CloudConfigurationForDefaultValues {
|
||||
@Bean
|
||||
public TaskObservationCloudKeyValues taskObservationCloudKeyValues() {
|
||||
return new TaskObservationCloudKeyValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,13 @@ package org.springframework.cloud.task.util;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.task.configuration.TaskObservationCloudKeyValues;
|
||||
import org.springframework.cloud.task.configuration.TaskProperties;
|
||||
import org.springframework.cloud.task.listener.TaskLifecycleListener;
|
||||
import org.springframework.cloud.task.listener.TaskListenerExecutorObjectFactory;
|
||||
@@ -82,10 +85,12 @@ public class TestDefaultConfiguration implements InitializingBean {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TaskLifecycleListener taskHandler(TaskExplorer taskExplorer) {
|
||||
public TaskLifecycleListener taskHandler(TaskExplorer taskExplorer,
|
||||
@Autowired(required = false) io.micrometer.core.instrument.MeterRegistry meterRegistry, @Autowired(required = false) ObservationRegistry observationRegistry) {
|
||||
|
||||
return new TaskLifecycleListener(taskRepository(), taskNameResolver(),
|
||||
this.applicationArguments, taskExplorer, this.taskProperties,
|
||||
taskListenerExecutorObjectProvider(this.context));
|
||||
taskListenerExecutorObjectProvider(this.context), observationRegistry, new TaskObservationCloudKeyValues());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user