From 165e62197f39c61b597ccdacff877c35616205e8 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Mon, 14 Feb 2022 12:34:46 +0100 Subject: [PATCH 1/9] Added observation API --- pom.xml | 1 + spring-batch-core/pom.xml | 6 + .../batch/core/job/AbstractJob.java | 32 +++-- .../batch/core/job/BatchJobObservation.java | 101 ++++++++++++++++ .../batch/core/metrics/BatchMetrics.java | 21 ++++ .../batch/core/step/AbstractStep.java | 34 ++++-- .../batch/core/step/BatchStepObservation.java | 112 ++++++++++++++++++ .../batch/core/job/SimpleJobTests.java | 16 +++ .../batch/core/step/NonAbstractStepTests.java | 14 +++ spring-batch-docs/pom.xml | 61 ++++++++++ .../src/main/asciidoc/appendix.adoc | 9 ++ spring-batch-test/pom.xml | 6 + .../ObservabilitySampleStepTests.java | 98 +++++++++++++++ 13 files changed, 493 insertions(+), 18 deletions(-) create mode 100644 spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobObservation.java create mode 100644 spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepObservation.java create mode 100644 spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java diff --git a/pom.xml b/pom.xml index 92443d2c0b..eb1641f149 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,7 @@ 1.3.1 6.0.0-SNAPSHOT 2.0.0-SNAPSHOT + 1.0.0-SNAPSHOT 2.13.1 diff --git a/spring-batch-core/pom.xml b/spring-batch-core/pom.xml index 3d14bf9f99..49a952bdaf 100644 --- a/spring-batch-core/pom.xml +++ b/spring-batch-core/pom.xml @@ -256,6 +256,12 @@ ${jakarta.inject-api.version} test + + io.micrometer + micrometer-test + ${micrometer.version} + test + diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java index 5b3ac1502a..08ea8b977a 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java @@ -18,10 +18,12 @@ import java.util.Collection; import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; import io.micrometer.api.instrument.LongTaskTimer; import io.micrometer.api.instrument.Tag; -import io.micrometer.api.instrument.Timer; +import io.micrometer.api.instrument.observation.Observation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.core.BatchStatus; @@ -304,8 +306,9 @@ public final void execute(JobExecution execution) { LongTaskTimer longTaskTimer = BatchMetrics.createLongTaskTimer("job.active", "Active jobs", Tag.of("name", execution.getJobInstance().getJobName())); LongTaskTimer.Sample longTaskTimerSample = longTaskTimer.start(); - Timer.Sample timerSample = BatchMetrics.createTimerSample(); - try { + Observation observation = BatchMetrics.createObservation(BatchJobObservation.BATCH_JOB_OBSERVATION.getName()) + .contextualName(execution.getJobInstance().getJobName()).start(); + try (Observation.Scope scope = observation.openScope()) { jobParametersValidator.validate(execution.getJobParameters()); @@ -361,11 +364,7 @@ public final void execute(JobExecution execution) { ExitStatus.NOOP.addExitDescription("All steps already completed or no steps configured for this job."); execution.setExitStatus(exitStatus.and(newExitStatus)); } - - timerSample.stop(BatchMetrics.createTimer("job", "Job duration", - Tag.of("name", execution.getJobInstance().getJobName()), - Tag.of("status", execution.getExitStatus().getExitCode()) - )); + stopTaggedObservation(execution, observation); longTaskTimerSample.stop(); execution.setEndTime(new Date()); @@ -384,6 +383,23 @@ public final void execute(JobExecution execution) { } + private void stopTaggedObservation(JobExecution execution, Observation observation) { + observation.lowCardinalityTag(BatchJobObservation.JobLowCardinalityTags.JOB_NAME.of(execution.getJobInstance().getJobName())) + .lowCardinalityTag(BatchJobObservation.JobLowCardinalityTags.JOB_STATUS.of(execution.getExitStatus().getExitCode())) + .highCardinalityTag(BatchJobObservation.JobHighCardinalityTags.JOB_INSTANCE_ID.of(String.valueOf(execution.getJobInstance().getInstanceId()))) + .highCardinalityTag(BatchJobObservation.JobHighCardinalityTags.JOB_EXECUTION_ID.of(String.valueOf(execution.getId()))); + List throwables = execution.getFailureExceptions(); + if (!throwables.isEmpty()) { + observation.error(mergedThrowables(throwables)); + } + observation.stop(); + } + + private IllegalStateException mergedThrowables(List throwables) { + return new IllegalStateException( + throwables.stream().map(Throwable::toString).collect(Collectors.joining("\n"))); + } + /** * Convenience method for subclasses to delegate the handling of a specific * step in the context of the current {@link JobExecution}. Clients of this diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobObservation.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobObservation.java new file mode 100644 index 0000000000..e49e95b271 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobObservation.java @@ -0,0 +1,101 @@ +/* + * Copyright 2013-2021 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.batch.core.job; + +import io.micrometer.api.instrument.docs.DocumentedObservation; +import io.micrometer.api.instrument.docs.TagKey; + +enum BatchJobObservation implements DocumentedObservation { + + /** + * Observation created around a Job execution. + */ + BATCH_JOB_OBSERVATION { + @Override + public String getName() { + return "spring.batch.job"; + } + + @Override + public String getContextualName() { + return "%s"; + } + + @Override + public TagKey[] getLowCardinalityTagKeys() { + return JobLowCardinalityTags.values(); + } + + @Override + public TagKey[] getHighCardinalityTagKeys() { + return JobHighCardinalityTags.values(); + } + + @Override + public String getPrefix() { + return "spring.batch"; + } + }; + + enum JobLowCardinalityTags implements TagKey { + + /** + * Name of the Spring Batch job. + */ + JOB_NAME { + @Override + public String getKey() { + return "spring.batch.job.name"; + } + }, + + /** + * Job status. + */ + JOB_STATUS { + @Override + public String getKey() { + return "spring.batch.job.status"; + } + } + + } + + enum JobHighCardinalityTags implements TagKey { + + /** + * ID of the Spring Batch job instance. + */ + JOB_INSTANCE_ID { + @Override + public String getKey() { + return "spring.batch.job.instanceId"; + } + }, + + /** + * ID of the Spring Batch execution. + */ + JOB_EXECUTION_ID { + @Override + public String getKey() { + return "spring.batch.job.executionId"; + } + } + + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java b/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java index 8ac8c28bc7..9e7b389443 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java @@ -21,9 +21,13 @@ import java.util.concurrent.TimeUnit; import io.micrometer.api.instrument.LongTaskTimer; +import io.micrometer.api.instrument.MeterRegistry; import io.micrometer.api.instrument.Metrics; import io.micrometer.api.instrument.Tag; import io.micrometer.api.instrument.Timer; +import io.micrometer.api.instrument.observation.Observation; +import io.micrometer.api.instrument.observation.TimerObservationHandler; +import io.micrometer.api.instrument.simple.SimpleMeterRegistry; import org.springframework.lang.Nullable; @@ -52,6 +56,14 @@ public final class BatchMetrics { private BatchMetrics() {} + private static final MeterRegistry simpleMeterRegistry = new SimpleMeterRegistry().withTimerObservationHandler(); + + static { + // TODO: This shouldn't be necessary - we need to fix it in Micrometer + Metrics.globalRegistry.observationConfig().observationHandler(new TimerObservationHandler(Metrics.globalRegistry)); + Metrics.globalRegistry.add(simpleMeterRegistry); + } + /** * Create a {@link Timer}. * @param name of the timer. Will be prefixed with {@link BatchMetrics#METRICS_PREFIX}. @@ -66,6 +78,15 @@ public static Timer createTimer(String name, String description, Tag... tags) { .register(Metrics.globalRegistry); } + /** + * Create a new {@link Observation}. It's not started, you must + * explicitly call {@link Observation#start()} to start it. + * @return a new timer sample instance + */ + public static Observation createObservation(String name) { + return Observation.createNotStarted(name, Metrics.globalRegistry); + } + /** * Create a new {@link Timer.Sample}. * @return a new timer sample instance diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java index 91b5d519d2..af01451de9 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java @@ -17,9 +17,10 @@ import java.time.Duration; import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; -import io.micrometer.api.instrument.Tag; -import io.micrometer.api.instrument.Timer; +import io.micrometer.api.instrument.observation.Observation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.core.BatchStatus; @@ -192,7 +193,8 @@ public final void execute(StepExecution stepExecution) throws JobInterruptedExce } stepExecution.setStartTime(new Date()); stepExecution.setStatus(BatchStatus.STARTED); - Timer.Sample sample = BatchMetrics.createTimerSample(); + Observation observation = BatchMetrics.createObservation(BatchStepObservation.BATCH_STEP_OBSERVATION.getName()) + .contextualName(stepExecution.getStepName()).start(); getJobRepository().update(stepExecution); // Start with a default value that will be trumped by anything @@ -200,7 +202,7 @@ public final void execute(StepExecution stepExecution) throws JobInterruptedExce doExecutionRegistration(stepExecution); - try { + try (Observation.Scope scope = observation.openScope()) { getCompositeListener().beforeStep(stepExecution); open(stepExecution.getExecutionContext()); @@ -260,12 +262,7 @@ public final void execute(StepExecution stepExecution) throws JobInterruptedExce logger.error(String.format("Encountered an error saving batch meta data for step %s in job %s. " + "This job is now in an unknown state and should not be restarted.", name, stepExecution.getJobExecution().getJobInstance().getJobName()), e); } - - sample.stop(BatchMetrics.createTimer("step", "Step duration", - Tag.of("job.name", stepExecution.getJobExecution().getJobInstance().getJobName()), - Tag.of("name", stepExecution.getStepName()), - Tag.of("status", stepExecution.getExitStatus().getExitCode()) - )); + stopTaggedObservation(stepExecution, observation); stepExecution.setEndTime(new Date()); stepExecution.setExitStatus(exitStatus); Duration stepExecutionDuration = BatchMetrics.calculateDuration(stepExecution.getStartTime(), stepExecution.getEndTime()); @@ -299,6 +296,23 @@ public final void execute(StepExecution stepExecution) throws JobInterruptedExce } } + private void stopTaggedObservation(StepExecution stepExecution, Observation observation) { + observation.lowCardinalityTag(BatchStepObservation.StepLowCardinalityTags.STEP_NAME.of(stepExecution.getStepName())) + .lowCardinalityTag(BatchStepObservation.StepLowCardinalityTags.JOB_NAME.of(stepExecution.getJobExecution().getJobInstance().getJobName())) + .lowCardinalityTag(BatchStepObservation.StepLowCardinalityTags.STEP_STATUS.of(stepExecution.getExitStatus().getExitCode())) + .highCardinalityTag(BatchStepObservation.StepHighCardinalityTags.STEP_EXECUTION_ID.of(String.valueOf(stepExecution.getId()))); + List throwables = stepExecution.getFailureExceptions(); + if (!throwables.isEmpty()) { + observation.error(mergedThrowables(throwables)); + } + observation.stop(); + } + + private IllegalStateException mergedThrowables(List throwables) { + return new IllegalStateException( + throwables.stream().map(Throwable::toString).collect(Collectors.joining("\n"))); + } + /** * Releases the most recent {@link StepExecution} */ diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepObservation.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepObservation.java new file mode 100644 index 0000000000..db596b31de --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepObservation.java @@ -0,0 +1,112 @@ +/* + * Copyright 2013-2021 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.batch.core.step; + +import io.micrometer.api.instrument.docs.DocumentedObservation; +import io.micrometer.api.instrument.docs.TagKey; + +enum BatchStepObservation implements DocumentedObservation { + + /** + * Observation created around a Job execution. + */ + BATCH_STEP_OBSERVATION { + @Override + public String getName() { + return "spring.batch.step"; + } + + @Override + public String getContextualName() { + return "%s"; + } + + @Override + public TagKey[] getLowCardinalityTagKeys() { + return StepLowCardinalityTags.values(); + } + + @Override + public TagKey[] getHighCardinalityTagKeys() { + return StepHighCardinalityTags.values(); + } + + @Override + public String getPrefix() { + return "spring.batch"; + } + }; + + enum StepLowCardinalityTags implements TagKey { + + /** + * Name of the Spring Batch job. + */ + STEP_NAME { + @Override + public String getKey() { + return "spring.batch.step.name"; + } + }, + + /** + * Type of the Spring Batch job. + */ + STEP_TYPE { + @Override + public String getKey() { + return "spring.batch.step.type"; + } + }, + + /** + * Name of the Spring Batch job. + */ + JOB_NAME { + @Override + public String getKey() { + return "spring.batch.job.name"; + } + }, + + /** + * Step status. + */ + STEP_STATUS { + @Override + public String getKey() { + return "spring.batch.step.status"; + } + } + + } + + enum StepHighCardinalityTags implements TagKey { + + /** + * ID of the Spring Batch execution. + */ + STEP_EXECUTION_ID { + @Override + public String getKey() { + return "spring.batch.step.executionId"; + } + } + + } + +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java index 7f202683e8..a53b26a6a3 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java @@ -31,8 +31,15 @@ import java.util.Date; import java.util.List; +import io.micrometer.api.instrument.Metrics; +import io.micrometer.api.instrument.Tag; +import io.micrometer.api.instrument.Tags; +import io.micrometer.core.tck.MeterRegistryAssert; +import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.AfterEach; + import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.ExitStatus; import org.springframework.batch.core.JobExecution; @@ -211,6 +218,15 @@ public void testRunNormally() throws Exception { assertTrue(step1.passedInJobContext.isEmpty()); assertFalse(step2.passedInJobContext.isEmpty()); + + // Observability + MeterRegistryAssert.assertThat(Metrics.globalRegistry) + .hasTimerWithNameAndTags(BatchJobObservation.BATCH_JOB_OBSERVATION.getName(), Tags.of(Tag.of("error", "none"), Tag.of("spring.batch.job.name", "testJob"), Tag.of("spring.batch.job.status", "COMPLETED"))); + } + + @After + public void cleanup() { + Metrics.globalRegistry.clear(); } @Test diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java index f6b81e7b85..160434828a 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java @@ -23,6 +23,11 @@ import java.util.ArrayList; import java.util.List; +import io.micrometer.api.instrument.Metrics; +import io.micrometer.api.instrument.Tag; +import io.micrometer.api.instrument.Tags; +import io.micrometer.core.tck.MeterRegistryAssert; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.batch.core.BatchStatus; @@ -198,6 +203,15 @@ public void testExecute() throws Exception { repository.saved.containsKey("beforeStep")); assertTrue("Execution context modifications made by listener should be persisted", repository.saved.containsKey("afterStep")); + + // Observability + MeterRegistryAssert.assertThat(Metrics.globalRegistry) + .hasTimerWithNameAndTags(BatchStepObservation.BATCH_STEP_OBSERVATION.getName(), Tags.of(Tag.of("error", "none"), Tag.of("spring.batch.job.name", "jobName"), Tag.of("spring.batch.step.name", "eventTrackingStep"), Tag.of("spring.batch.step.status", "COMPLETED"))); + } + + @After + public void cleanup() { + Metrics.globalRegistry.clear(); } @Test diff --git a/spring-batch-docs/pom.xml b/spring-batch-docs/pom.xml index 493fedc63c..ca02fc007f 100644 --- a/spring-batch-docs/pom.xml +++ b/spring-batch-docs/pom.xml @@ -10,6 +10,14 @@ Spring Batch Docs Spring Batch documentation + + + 1.0.0-SNAPSHOT + ${maven.multiModuleProjectDirectory}/spring-batch-core/ + .* + ${maven.multiModuleProjectDirectory}/spring-batch-docs/target/observability/ + + io.spring.docresources @@ -56,6 +64,59 @@ + + + org.codehaus.mojo + exec-maven-plugin + + + generate-metrics-metadata + prepare-package + + java + + + io.micrometer.docs.metrics.DocsFromSources + + + + generate-tracing-metadata + prepare-package + + java + + + io.micrometer.docs.spans.DocsFromSources + + + + + + io.micrometer + + micrometer-docs-generator-spans + ${micrometer-docs-generator.version} + + jar + + + io.micrometer + + micrometer-docs-generator-metrics + ${micrometer-docs-generator.version} + + jar + + + + true + + ${micrometer-docs-generator.inputPath} + ${micrometer-docs-generator.inclusionPattern} + ${micrometer-docs-generator.outputPath} + + + org.asciidoctor asciidoctor-maven-plugin diff --git a/spring-batch-docs/src/main/asciidoc/appendix.adoc b/spring-batch-docs/src/main/asciidoc/appendix.adoc index 502e3d0590..44fb10e666 100644 --- a/spring-batch-docs/src/main/asciidoc/appendix.adoc +++ b/spring-batch-docs/src/main/asciidoc/appendix.adoc @@ -133,3 +133,12 @@ This reader stores message offsets in the execution context to support restart c convert each item to Json and then writes it to an Json file. |=============== + +:root-target: ../../../target + +[[observability]] +== Observability metadata + +include::{root-target}/observability/_metrics.adoc[] + +include::{root-target}/observability/_spans.adoc[] diff --git a/spring-batch-test/pom.xml b/spring-batch-test/pom.xml index 3ae9aac70e..dee047600a 100644 --- a/spring-batch-test/pom.xml +++ b/spring-batch-test/pom.xml @@ -86,5 +86,11 @@ ${slf4j.version} test + + io.micrometer + micrometer-tracing-integration-test + ${micrometer-tracing.version} + test + diff --git a/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java b/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java new file mode 100644 index 0000000000..f96376d869 --- /dev/null +++ b/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java @@ -0,0 +1,98 @@ +/* + * Copyright 2008-2021 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.batch.test.observability; + +import java.util.function.BiConsumer; + +import io.micrometer.api.instrument.MeterRegistry; +import io.micrometer.api.instrument.Metrics; +import io.micrometer.tracing.Tracer; +import io.micrometer.tracing.test.SampleTestRunner; +import org.junit.After; +import org.junit.Before; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.runner.RunWith; + +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.batch.test.SpringBatchTestJUnit5Tests; +import org.springframework.batch.test.StepRunner; +import org.springframework.batch.test.context.SpringBatchTest; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.jdbc.JdbcTestUtils; + +import static org.junit.Assert.assertEquals; + +@SpringBatchTest +public class ObservabilitySampleStepTests extends SampleTestRunner { + + @Autowired + private JobLauncherTestUtils jobLauncherTestUtils; + + @Override + protected MeterRegistry getMeterRegistry() { + return Metrics.globalRegistry; + } + + @AfterEach + void clean() { + Metrics.globalRegistry.clear(); + } + + @Override + public BiConsumer yourCode() throws Exception { + return (tracer, meterRegistry) -> { + // given + JobParameters jobParameters = this.jobLauncherTestUtils.getUniqueJobParameters(); + + // when + JobExecution jobExecution = null; + try { + jobExecution = this.jobLauncherTestUtils.launchJob(jobParameters); + } + catch (Exception e) { + throw new RuntimeException(e); + } + + // then + Assertions.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus()); + }; + } + + @Configuration(proxyBeanMethods = false) + @Import(SpringBatchTestJUnit5Tests.JobConfiguration.class) + static class TestConfig { + + } +} From adbdf6a634ca6928d034b37b514f3c56cec2bf9e Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Mon, 14 Feb 2022 14:54:16 +0100 Subject: [PATCH 2/9] Fixes following Tommy's review --- .../batch/core/metrics/BatchMetrics.java | 16 +++++----------- .../batch/core/job/SimpleJobTests.java | 1 + .../batch/core/step/NonAbstractStepTests.java | 1 + 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java b/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java index 9e7b389443..9da414bc94 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java @@ -21,13 +21,11 @@ import java.util.concurrent.TimeUnit; import io.micrometer.api.instrument.LongTaskTimer; -import io.micrometer.api.instrument.MeterRegistry; import io.micrometer.api.instrument.Metrics; import io.micrometer.api.instrument.Tag; import io.micrometer.api.instrument.Timer; import io.micrometer.api.instrument.observation.Observation; import io.micrometer.api.instrument.observation.TimerObservationHandler; -import io.micrometer.api.instrument.simple.SimpleMeterRegistry; import org.springframework.lang.Nullable; @@ -56,14 +54,6 @@ public final class BatchMetrics { private BatchMetrics() {} - private static final MeterRegistry simpleMeterRegistry = new SimpleMeterRegistry().withTimerObservationHandler(); - - static { - // TODO: This shouldn't be necessary - we need to fix it in Micrometer - Metrics.globalRegistry.observationConfig().observationHandler(new TimerObservationHandler(Metrics.globalRegistry)); - Metrics.globalRegistry.add(simpleMeterRegistry); - } - /** * Create a {@link Timer}. * @param name of the timer. Will be prefixed with {@link BatchMetrics#METRICS_PREFIX}. @@ -81,7 +71,11 @@ public static Timer createTimer(String name, String description, Tag... tags) { /** * Create a new {@link Observation}. It's not started, you must * explicitly call {@link Observation#start()} to start it. - * @return a new timer sample instance + * + * Remember to register the {@link TimerObservationHandler} + * via the {@code Metrics.globalRegistry.withTimerObservationHandler() + * in the user code. Otherwise you won't observe any metrics. + * @return a new observation instance */ public static Observation createObservation(String name) { return Observation.createNotStarted(name, Metrics.globalRegistry); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java index a53b26a6a3..b2ea96b0c7 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java @@ -208,6 +208,7 @@ public boolean isAllowStartIfComplete() { @Test public void testRunNormally() throws Exception { + Metrics.globalRegistry.withTimerObservationHandler(); step1.setStartLimit(5); step2.setStartLimit(5); job.execute(jobExecution); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java index 160434828a..c49e61646d 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java @@ -184,6 +184,7 @@ protected void doExecute(StepExecution stepExecution) throws Exception { */ @Test public void testExecute() throws Exception { + Metrics.globalRegistry.withTimerObservationHandler(); tested.setStepExecutionListeners(new StepExecutionListener[] { listener1, listener2 }); tested.execute(execution); From 4e6097b137604439dd8f778cce7cac895fa5af0e Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Mon, 14 Feb 2022 18:01:33 +0100 Subject: [PATCH 3/9] Updated sample test runner to the latest API changes --- .../ObservabilitySampleStepTests.java | 41 +++++-------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java b/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java index f96376d869..73bb83829d 100644 --- a/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java +++ b/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java @@ -15,44 +15,23 @@ */ package org.springframework.batch.test.observability; -import java.util.function.BiConsumer; - import io.micrometer.api.instrument.MeterRegistry; import io.micrometer.api.instrument.Metrics; -import io.micrometer.tracing.Tracer; import io.micrometer.tracing.test.SampleTestRunner; -import org.junit.After; -import org.junit.Before; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.runner.RunWith; -import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.ExitStatus; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameters; -import org.springframework.batch.core.Step; -import org.springframework.batch.core.launch.JobLauncher; -import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.test.JobLauncherTestUtils; import org.springframework.batch.test.SpringBatchTestJUnit5Tests; -import org.springframework.batch.test.StepRunner; import org.springframework.batch.test.context.SpringBatchTest; -import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.jdbc.JdbcTestUtils; -import static org.junit.Assert.assertEquals; +import static io.micrometer.tracing.test.simple.SpansAssert.assertThat; @SpringBatchTest public class ObservabilitySampleStepTests extends SampleTestRunner { @@ -71,22 +50,22 @@ void clean() { } @Override - public BiConsumer yourCode() throws Exception { - return (tracer, meterRegistry) -> { + public SampleTestRunnerConsumer yourCode() { + return (bb, meterRegistry) -> { // given JobParameters jobParameters = this.jobLauncherTestUtils.getUniqueJobParameters(); // when - JobExecution jobExecution = null; - try { - jobExecution = this.jobLauncherTestUtils.launchJob(jobParameters); - } - catch (Exception e) { - throw new RuntimeException(e); - } + JobExecution jobExecution = this.jobLauncherTestUtils.launchJob(jobParameters); // then Assertions.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus()); + + // and + assertThat(bb.getFinishedSpans()) + .haveSameTraceId() + .hasASpanWithName("job") + .hasASpanWithName("step"); }; } From 17241a339d5b5a8c41110e37a5590ce95020fc61 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 15 Feb 2022 10:51:42 +0100 Subject: [PATCH 4/9] Upgraded to Micrometer 2.0.0-M2, Tracing 1.0.0-M2 and Micrometer Docs Generator 1.0.0-M1. Fixed docs generation --- pom.xml | 2 +- .../springframework/batch/core/metrics/BatchMetrics.java | 2 +- spring-batch-docs/pom.xml | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index eb1641f149..ee3639dc3c 100644 --- a/pom.xml +++ b/pom.xml @@ -53,7 +53,7 @@ 6.0.0-SNAPSHOT 1.3.1 - 6.0.0-SNAPSHOT + 6.0.0-M1 2.0.0-SNAPSHOT 1.0.0-SNAPSHOT 2.13.1 diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java b/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java index 9da414bc94..bd0a4a5ccd 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java @@ -73,7 +73,7 @@ public static Timer createTimer(String name, String description, Tag... tags) { * explicitly call {@link Observation#start()} to start it. * * Remember to register the {@link TimerObservationHandler} - * via the {@code Metrics.globalRegistry.withTimerObservationHandler() + * via the {@code Metrics.globalRegistry.withTimerObservationHandler()} * in the user code. Otherwise you won't observe any metrics. * @return a new observation instance */ diff --git a/spring-batch-docs/pom.xml b/spring-batch-docs/pom.xml index ca02fc007f..2863d5bd7c 100644 --- a/spring-batch-docs/pom.xml +++ b/spring-batch-docs/pom.xml @@ -12,7 +12,7 @@ - 1.0.0-SNAPSHOT + 1.0.0-M1 ${maven.multiModuleProjectDirectory}/spring-batch-core/ .* ${maven.multiModuleProjectDirectory}/spring-batch-docs/target/observability/ @@ -64,14 +64,13 @@ - org.codehaus.mojo exec-maven-plugin generate-metrics-metadata - prepare-package + pre-site java @@ -81,7 +80,7 @@ generate-tracing-metadata - prepare-package + pre-site java From c20813f2683174d4af598437085b2c18113e286a Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 17 Feb 2022 11:08:46 +0100 Subject: [PATCH 5/9] Uses TagsProvider --- .../batch/core/job/AbstractJob.java | 21 ++++++---- .../batch/core/job/BatchJobContext.java | 35 ++++++++++++++++ .../batch/core/job/BatchJobTagsProvider.java | 40 ++++++++++++++++++ .../core/job/DefaultBatchJobTagsProvider.java | 42 +++++++++++++++++++ .../batch/core/step/AbstractStep.java | 20 +++++---- .../batch/core/step/BatchStepContext.java | 35 ++++++++++++++++ .../core/step/BatchStepTagsProvider.java | 32 ++++++++++++++ .../step/DefaultBatchStepTagsProvider.java | 42 +++++++++++++++++++ spring-batch-test/pom.xml | 6 +++ .../ObservabilitySampleStepTests.java | 12 +++++- 10 files changed, 267 insertions(+), 18 deletions(-) create mode 100644 spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobContext.java create mode 100644 spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobTagsProvider.java create mode 100644 spring-batch-core/src/main/java/org/springframework/batch/core/job/DefaultBatchJobTagsProvider.java create mode 100644 spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepContext.java create mode 100644 spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepTagsProvider.java create mode 100644 spring-batch-core/src/main/java/org/springframework/batch/core/step/DefaultBatchStepTagsProvider.java diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java index 08ea8b977a..6ce2cf91f3 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java @@ -64,7 +64,7 @@ * @author Mahmoud Ben Hassine */ public abstract class AbstractJob implements Job, StepLocator, BeanNameAware, -InitializingBean { +InitializingBean, Observation.TagsProviderAware { protected static final Log logger = LogFactory.getLog(AbstractJob.class); @@ -82,6 +82,8 @@ public abstract class AbstractJob implements Job, StepLocator, BeanNameAware, private StepHandler stepHandler; + private BatchJobTagsProvider tagsProvider = new DefaultBatchJobTagsProvider(); + /** * Default constructor. */ @@ -307,7 +309,9 @@ public final void execute(JobExecution execution) { Tag.of("name", execution.getJobInstance().getJobName())); LongTaskTimer.Sample longTaskTimerSample = longTaskTimer.start(); Observation observation = BatchMetrics.createObservation(BatchJobObservation.BATCH_JOB_OBSERVATION.getName()) - .contextualName(execution.getJobInstance().getJobName()).start(); + .contextualName(execution.getJobInstance().getJobName()) + .tagsProvider(this.tagsProvider) + .start(); try (Observation.Scope scope = observation.openScope()) { jobParametersValidator.validate(execution.getJobParameters()); @@ -364,7 +368,7 @@ public final void execute(JobExecution execution) { ExitStatus.NOOP.addExitDescription("All steps already completed or no steps configured for this job."); execution.setExitStatus(exitStatus.and(newExitStatus)); } - stopTaggedObservation(execution, observation); + stopObservation(execution, observation); longTaskTimerSample.stop(); execution.setEndTime(new Date()); @@ -383,11 +387,7 @@ public final void execute(JobExecution execution) { } - private void stopTaggedObservation(JobExecution execution, Observation observation) { - observation.lowCardinalityTag(BatchJobObservation.JobLowCardinalityTags.JOB_NAME.of(execution.getJobInstance().getJobName())) - .lowCardinalityTag(BatchJobObservation.JobLowCardinalityTags.JOB_STATUS.of(execution.getExitStatus().getExitCode())) - .highCardinalityTag(BatchJobObservation.JobHighCardinalityTags.JOB_INSTANCE_ID.of(String.valueOf(execution.getJobInstance().getInstanceId()))) - .highCardinalityTag(BatchJobObservation.JobHighCardinalityTags.JOB_EXECUTION_ID.of(String.valueOf(execution.getId()))); + private void stopObservation(JobExecution execution, Observation observation) { List throwables = execution.getFailureExceptions(); if (!throwables.isEmpty()) { observation.error(mergedThrowables(throwables)); @@ -459,6 +459,11 @@ private void updateStatus(JobExecution jobExecution, BatchStatus status) { jobRepository.update(jobExecution); } + @Override + public void setTagsProvider(BatchJobTagsProvider tagsProvider) { + this.tagsProvider = tagsProvider; + } + @Override public String toString() { return ClassUtils.getShortName(getClass()) + ": [name=" + name + "]"; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobContext.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobContext.java new file mode 100644 index 0000000000..2a77bd883a --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobContext.java @@ -0,0 +1,35 @@ +/* + * Copyright 2013-2021 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.batch.core.job; + +import io.micrometer.api.instrument.observation.Observation; + +import org.springframework.batch.core.JobExecution; + +public class BatchJobContext extends Observation.Context { + + private final JobExecution jobExecution; + + public BatchJobContext(JobExecution jobExecution) { + this.jobExecution = jobExecution; + } + + public JobExecution getJobExecution() { + return jobExecution; + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobTagsProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobTagsProvider.java new file mode 100644 index 0000000000..3d3b600592 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobTagsProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright 2006-2009 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.batch.core.job; + +import io.micrometer.api.instrument.observation.Observation; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobInterruptedException; +import org.springframework.batch.core.StartLimitExceededException; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.repository.JobRestartException; + +/** + * {@link Observation.TagsProvider} for {@link BatchJobContext}. + * + * @author Marcin Grzejszczak + */ +public interface BatchJobTagsProvider extends Observation.TagsProvider { + + @Override + default boolean supportsContext(Observation.Context context) { + return context instanceof BatchJobContext; + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/DefaultBatchJobTagsProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/DefaultBatchJobTagsProvider.java new file mode 100644 index 0000000000..7c6d808304 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/DefaultBatchJobTagsProvider.java @@ -0,0 +1,42 @@ +/* + * Copyright 2011-2018 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.batch.core.job; + +import io.micrometer.api.instrument.Tags; + +import org.springframework.batch.core.JobExecution; + +/** + * Default {@link BatchJobTagsProvider} implementation. + * + * @author Marcin Grzejszczak + */ +public class DefaultBatchJobTagsProvider implements BatchJobTagsProvider { + @Override + public Tags getLowCardinalityTags(BatchJobContext context) { + JobExecution execution = context.getJobExecution(); + return Tags.of(BatchJobObservation.JobLowCardinalityTags.JOB_NAME.of(execution.getJobInstance().getJobName()), + BatchJobObservation.JobLowCardinalityTags.JOB_STATUS.of(execution.getExitStatus().getExitCode())); + } + + @Override + public Tags getHighCardinalityTags(BatchJobContext context) { + JobExecution execution = context.getJobExecution(); + return Tags.of(BatchJobObservation.JobHighCardinalityTags.JOB_INSTANCE_ID.of(String.valueOf(execution.getJobInstance().getInstanceId())), + BatchJobObservation.JobHighCardinalityTags.JOB_EXECUTION_ID.of(String.valueOf(execution.getId()))); + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java index af01451de9..b994d85368 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java @@ -55,7 +55,7 @@ * @author Chris Schaefer * @author Mahmoud Ben Hassine */ -public abstract class AbstractStep implements Step, InitializingBean, BeanNameAware { +public abstract class AbstractStep implements Step, InitializingBean, BeanNameAware, Observation.TagsProviderAware { private static final Log logger = LogFactory.getLog(AbstractStep.class); @@ -69,6 +69,8 @@ public abstract class AbstractStep implements Step, InitializingBean, BeanNameAw private JobRepository jobRepository; + private BatchStepTagsProvider tagsProvider = new DefaultBatchStepTagsProvider(); + /** * Default constructor. */ @@ -194,7 +196,9 @@ public final void execute(StepExecution stepExecution) throws JobInterruptedExce stepExecution.setStartTime(new Date()); stepExecution.setStatus(BatchStatus.STARTED); Observation observation = BatchMetrics.createObservation(BatchStepObservation.BATCH_STEP_OBSERVATION.getName()) - .contextualName(stepExecution.getStepName()).start(); + .contextualName(stepExecution.getStepName()) + .tagsProvider(this.tagsProvider) + .start(); getJobRepository().update(stepExecution); // Start with a default value that will be trumped by anything @@ -262,7 +266,7 @@ public final void execute(StepExecution stepExecution) throws JobInterruptedExce logger.error(String.format("Encountered an error saving batch meta data for step %s in job %s. " + "This job is now in an unknown state and should not be restarted.", name, stepExecution.getJobExecution().getJobInstance().getJobName()), e); } - stopTaggedObservation(stepExecution, observation); + stopObservation(stepExecution, observation); stepExecution.setEndTime(new Date()); stepExecution.setExitStatus(exitStatus); Duration stepExecutionDuration = BatchMetrics.calculateDuration(stepExecution.getStartTime(), stepExecution.getEndTime()); @@ -296,11 +300,7 @@ public final void execute(StepExecution stepExecution) throws JobInterruptedExce } } - private void stopTaggedObservation(StepExecution stepExecution, Observation observation) { - observation.lowCardinalityTag(BatchStepObservation.StepLowCardinalityTags.STEP_NAME.of(stepExecution.getStepName())) - .lowCardinalityTag(BatchStepObservation.StepLowCardinalityTags.JOB_NAME.of(stepExecution.getJobExecution().getJobInstance().getJobName())) - .lowCardinalityTag(BatchStepObservation.StepLowCardinalityTags.STEP_STATUS.of(stepExecution.getExitStatus().getExitCode())) - .highCardinalityTag(BatchStepObservation.StepHighCardinalityTags.STEP_EXECUTION_ID.of(String.valueOf(stepExecution.getId()))); + private void stopObservation(StepExecution stepExecution, Observation observation) { List throwables = stepExecution.getFailureExceptions(); if (!throwables.isEmpty()) { observation.error(mergedThrowables(throwables)); @@ -408,4 +408,8 @@ else if (ex instanceof NoSuchJobException || ex.getCause() instanceof NoSuchJobE return exitStatus; } + @Override + public void setTagsProvider(BatchStepTagsProvider tagsProvider) { + this.tagsProvider = tagsProvider; + } } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepContext.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepContext.java new file mode 100644 index 0000000000..7a68a76316 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepContext.java @@ -0,0 +1,35 @@ +/* + * Copyright 2013-2021 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.batch.core.step; + +import io.micrometer.api.instrument.observation.Observation; + +import org.springframework.batch.core.StepExecution; + +public class BatchStepContext extends Observation.Context { + + private final StepExecution stepExecution; + + public BatchStepContext(StepExecution stepExecution) { + this.stepExecution = stepExecution; + } + + public StepExecution getStepExecution() { + return stepExecution; + } + +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepTagsProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepTagsProvider.java new file mode 100644 index 0000000000..b9cdb6946f --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepTagsProvider.java @@ -0,0 +1,32 @@ +/* + * Copyright 2006-2009 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.batch.core.step; + +import io.micrometer.api.instrument.observation.Observation; + +/** + * {@link Observation.TagsProvider} for {@link BatchStepContext}. + * + * @author Marcin Grzejszczak + */ +public interface BatchStepTagsProvider extends Observation.TagsProvider { + + @Override + default boolean supportsContext(Observation.Context context) { + return context instanceof BatchStepContext; + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/DefaultBatchStepTagsProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/DefaultBatchStepTagsProvider.java new file mode 100644 index 0000000000..03641c7892 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/DefaultBatchStepTagsProvider.java @@ -0,0 +1,42 @@ +/* + * Copyright 2011-2018 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.batch.core.step; + +import io.micrometer.api.instrument.Tags; + +import org.springframework.batch.core.StepExecution; + +/** + * Default {@link BatchStepTagsProvider} implementation. + * + * @author Marcin Grzejszczak + */ +public class DefaultBatchStepTagsProvider implements BatchStepTagsProvider { + @Override + public Tags getLowCardinalityTags(BatchStepContext context) { + StepExecution execution = context.getStepExecution(); + return Tags.of(BatchStepObservation.StepLowCardinalityTags.STEP_NAME.of(execution.getStepName()), + BatchStepObservation.StepLowCardinalityTags.JOB_NAME.of(execution.getJobExecution().getJobInstance().getJobName()), + BatchStepObservation.StepLowCardinalityTags.STEP_STATUS.of(execution.getExitStatus().getExitCode())); + } + + @Override + public Tags getHighCardinalityTags(BatchStepContext context) { + StepExecution execution = context.getStepExecution(); + return Tags.of(BatchStepObservation.StepHighCardinalityTags.STEP_EXECUTION_ID.of(String.valueOf(execution.getId()))); + } + +} diff --git a/spring-batch-test/pom.xml b/spring-batch-test/pom.xml index dee047600a..b34ee57937 100644 --- a/spring-batch-test/pom.xml +++ b/spring-batch-test/pom.xml @@ -92,5 +92,11 @@ ${micrometer-tracing.version} test + + io.micrometer + micrometer-test + ${micrometer.version} + test + diff --git a/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java b/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java index 73bb83829d..857cbbbf6d 100644 --- a/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java +++ b/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java @@ -17,6 +17,7 @@ import io.micrometer.api.instrument.MeterRegistry; import io.micrometer.api.instrument.Metrics; +import io.micrometer.core.tck.MeterRegistryAssert; import io.micrometer.tracing.test.SampleTestRunner; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -39,14 +40,16 @@ public class ObservabilitySampleStepTests extends SampleTestRunner { @Autowired private JobLauncherTestUtils jobLauncherTestUtils; + private static MeterRegistry registry = Metrics.globalRegistry.withTimerObservationHandler(); + @Override protected MeterRegistry getMeterRegistry() { - return Metrics.globalRegistry; + return registry; } @AfterEach void clean() { - Metrics.globalRegistry.clear(); + registry.clear(); } @Override @@ -66,6 +69,11 @@ public SampleTestRunnerConsumer yourCode() { .haveSameTraceId() .hasASpanWithName("job") .hasASpanWithName("step"); + + // and + MeterRegistryAssert.assertThat(meterRegistry) + .hasTimerWithName("spring.batch.job") + .hasTimerWithName("spring.batch.step"); }; } From 282cb1b8fc689bc7911edc2e0d2782552bf4e5f2 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Fri, 18 Feb 2022 08:36:39 +0100 Subject: [PATCH 6/9] Sets spring integration back to SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ee3639dc3c..eb1641f149 100644 --- a/pom.xml +++ b/pom.xml @@ -53,7 +53,7 @@ 6.0.0-SNAPSHOT 1.3.1 - 6.0.0-M1 + 6.0.0-SNAPSHOT 2.0.0-SNAPSHOT 1.0.0-SNAPSHOT 2.13.1 From c524b4367aa4d7a55d14c463bf15ee1bf2e20a48 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 10 Mar 2022 14:00:01 +0100 Subject: [PATCH 7/9] Going back to snapshots --- spring-batch-docs/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-batch-docs/pom.xml b/spring-batch-docs/pom.xml index 2863d5bd7c..4e064c7e95 100644 --- a/spring-batch-docs/pom.xml +++ b/spring-batch-docs/pom.xml @@ -12,7 +12,7 @@ - 1.0.0-M1 + 1.0.0-SNAPSHOT ${maven.multiModuleProjectDirectory}/spring-batch-core/ .* ${maven.multiModuleProjectDirectory}/spring-batch-docs/target/observability/ From 1f9325fc5c3ee79165e5cb8611ff4a23a4021d94 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 10 Mar 2022 14:09:31 +0100 Subject: [PATCH 8/9] Updated micrometer changes --- .../springframework/batch/core/job/AbstractJob.java | 6 +++--- .../batch/core/job/BatchJobContext.java | 2 +- .../batch/core/job/BatchJobObservation.java | 4 ++-- .../batch/core/job/BatchJobTagsProvider.java | 2 +- .../batch/core/job/DefaultBatchJobTagsProvider.java | 2 +- .../batch/core/metrics/BatchMetrics.java | 12 ++++++------ .../batch/core/step/AbstractStep.java | 2 +- .../batch/core/step/BatchStepContext.java | 2 +- .../batch/core/step/BatchStepObservation.java | 4 ++-- .../batch/core/step/BatchStepTagsProvider.java | 2 +- .../core/step/DefaultBatchStepTagsProvider.java | 2 +- .../core/step/item/FaultTolerantChunkProcessor.java | 2 +- .../batch/core/step/item/SimpleChunkProcessor.java | 4 ++-- .../batch/core/step/item/SimpleChunkProvider.java | 6 +++--- .../batch/core/job/SimpleJobTests.java | 6 +++--- .../batch/core/step/NonAbstractStepTests.java | 6 +++--- .../sample/metrics/PrometheusConfiguration.java | 2 +- .../batch/sample/metrics/BatchMetricsTests.java | 4 ++-- .../observability/ObservabilitySampleStepTests.java | 4 ++-- 19 files changed, 37 insertions(+), 37 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java index 6ce2cf91f3..5b82b3400f 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java @@ -21,9 +21,9 @@ import java.util.List; import java.util.stream.Collectors; -import io.micrometer.api.instrument.LongTaskTimer; -import io.micrometer.api.instrument.Tag; -import io.micrometer.api.instrument.observation.Observation; +import io.micrometer.core.instrument.LongTaskTimer; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.observation.Observation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.core.BatchStatus; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobContext.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobContext.java index 2a77bd883a..c3866c3347 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobContext.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobContext.java @@ -16,7 +16,7 @@ package org.springframework.batch.core.job; -import io.micrometer.api.instrument.observation.Observation; +import io.micrometer.core.instrument.observation.Observation; import org.springframework.batch.core.JobExecution; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobObservation.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobObservation.java index e49e95b271..c3fa1f49ab 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobObservation.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobObservation.java @@ -16,8 +16,8 @@ package org.springframework.batch.core.job; -import io.micrometer.api.instrument.docs.DocumentedObservation; -import io.micrometer.api.instrument.docs.TagKey; +import io.micrometer.core.instrument.docs.DocumentedObservation; +import io.micrometer.core.instrument.docs.TagKey; enum BatchJobObservation implements DocumentedObservation { diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobTagsProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobTagsProvider.java index 3d3b600592..41bcf7ea1b 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobTagsProvider.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/BatchJobTagsProvider.java @@ -16,7 +16,7 @@ package org.springframework.batch.core.job; -import io.micrometer.api.instrument.observation.Observation; +import io.micrometer.core.instrument.observation.Observation; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/DefaultBatchJobTagsProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/DefaultBatchJobTagsProvider.java index 7c6d808304..7c6497459d 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/DefaultBatchJobTagsProvider.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/DefaultBatchJobTagsProvider.java @@ -15,7 +15,7 @@ */ package org.springframework.batch.core.job; -import io.micrometer.api.instrument.Tags; +import io.micrometer.core.instrument.Tags; import org.springframework.batch.core.JobExecution; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java b/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java index bd0a4a5ccd..8f9c7c8dc7 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java @@ -20,12 +20,12 @@ import java.util.Date; import java.util.concurrent.TimeUnit; -import io.micrometer.api.instrument.LongTaskTimer; -import io.micrometer.api.instrument.Metrics; -import io.micrometer.api.instrument.Tag; -import io.micrometer.api.instrument.Timer; -import io.micrometer.api.instrument.observation.Observation; -import io.micrometer.api.instrument.observation.TimerObservationHandler; +import io.micrometer.core.instrument.LongTaskTimer; +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.observation.Observation; +import io.micrometer.core.instrument.observation.TimerObservationHandler; import org.springframework.lang.Nullable; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java index b994d85368..d1e22aaef7 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.stream.Collectors; -import io.micrometer.api.instrument.observation.Observation; +import io.micrometer.core.instrument.observation.Observation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.core.BatchStatus; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepContext.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepContext.java index 7a68a76316..7865ea43d5 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepContext.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepContext.java @@ -16,7 +16,7 @@ package org.springframework.batch.core.step; -import io.micrometer.api.instrument.observation.Observation; +import io.micrometer.core.instrument.observation.Observation; import org.springframework.batch.core.StepExecution; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepObservation.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepObservation.java index db596b31de..35a7312d0b 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepObservation.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepObservation.java @@ -16,8 +16,8 @@ package org.springframework.batch.core.step; -import io.micrometer.api.instrument.docs.DocumentedObservation; -import io.micrometer.api.instrument.docs.TagKey; +import io.micrometer.core.instrument.docs.DocumentedObservation; +import io.micrometer.core.instrument.docs.TagKey; enum BatchStepObservation implements DocumentedObservation { diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepTagsProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepTagsProvider.java index b9cdb6946f..2d2b458b2b 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepTagsProvider.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/BatchStepTagsProvider.java @@ -16,7 +16,7 @@ package org.springframework.batch.core.step; -import io.micrometer.api.instrument.observation.Observation; +import io.micrometer.core.instrument.observation.Observation; /** * {@link Observation.TagsProvider} for {@link BatchStepContext}. diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/DefaultBatchStepTagsProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/DefaultBatchStepTagsProvider.java index 03641c7892..6df520b384 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/DefaultBatchStepTagsProvider.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/DefaultBatchStepTagsProvider.java @@ -15,7 +15,7 @@ */ package org.springframework.batch.core.step; -import io.micrometer.api.instrument.Tags; +import io.micrometer.core.instrument.Tags; import org.springframework.batch.core.StepExecution; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java index f188b1b244..09137e55a2 100755 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/FaultTolerantChunkProcessor.java @@ -22,7 +22,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; -import io.micrometer.api.instrument.Timer; +import io.micrometer.core.instrument.Timer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java index 4ec68b4830..d946e39217 100755 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProcessor.java @@ -18,8 +18,8 @@ import java.util.List; -import io.micrometer.api.instrument.Tag; -import io.micrometer.api.instrument.Timer; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Timer; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.StepExecution; diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProvider.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProvider.java index 4c4068ac18..4a14220ae6 100755 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProvider.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/SimpleChunkProvider.java @@ -18,9 +18,9 @@ import java.util.List; -import io.micrometer.api.instrument.Metrics; -import io.micrometer.api.instrument.Tag; -import io.micrometer.api.instrument.Timer; +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Timer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.core.StepContribution; diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java index b2ea96b0c7..22cc26955c 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java @@ -31,9 +31,9 @@ import java.util.Date; import java.util.List; -import io.micrometer.api.instrument.Metrics; -import io.micrometer.api.instrument.Tag; -import io.micrometer.api.instrument.Tags; +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; import io.micrometer.core.tck.MeterRegistryAssert; import org.junit.After; import org.junit.Before; diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java index c49e61646d..037f5f0db8 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/NonAbstractStepTests.java @@ -23,9 +23,9 @@ import java.util.ArrayList; import java.util.List; -import io.micrometer.api.instrument.Metrics; -import io.micrometer.api.instrument.Tag; -import io.micrometer.api.instrument.Tags; +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; import io.micrometer.core.tck.MeterRegistryAssert; import org.junit.After; import org.junit.Before; diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/metrics/PrometheusConfiguration.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/metrics/PrometheusConfiguration.java index 7f15253e36..6c5c226c63 100644 --- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/metrics/PrometheusConfiguration.java +++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/metrics/PrometheusConfiguration.java @@ -19,7 +19,7 @@ import java.util.Map; import jakarta.annotation.PostConstruct; -import io.micrometer.api.instrument.Metrics; +import io.micrometer.core.instrument.Metrics; import io.micrometer.prometheus.PrometheusConfig; import io.micrometer.prometheus.PrometheusMeterRegistry; import io.prometheus.client.CollectorRegistry; diff --git a/spring-batch-samples/src/test/java/org/springframework/batch/sample/metrics/BatchMetricsTests.java b/spring-batch-samples/src/test/java/org/springframework/batch/sample/metrics/BatchMetricsTests.java index 219380e55c..081fbc478a 100644 --- a/spring-batch-samples/src/test/java/org/springframework/batch/sample/metrics/BatchMetricsTests.java +++ b/spring-batch-samples/src/test/java/org/springframework/batch/sample/metrics/BatchMetricsTests.java @@ -25,8 +25,8 @@ import javax.sql.DataSource; -import io.micrometer.api.instrument.Meter; -import io.micrometer.api.instrument.Metrics; +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.Metrics; import org.junit.Test; import org.springframework.batch.core.ExitStatus; diff --git a/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java b/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java index 857cbbbf6d..ba81b3b9c3 100644 --- a/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java +++ b/spring-batch-test/src/test/java/org/springframework/batch/test/observability/ObservabilitySampleStepTests.java @@ -15,8 +15,8 @@ */ package org.springframework.batch.test.observability; -import io.micrometer.api.instrument.MeterRegistry; -import io.micrometer.api.instrument.Metrics; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Metrics; import io.micrometer.core.tck.MeterRegistryAssert; import io.micrometer.tracing.test.SampleTestRunner; import org.junit.jupiter.api.AfterEach; From 61ec4d4364447135181c5997c9522634da637957 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Fri, 11 Mar 2022 13:54:53 +0100 Subject: [PATCH 9/9] Adds missing contextd reference without this change the BatchJobTagsProvider or BatchStepTagsProvider is not applied because it has a condition on instanceof BatchJobContext or BatchStepContext with this change we're adding the missing context when the observation is created, without this the default context was used --- .../org/springframework/batch/core/job/AbstractJob.java | 2 +- .../springframework/batch/core/metrics/BatchMetrics.java | 4 ++-- .../org/springframework/batch/core/step/AbstractStep.java | 2 +- .../batch/sample/metrics/BatchMetricsTests.java | 6 ++++++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java index 5b82b3400f..4a591a9048 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java @@ -308,7 +308,7 @@ public final void execute(JobExecution execution) { LongTaskTimer longTaskTimer = BatchMetrics.createLongTaskTimer("job.active", "Active jobs", Tag.of("name", execution.getJobInstance().getJobName())); LongTaskTimer.Sample longTaskTimerSample = longTaskTimer.start(); - Observation observation = BatchMetrics.createObservation(BatchJobObservation.BATCH_JOB_OBSERVATION.getName()) + Observation observation = BatchMetrics.createObservation(BatchJobObservation.BATCH_JOB_OBSERVATION.getName(), new BatchJobContext(execution)) .contextualName(execution.getJobInstance().getJobName()) .tagsProvider(this.tagsProvider) .start(); diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java b/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java index 8f9c7c8dc7..61761186b8 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/metrics/BatchMetrics.java @@ -77,8 +77,8 @@ public static Timer createTimer(String name, String description, Tag... tags) { * in the user code. Otherwise you won't observe any metrics. * @return a new observation instance */ - public static Observation createObservation(String name) { - return Observation.createNotStarted(name, Metrics.globalRegistry); + public static Observation createObservation(String name, Observation.Context context) { + return Observation.createNotStarted(name, context, Metrics.globalRegistry); } /** diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java index d1e22aaef7..1aaaff4913 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java @@ -195,7 +195,7 @@ public final void execute(StepExecution stepExecution) throws JobInterruptedExce } stepExecution.setStartTime(new Date()); stepExecution.setStatus(BatchStatus.STARTED); - Observation observation = BatchMetrics.createObservation(BatchStepObservation.BATCH_STEP_OBSERVATION.getName()) + Observation observation = BatchMetrics.createObservation(BatchStepObservation.BATCH_STEP_OBSERVATION.getName(), new BatchStepContext(stepExecution)) .contextualName(stepExecution.getStepName()) .tagsProvider(this.tagsProvider) .start(); diff --git a/spring-batch-samples/src/test/java/org/springframework/batch/sample/metrics/BatchMetricsTests.java b/spring-batch-samples/src/test/java/org/springframework/batch/sample/metrics/BatchMetricsTests.java index 081fbc478a..345537f8de 100644 --- a/spring-batch-samples/src/test/java/org/springframework/batch/sample/metrics/BatchMetricsTests.java +++ b/spring-batch-samples/src/test/java/org/springframework/batch/sample/metrics/BatchMetricsTests.java @@ -27,6 +27,7 @@ import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.Metrics; +import org.junit.BeforeClass; import org.junit.Test; import org.springframework.batch.core.ExitStatus; @@ -60,6 +61,11 @@ public class BatchMetricsTests { private static final int EXPECTED_SPRING_BATCH_METRICS = 10; + @BeforeClass + public static void setup() { + Metrics.globalRegistry.withTimerObservationHandler(); + } + @Test public void testCalculateDuration() { LocalDateTime startTime = LocalDateTime.now();