diff --git a/framework-docs/modules/ROOT/pages/integration/observability.adoc b/framework-docs/modules/ROOT/pages/integration/observability.adoc index 398416379b..05f85aabd7 100644 --- a/framework-docs/modules/ROOT/pages/integration/observability.adoc +++ b/framework-docs/modules/ROOT/pages/integration/observability.adoc @@ -91,7 +91,7 @@ This can be done by declaring a `SchedulingConfigurer` bean that sets the observ include-code::./ObservationSchedulingConfigurer[] -It is using the `org.springframework.scheduling.config.DefaultScheduledTaskObservationConvention` by default, backed by the `ScheduledTaskObservationContext`. +It is using the `org.springframework.scheduling.support.DefaultScheduledTaskObservationConvention` by default, backed by the `ScheduledTaskObservationContext`. You can configure a custom implementation on the `ObservationRegistry` directly. During the execution of the scheduled method, the current observation is restored in the `ThreadLocal` context or the Reactor context (if the scheduled method returns a `Mono` or `Flux` type). diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationReactiveSupport.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationReactiveSupport.java index d3f204e868..f0e89d921c 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationReactiveSupport.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationReactiveSupport.java @@ -38,15 +38,15 @@ import org.springframework.core.KotlinDetector; import org.springframework.core.ReactiveAdapter; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.lang.Nullable; -import org.springframework.scheduling.config.DefaultScheduledTaskObservationConvention; -import org.springframework.scheduling.config.ScheduledTaskObservationContext; -import org.springframework.scheduling.config.ScheduledTaskObservationConvention; +import org.springframework.scheduling.support.DefaultScheduledTaskObservationConvention; +import org.springframework.scheduling.support.ScheduledTaskObservationContext; +import org.springframework.scheduling.support.ScheduledTaskObservationConvention; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; -import static org.springframework.scheduling.config.ScheduledTaskObservationDocumentation.TASKS_SCHEDULED_EXECUTION; +import static org.springframework.scheduling.support.ScheduledTaskObservationDocumentation.TASKS_SCHEDULED_EXECUTION; /** * Helper class for @{@link ScheduledAnnotationBeanPostProcessor} to support reactive diff --git a/spring-context/src/main/java/org/springframework/scheduling/config/DefaultScheduledTaskObservationConvention.java b/spring-context/src/main/java/org/springframework/scheduling/support/DefaultScheduledTaskObservationConvention.java similarity index 94% rename from spring-context/src/main/java/org/springframework/scheduling/config/DefaultScheduledTaskObservationConvention.java rename to spring-context/src/main/java/org/springframework/scheduling/support/DefaultScheduledTaskObservationConvention.java index 37b8414802..837f005724 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/config/DefaultScheduledTaskObservationConvention.java +++ b/spring-context/src/main/java/org/springframework/scheduling/support/DefaultScheduledTaskObservationConvention.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package org.springframework.scheduling.config; +package org.springframework.scheduling.support; import io.micrometer.common.KeyValue; import io.micrometer.common.KeyValues; import org.springframework.util.StringUtils; -import static org.springframework.scheduling.config.ScheduledTaskObservationDocumentation.LowCardinalityKeyNames; +import static org.springframework.scheduling.support.ScheduledTaskObservationDocumentation.LowCardinalityKeyNames; /** * Default implementation for {@link ScheduledTaskObservationConvention}. diff --git a/spring-context/src/main/java/org/springframework/scheduling/support/ScheduledMethodRunnable.java b/spring-context/src/main/java/org/springframework/scheduling/support/ScheduledMethodRunnable.java index bc9fe80b0b..e05d49e1cc 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/support/ScheduledMethodRunnable.java +++ b/spring-context/src/main/java/org/springframework/scheduling/support/ScheduledMethodRunnable.java @@ -24,10 +24,6 @@ import java.util.function.Supplier; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; -import org.springframework.scheduling.config.DefaultScheduledTaskObservationConvention; -import org.springframework.scheduling.config.ScheduledTaskObservationContext; -import org.springframework.scheduling.config.ScheduledTaskObservationConvention; -import org.springframework.scheduling.config.ScheduledTaskObservationDocumentation; import org.springframework.util.ReflectionUtils; /** @@ -42,7 +38,8 @@ import org.springframework.util.ReflectionUtils; */ public class ScheduledMethodRunnable implements Runnable { - private static final ScheduledTaskObservationConvention DEFAULT_CONVENTION = new DefaultScheduledTaskObservationConvention(); + private static final ScheduledTaskObservationConvention DEFAULT_CONVENTION = + new DefaultScheduledTaskObservationConvention(); private final Object target; @@ -50,6 +47,7 @@ public class ScheduledMethodRunnable implements Runnable { private final Supplier observationRegistrySupplier; + /** * Create a {@code ScheduledMethodRunnable} for the given target instance, * calling the specified method. diff --git a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskObservationContext.java b/spring-context/src/main/java/org/springframework/scheduling/support/ScheduledTaskObservationContext.java similarity index 92% rename from spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskObservationContext.java rename to spring-context/src/main/java/org/springframework/scheduling/support/ScheduledTaskObservationContext.java index 382dd10399..a7f7e96ca0 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskObservationContext.java +++ b/spring-context/src/main/java/org/springframework/scheduling/support/ScheduledTaskObservationContext.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.scheduling.config; +package org.springframework.scheduling.support; import java.lang.reflect.Method; @@ -23,8 +23,9 @@ import io.micrometer.observation.Observation; import org.springframework.util.ClassUtils; /** - * Context that holds information for observation metadata collection - * during the {@link ScheduledTaskObservationDocumentation#TASKS_SCHEDULED_EXECUTION execution of scheduled tasks}. + * Context that holds information for observation metadata collection during the + * {@link ScheduledTaskObservationDocumentation#TASKS_SCHEDULED_EXECUTION execution of scheduled tasks}. + * * @author Brian Clozel * @since 6.1 */ @@ -36,6 +37,7 @@ public class ScheduledTaskObservationContext extends Observation.Context { private boolean complete; + /** * Create a new observation context for a task, given the target object * and the method to be called. @@ -47,6 +49,7 @@ public class ScheduledTaskObservationContext extends Observation.Context { this.method = method; } + /** * Return the type of the target object. */ @@ -77,4 +80,5 @@ public class ScheduledTaskObservationContext extends Observation.Context { public void setComplete(boolean complete) { this.complete = complete; } + } diff --git a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskObservationConvention.java b/spring-context/src/main/java/org/springframework/scheduling/support/ScheduledTaskObservationConvention.java similarity index 95% rename from spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskObservationConvention.java rename to spring-context/src/main/java/org/springframework/scheduling/support/ScheduledTaskObservationConvention.java index bbaf593420..23f53bf609 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskObservationConvention.java +++ b/spring-context/src/main/java/org/springframework/scheduling/support/ScheduledTaskObservationConvention.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.scheduling.config; +package org.springframework.scheduling.support; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationConvention; @@ -22,6 +22,7 @@ import io.micrometer.observation.ObservationConvention; /** * Interface for an {@link ObservationConvention} for * {@link ScheduledTaskObservationDocumentation#TASKS_SCHEDULED_EXECUTION scheduled task executions}. + * * @author Brian Clozel * @since 6.1 */ diff --git a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskObservationDocumentation.java b/spring-context/src/main/java/org/springframework/scheduling/support/ScheduledTaskObservationDocumentation.java similarity index 95% rename from spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskObservationDocumentation.java rename to spring-context/src/main/java/org/springframework/scheduling/support/ScheduledTaskObservationDocumentation.java index 6e54f60924..4d80fdab7d 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskObservationDocumentation.java +++ b/spring-context/src/main/java/org/springframework/scheduling/support/ScheduledTaskObservationDocumentation.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.scheduling.config; +package org.springframework.scheduling.support; import io.micrometer.common.KeyValue; import io.micrometer.common.docs.KeyName; @@ -24,8 +24,10 @@ import io.micrometer.observation.docs.ObservationDocumentation; /** * Documented {@link io.micrometer.common.KeyValue KeyValues} for the observations on - * executions of {@link org.springframework.scheduling.annotation.Scheduled scheduled tasks}. - *

This class is used by automated tools to document KeyValues attached to the {@code @Scheduled} observations. + * executions of {@link org.springframework.scheduling.annotation.Scheduled scheduled tasks} + * + *

This class is used by automated tools to document KeyValues attached to the + * {@code @Scheduled} observations. * * @author Brian Clozel * @since 6.1 @@ -40,19 +42,17 @@ public enum ScheduledTaskObservationDocumentation implements ObservationDocument public Class> getDefaultConvention() { return DefaultScheduledTaskObservationConvention.class; } - @Override public KeyName[] getLowCardinalityKeyNames() { return LowCardinalityKeyNames.values(); } - @Override public KeyName[] getHighCardinalityKeyNames() { return new KeyName[] {}; } - }; + public enum LowCardinalityKeyNames implements KeyName { /** diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorObservabilityTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorObservabilityTests.java index 5578c74531..681a2ff5a1 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorObservabilityTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorObservabilityTests.java @@ -36,8 +36,8 @@ import org.springframework.context.support.StaticApplicationContext; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.scheduling.config.ScheduledTask; import org.springframework.scheduling.config.ScheduledTaskHolder; -import org.springframework.scheduling.config.ScheduledTaskObservationContext; import org.springframework.scheduling.config.ScheduledTaskRegistrar; +import org.springframework.scheduling.support.ScheduledTaskObservationContext; import static org.assertj.core.api.Assertions.assertThat; @@ -55,11 +55,13 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests { private final TestObservationRegistry observationRegistry = TestObservationRegistry.create(); + @AfterEach void closeContext() { context.close(); } + @Test void shouldRecordSuccessObservationsForTasks() throws Exception { registerScheduledBean(FixedDelayBean.class); @@ -185,6 +187,7 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests { .hasObservationWithNameEqualTo("tasks.scheduled.execution").that(); } + static abstract class TaskTester { ObservationRegistry observationRegistry; @@ -200,13 +203,13 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests { } } + static class FixedDelayBean extends TaskTester { @Scheduled(fixedDelay = 10_000, initialDelay = 5_000) public void fixedDelay() { this.latch.countDown(); } - } @@ -217,18 +220,18 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests { this.latch.countDown(); throw new IllegalStateException("test error"); } - } + static class FixedDelayReactiveBean extends TaskTester { @Scheduled(fixedDelay = 10_000, initialDelay = 5_000) public Mono fixedDelay() { return Mono.empty().doOnTerminate(() -> this.latch.countDown()); } - } + static class FixedDelayReactiveErrorBean extends TaskTester { @Scheduled(fixedDelay = 10_000, initialDelay = 5_000) @@ -236,9 +239,9 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests { return Mono.error(new IllegalStateException("test error")) .doOnTerminate(() -> this.latch.countDown()); } - } + static class CancelledTaskBean extends TaskTester { @Scheduled(fixedDelay = 10_000, initialDelay = 5_000) @@ -251,9 +254,9 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests { // ignore cancelled task } } - } + static class CancelledReactiveTaskBean extends TaskTester { @Scheduled(fixedDelay = 10_000, initialDelay = 5_000) @@ -261,9 +264,9 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests { return Flux.interval(Duration.ZERO, Duration.ofSeconds(1)) .doOnNext(el -> this.latch.countDown()); } - } + static class CurrentObservationBean extends TaskTester { @Scheduled(fixedDelay = 10_000, initialDelay = 5_000) @@ -272,9 +275,9 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests { assertThat(this.observationRegistry.getCurrentObservation().getContext()).isInstanceOf(ScheduledTaskObservationContext.class); this.latch.countDown(); } - } + static class CurrentObservationReactiveBean extends TaskTester { @Scheduled(fixedDelay = 10_000, initialDelay = 5_000) @@ -290,7 +293,6 @@ class ScheduledAnnotationBeanPostProcessorObservabilityTests { }) .doOnTerminate(() -> this.latch.countDown()); } - } } diff --git a/spring-context/src/test/java/org/springframework/scheduling/config/DefaultScheduledTaskObservationConventionTests.java b/spring-context/src/test/java/org/springframework/scheduling/support/DefaultScheduledTaskObservationConventionTests.java similarity index 98% rename from spring-context/src/test/java/org/springframework/scheduling/config/DefaultScheduledTaskObservationConventionTests.java rename to spring-context/src/test/java/org/springframework/scheduling/support/DefaultScheduledTaskObservationConventionTests.java index 47da8360b9..91203377bb 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/config/DefaultScheduledTaskObservationConventionTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/support/DefaultScheduledTaskObservationConventionTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.scheduling.config; +package org.springframework.scheduling.support; import java.lang.reflect.Method; @@ -37,6 +37,7 @@ class DefaultScheduledTaskObservationConventionTests { private final ScheduledTaskObservationConvention convention = new DefaultScheduledTaskObservationConvention(); + @Test void observationShouldHaveDefaultName() { assertThat(convention.getName()).isEqualTo("tasks.scheduled.execution"); @@ -92,17 +93,16 @@ class DefaultScheduledTaskObservationConventionTests { } - static class BeanWithScheduledMethods implements TaskProcessor { - - public void process() { - - } - } - interface TaskProcessor { void process(); + } + + static class BeanWithScheduledMethods implements TaskProcessor { + + public void process() { + } } }