diff --git a/pom.xml b/pom.xml
index 9bb75370..fa7d42a2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,6 +48,8 @@
3.1.1
1.17.6
3.1.0
+
+ 1.5.0-SNAPSHOT
@@ -97,6 +99,14 @@ limitations under the License.
pom
import
+
+
+ io.micrometer
+ micrometer-tracing-bom
+ ${micrometer-tracing.version}
+ pom
+ import
+
org.springframework.boot
spring-boot-dependencies
diff --git a/spring-modulith-observability/pom.xml b/spring-modulith-observability/pom.xml
index bd0f2363..6a285292 100644
--- a/spring-modulith-observability/pom.xml
+++ b/spring-modulith-observability/pom.xml
@@ -13,7 +13,11 @@
org.springframework.modulith.observability
- 2021.0.0
+
+ 1.0.4
+ ${project.basedir}/src/main/java/
+ .*
+ ${project.build.directory}/observation-documentation/
@@ -73,12 +77,24 @@
true
+
+ io.micrometer
+ micrometer-core
+ true
+
+
io.zipkin.brave
brave
true
+
+ io.opentelemetry
+ opentelemetry-api
+ true
+
+
@@ -107,4 +123,39 @@
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+
+
+ generate-docs
+ prepare-package
+
+ java
+
+
+ io.micrometer.docs.DocsGeneratorCommand
+ true
+
+ ${micrometer-docs-generator.inputPath}
+ ${micrometer-docs-generator.inclusionPattern}
+ ${micrometer-docs-generator.outputPath}
+
+
+
+
+
+
+ io.micrometer
+ micrometer-docs-generator
+ ${micrometer-docs-generator.version}
+ jar
+
+
+
+
+
+
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/DefaultModulithObservationConvention.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/DefaultModulithObservationConvention.java
new file mode 100644
index 00000000..d42bb4b5
--- /dev/null
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/DefaultModulithObservationConvention.java
@@ -0,0 +1,50 @@
+package org.springframework.modulith.observability;
+
+import java.lang.reflect.Method;
+
+import io.micrometer.common.KeyValues;
+
+import org.springframework.modulith.observability.ModulithObservations.HighKeys;
+import org.springframework.modulith.observability.ModulithObservations.LowKeys;
+
+/**
+ * Default implementation of {@link ModulithObservationConvention}.
+ *
+ * @author Marcin Grzejszczak
+ * @since 1.4
+ */
+public class DefaultModulithObservationConvention implements ModulithObservationConvention {
+
+ @Override
+ public KeyValues getLowCardinalityKeyValues(ModulithContext context) {
+ KeyValues keyValues = KeyValues.of(LowKeys.MODULE_KEY.withValue(context.getModule().getIdentifier().toString()));
+ if (isEventListener(context)) {
+ return keyValues.and(LowKeys.INVOCATION_TYPE.withValue("event-listener"));
+ }
+ return keyValues;
+ }
+
+ private boolean isEventListener(ModulithContext context) {
+ try {
+ return context.getModule().isEventListenerInvocation(context.getInvocation());
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ @Override
+ public KeyValues getHighCardinalityKeyValues(ModulithContext context) {
+ Method method = context.getInvocation().getMethod();
+ return KeyValues.of(HighKeys.MODULE_METHOD.withValue(method.getName()));
+ }
+
+ @Override
+ public String getName() {
+ return "module.requests";
+ }
+
+ @Override
+ public String getContextualName(ModulithContext context) {
+ return "[" + context.getApplicationName() + "] " + context.getModule().getDisplayName();
+ }
+}
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/DefaultObservedModule.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/DefaultObservedModule.java
index 5a54e29a..e97fc963 100644
--- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/DefaultObservedModule.java
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/DefaultObservedModule.java
@@ -25,6 +25,7 @@ import org.springframework.aop.support.AopUtils;
import org.springframework.modulith.core.ApplicationModule;
import org.springframework.modulith.core.ApplicationModuleIdentifier;
import org.springframework.modulith.core.ApplicationModules;
+import org.springframework.modulith.core.ArchitecturallyEvidentType;
import org.springframework.modulith.core.ArchitecturallyEvidentType.ReferenceMethod;
import org.springframework.modulith.core.FormattableType;
import org.springframework.modulith.core.SpringBean;
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleEntryInterceptor.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleEntryInterceptor.java
index ee6ffd74..8ac94a0a 100644
--- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleEntryInterceptor.java
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleEntryInterceptor.java
@@ -15,47 +15,79 @@
*/
package org.springframework.modulith.observability;
-import io.micrometer.tracing.BaggageInScope;
-import io.micrometer.tracing.Tracer;
-import io.micrometer.tracing.Tracer.SpanInScope;
+import io.micrometer.common.KeyValue;
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.ObservationRegistry;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.core.env.Environment;
+import org.springframework.lang.Nullable;
+import org.springframework.modulith.core.ApplicationModuleIdentifier;
+import org.springframework.modulith.observability.ModulithObservations.LowKeys;
import org.springframework.util.Assert;
class ModuleEntryInterceptor implements MethodInterceptor {
private static Logger LOGGER = LoggerFactory.getLogger(ModuleEntryInterceptor.class);
- private static Map CACHE = new HashMap<>();
- private static final String MODULE_KEY = ModuleTracingBeanPostProcessor.MODULE_BAGGAGE_KEY;
+ private static Map CACHE = new HashMap<>();
+
+ private static final ModulithObservationConvention DEFAULT = new DefaultModulithObservationConvention();
private final ObservedModule module;
- private final Tracer tracer;
+ private final ObservationRegistry observationRegistry;
+ @Nullable private final ModulithObservationConvention customModulithObservationConvention;
+ private final Environment environment;
/**
- * Creates a new {@link ModuleEntryInterceptor} for the given {@link ObservedModule} and {@link Tracer}.
+ * Creates a new {@link ModuleEntryInterceptor} for the given {@link ObservedModule} and {@link ObservationRegistry}.
*
* @param module must not be {@literal null}.
- * @param tracer must not be {@literal null}.
+ * @param observationRegistry must not be {@literal null}.
+ * @param environment must not be {@literal null}.
*/
- private ModuleEntryInterceptor(ObservedModule module, Tracer tracer) {
-
- Assert.notNull(module, "ObservedModule must not be null!");
- Assert.notNull(tracer, "Tracer must not be null!");
-
- this.module = module;
- this.tracer = tracer;
+ private ModuleEntryInterceptor(ObservedModule module, ObservationRegistry observationRegistry,
+ Environment environment) {
+ this(module, observationRegistry, null, environment);
}
- public static ModuleEntryInterceptor of(ObservedModule module, Tracer tracer) {
+ /**
+ * Creates a new {@link ModuleEntryInterceptor} for the given {@link ObservedModule}, {@link ObservationRegistry} and
+ * {@link ModulithObservationConvention}.
+ *
+ * @param module must not be {@literal null}.
+ * @param observationRegistry must not be {@literal null}.
+ * @param custom must not be {@literal null}.
+ * @param environment must not be {@literal null}.
+ */
+ private ModuleEntryInterceptor(ObservedModule module, ObservationRegistry observationRegistry,
+ ModulithObservationConvention custom, Environment environment) {
- return CACHE.computeIfAbsent(module.getName(), __ -> {
- return new ModuleEntryInterceptor(module, tracer);
+ Assert.notNull(module, "ObservedModule must not be null!");
+ Assert.notNull(observationRegistry, "ObservationRegistry must not be null!");
+
+ this.module = module;
+ this.observationRegistry = observationRegistry;
+ this.customModulithObservationConvention = custom;
+ this.environment = environment;
+ }
+
+ public static ModuleEntryInterceptor of(ObservedModule module, ObservationRegistry observationRegistry,
+ Environment environment) {
+ return of(module, observationRegistry, null, environment);
+ }
+
+ public static ModuleEntryInterceptor of(ObservedModule module, ObservationRegistry observationRegistry,
+ ModulithObservationConvention custom, Environment environment) {
+
+ return CACHE.computeIfAbsent(module.getIdentifier(), __ -> {
+ return new ModuleEntryInterceptor(module, observationRegistry, custom, environment);
});
}
@@ -66,12 +98,17 @@ class ModuleEntryInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
- var moduleName = module.getName();
- var currentSpan = tracer.currentSpan();
- var currentBaggage = tracer.getBaggage(MODULE_KEY);
- var currentModule = currentBaggage != null ? currentBaggage.get() : null;
+ var moduleIdentifier = module.getIdentifier();
+ var currentObservation = observationRegistry.getCurrentObservation();
+ String currentModule = null;
- if (currentSpan != null && moduleName.equals(currentModule)) {
+ if (currentObservation != null) {
+ KeyValue moduleKey = currentObservation.getContextView().getLowCardinalityKeyValue(LowKeys.MODULE_KEY.asString());
+ currentModule = moduleKey != null ? moduleKey.getValue() : null;
+ }
+
+ if (currentObservation != null && Objects.equals(moduleIdentifier.toString(), currentModule)) {
+ // Same module
return invocation.proceed();
}
@@ -79,21 +116,20 @@ class ModuleEntryInterceptor implements MethodInterceptor {
LOGGER.trace("Entering {} via {}.", module.getDisplayName(), invokedMethod);
- var span = tracer.spanBuilder()
- .name(moduleName)
- .tag("module.method", invokedMethod)
- .tag(MODULE_KEY, moduleName)
- .start();
-
- try (SpanInScope ws = tracer.withSpan(span);
- BaggageInScope baggage = tracer.createBaggageInScope(MODULE_KEY, moduleName)) {
-
- return invocation.proceed();
-
+ ModulithContext modulithContext = new ModulithContext(module, invocation, environment);
+ var observation = Observation.createNotStarted(customModulithObservationConvention, DEFAULT,
+ () -> modulithContext, observationRegistry);
+ try (Observation.Scope scope = observation.start().openScope()) {
+ Object proceed = invocation.proceed();
+ observation.event(ModulithObservations.Events.EVENT_PUBLICATION_SUCCESS);
+ return proceed;
+ } catch (Exception ex) {
+ observation.error(ex);
+ observation.event(ModulithObservations.Events.EVENT_PUBLICATION_FAILURE);
+ throw ex;
} finally {
-
LOGGER.trace("Leaving {}", module.getDisplayName());
- span.end();
+ observation.stop();
}
}
}
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleEventListener.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleEventListener.java
index 64648865..4eac054d 100644
--- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleEventListener.java
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleEventListener.java
@@ -15,13 +15,17 @@
*/
package org.springframework.modulith.observability;
-import io.micrometer.tracing.Tracer;
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.observation.Observation.Event;
+import io.micrometer.observation.ObservationRegistry;
import java.util.function.Supplier;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.PayloadApplicationEvent;
+import org.springframework.modulith.observability.ModulithObservations.Events;
import org.springframework.modulith.runtime.ApplicationModulesRuntime;
import org.springframework.util.Assert;
@@ -31,21 +35,25 @@ import org.springframework.util.Assert;
public class ModuleEventListener implements ApplicationListener {
private final ApplicationModulesRuntime runtime;
- private final Supplier tracer;
+ private final Supplier observationRegistry;
+ private final Supplier meterRegistry;
/**
- * Creates a new {@link ModuleEventListener} for the given {@link ApplicationModulesRuntime} and {@link Tracer}.
+ * Creates a new {@link ModuleEventListener} for the given {@link ApplicationModulesRuntime} and {@link ObservationRegistry} and {@link MeterRegistry}.
*
* @param runtime must not be {@literal null}.
- * @param tracer must not be {@literal null}.
+ * @param observationRegistrySupplier must not be {@literal null}.
*/
- public ModuleEventListener(ApplicationModulesRuntime runtime, Supplier tracer) {
+ public ModuleEventListener(ApplicationModulesRuntime runtime, Supplier observationRegistrySupplier,
+ Supplier meterRegistrySupplier) {
Assert.notNull(runtime, "ApplicationModulesRuntime must not be null!");
- Assert.notNull(tracer, "Tracer must not be null!");
+ Assert.notNull(observationRegistrySupplier, "ObservationRegistry must not be null!");
+ Assert.notNull(meterRegistrySupplier, "MeterRegistry must not be null!");
this.runtime = runtime;
- this.tracer = tracer;
+ this.observationRegistry = observationRegistrySupplier;
+ this.meterRegistry = meterRegistrySupplier;
}
/*
@@ -74,12 +82,20 @@ public class ModuleEventListener implements ApplicationListener tracer;
+ private final Supplier observationRegistry;
private final Map advisors;
private final ConfigurableListableBeanFactory factory;
+ private final Environment environment;
/**
- * Creates a new {@link ModuleTracingBeanPostProcessor} for the given {@link ApplicationModulesRuntime} and
- * {@link Tracer}.
+ * Creates a new {@link ModuleObservabilityBeanPostProcessor} for the given {@link ApplicationModulesRuntime} and
+ * {@link ObservationRegistry}.
*
* @param runtime must not be {@literal null}.
- * @param tracer must not be {@literal null}.
+ * @param observationRegistry must not be {@literal null}.
+ * @param factory must not be {@literal null}.
+ * @param environment must not be {@literal null}.
*/
- public ModuleTracingBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier tracer,
- ConfigurableListableBeanFactory factory) {
+ public ModuleObservabilityBeanPostProcessor(ApplicationModulesRuntime runtime,
+ Supplier observationRegistry, ConfigurableListableBeanFactory factory,
+ Environment environment) {
Assert.notNull(runtime, "ApplicationModulesRuntime must not be null!");
- Assert.notNull(tracer, "Tracer must not be null!");
+ Assert.notNull(observationRegistry, "ObservationRegistry must not be null!");
+ Assert.notNull(factory, "BeanFactory must not be null!");
+ Assert.notNull(environment, "Environment must not be null!");
this.runtime = runtime;
- this.tracer = tracer;
+ this.observationRegistry = observationRegistry;
this.advisors = new HashMap<>();
this.factory = factory;
+ this.environment = environment;
}
/*
@@ -99,15 +108,17 @@ public class ModuleTracingBeanPostProcessor extends ModuleTracingSupport impleme
var modules = runtime.get();
- return modules.getModuleByType(type.getName()).map(DefaultObservedModule::new).map(it -> {
+ return modules.getModuleByType(type.getName())
+ .map(DefaultObservedModule::new)
+ .map(it -> {
- var moduleType = it.getObservedModuleType(type, modules);
+ var moduleType = it.getObservedModuleType(type, modules);
- return moduleType != null //
- ? addAdvisor(bean, getOrBuildAdvisor(it, moduleType)) //
- : bean;
+ return moduleType != null //
+ ? addAdvisor(bean, getOrBuildAdvisor(it, moduleType)) //
+ : bean;
- }).orElse(bean);
+ }).orElse(bean);
}
private boolean isInfrastructureBean(String beanName) {
@@ -129,8 +140,9 @@ public class ModuleTracingBeanPostProcessor extends ModuleTracingSupport impleme
private Advisor getOrBuildAdvisor(ObservedModule module, ObservedModuleType type) {
- return advisors.computeIfAbsent(module.getName(), __ -> {
- return new ApplicationModuleObservingAdvisor(type, ModuleEntryInterceptor.of(module, tracer.get()));
+ return advisors.computeIfAbsent(module.getIdentifier().toString(), __ -> {
+ return new ApplicationModuleObservingAdvisor(type,
+ ModuleEntryInterceptor.of(module, observationRegistry.get(), environment));
});
}
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleTracingSupport.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleObservabilitySupport.java
similarity index 97%
rename from spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleTracingSupport.java
rename to spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleObservabilitySupport.java
index 49ed862d..1dc64a5a 100644
--- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleTracingSupport.java
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleObservabilitySupport.java
@@ -31,7 +31,7 @@ import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor;
/**
* @author Oliver Drotbohm
*/
-class ModuleTracingSupport implements BeanClassLoaderAware, BeanFactoryAware {
+class ModuleObservabilitySupport implements BeanClassLoaderAware, BeanFactoryAware {
private ClassLoader classLoader;
private @Nullable AbstractAutoProxyCreator creator;
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulePassingObservationFilter.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulePassingObservationFilter.java
new file mode 100644
index 00000000..4e20bd47
--- /dev/null
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulePassingObservationFilter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022-2024 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.modulith.observability;
+
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.ObservationFilter;
+
+/**
+ * Ensures that {@link ModulithObservations.LowKeys#MODULE_KEY} gets propagated from parent
+ * to child.
+ *
+ * @author Marcin Grzejszczak
+ * @since 1.4
+ */
+public class ModulePassingObservationFilter implements ObservationFilter {
+
+ @Override
+ public Observation.Context map(Observation.Context context) {
+ if (isModuleKeyValueAbsentInCurrent(context) && isModuleKeyValuePresentInParent(context)) {
+ return context.addLowCardinalityKeyValue(ModulithObservations.LowKeys.MODULE_KEY.withValue(context.getParentObservation().getContextView().getLowCardinalityKeyValue(ModulithObservations.LowKeys.MODULE_KEY.asString()).getValue()));
+ }
+ return context;
+ }
+
+ private static boolean isModuleKeyValueAbsentInCurrent(Observation.ContextView context) {
+ return context.getLowCardinalityKeyValue(ModulithObservations.LowKeys.MODULE_KEY.asString()) == null;
+ }
+
+ private static boolean isModuleKeyValuePresentInParent(Observation.ContextView context) {
+ return context.getParentObservation() != null && context.getParentObservation().getContextView().getLowCardinalityKeyValue(ModulithObservations.LowKeys.MODULE_KEY.asString()) != null;
+ }
+}
\ No newline at end of file
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithContext.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithContext.java
new file mode 100644
index 00000000..b6a5b189
--- /dev/null
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithContext.java
@@ -0,0 +1,39 @@
+package org.springframework.modulith.observability;
+
+import io.micrometer.observation.Observation;
+import org.aopalliance.intercept.MethodInvocation;
+
+import org.springframework.core.env.Environment;
+
+/**
+ * A {@link Observation.Context} for Modulithic applications.
+ *
+ * @author Marcin Grzejsczak
+ * @since 1.4
+ */
+public class ModulithContext extends Observation.Context {
+
+ private final ObservedModule module;
+
+ private final MethodInvocation invocation;
+
+ private final String applicationName;
+
+ public ModulithContext(ObservedModule module, MethodInvocation invocation, Environment environment) {
+ this.module = module;
+ this.invocation = invocation;
+ this.applicationName = environment.getProperty("spring.application.name");
+ }
+
+ public ObservedModule getModule() {
+ return module;
+ }
+
+ public MethodInvocation getInvocation() {
+ return invocation;
+ }
+
+ public String getApplicationName() {
+ return applicationName;
+ }
+}
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithMetrics.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithMetrics.java
new file mode 100644
index 00000000..377d5531
--- /dev/null
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithMetrics.java
@@ -0,0 +1,50 @@
+package org.springframework.modulith.observability;
+
+import io.micrometer.common.docs.KeyName;
+import io.micrometer.core.instrument.Meter;
+import io.micrometer.core.instrument.docs.MeterDocumentation;
+
+enum ModulithMetrics implements MeterDocumentation {
+
+ /**
+ * Counter for the events.
+ */
+ EVENTS {
+ @Override
+ public String getName() {
+ return "modulith.events.processed";
+ }
+
+ @Override
+ public Meter.Type getType() {
+ return Meter.Type.COUNTER;
+ }
+
+ @Override
+ public KeyName[] getKeyNames() {
+ return LowKeys.values();
+ }
+ };
+
+ enum LowKeys implements KeyName {
+ /**
+ * Type of the emitted event.
+ */
+ EVENT_TYPE {
+ @Override
+ public String asString() {
+ return "event.type";
+ }
+ },
+
+ /**
+ * Name of the module.
+ */
+ MODULE_NAME {
+ @Override
+ public String asString() {
+ return "module.name";
+ }
+ }
+ }
+}
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithObservationConvention.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithObservationConvention.java
new file mode 100644
index 00000000..b6df45b4
--- /dev/null
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithObservationConvention.java
@@ -0,0 +1,18 @@
+package org.springframework.modulith.observability;
+
+import io.micrometer.observation.Observation.Context;
+import io.micrometer.observation.ObservationConvention;
+
+/**
+ * {@link ObservationConvention} for {@link ModulithContext}.
+ *
+ * @author Marcin Grzejszczak
+ * @since 1.4
+ */
+public interface ModulithObservationConvention extends ObservationConvention {
+
+ @Override
+ default boolean supportsContext(Context context) {
+ return context instanceof ModulithContext;
+ }
+}
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithObservations.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithObservations.java
new file mode 100644
index 00000000..bf68bbe2
--- /dev/null
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulithObservations.java
@@ -0,0 +1,92 @@
+package org.springframework.modulith.observability;
+
+import io.micrometer.common.docs.KeyName;
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.Observation.Context;
+import io.micrometer.observation.ObservationConvention;
+import io.micrometer.observation.docs.ObservationDocumentation;
+
+enum ModulithObservations implements ObservationDocumentation {
+
+ /**
+ * Observation related to entering a module.
+ */
+ MODULE_ENTRY {
+ @Override public Class extends ObservationConvention extends Context>> getDefaultConvention() {
+ return DefaultModulithObservationConvention.class;
+ }
+
+ @Override public KeyName[] getLowCardinalityKeyNames() {
+ return LowKeys.values();
+ }
+
+ @Override public KeyName[] getHighCardinalityKeyNames() {
+ return HighKeys.values();
+ }
+
+ @Override public Observation.Event[] getEvents() {
+ return Events.values();
+ }
+ };
+
+ enum LowKeys implements KeyName {
+
+ /**
+ * Name of the module.
+ */
+ MODULE_KEY {
+ @Override public String asString() {
+ return "module.key";
+ }
+ },
+
+ /**
+ * Type of invocation (e.g. event listener).
+ */
+ INVOCATION_TYPE {
+ @Override public String asString() {
+ return "module.invocation-type";
+ }
+ }
+ }
+
+ enum HighKeys implements KeyName {
+ /**
+ * Method executed on a module.
+ */
+ MODULE_METHOD {
+ @Override public String asString() {
+ return "module.method";
+ }
+ }
+ }
+
+ enum Events implements Observation.Event {
+
+ /**
+ * Published when an event is sent successfully.
+ */
+ EVENT_PUBLICATION_SUCCESS {
+ @Override public String getName() {
+ return "event.publication.success";
+ }
+
+ @Override public String getContextualName() {
+ return getName();
+ }
+ },
+
+ /**
+ * Published when an event is sent with a failure.
+ */
+ EVENT_PUBLICATION_FAILURE {
+ @Override public String getName() {
+ return "event.publication.failure";
+ }
+
+ @Override public String getContextualName() {
+ return getName();
+ }
+ }
+ }
+}
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ObservedModule.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ObservedModule.java
index 763c0d8a..44a99baf 100644
--- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ObservedModule.java
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ObservedModule.java
@@ -24,11 +24,15 @@ import org.springframework.modulith.core.ApplicationModuleIdentifier;
import org.springframework.modulith.core.ApplicationModules;
import com.tngtech.archunit.core.domain.JavaClass;
+import org.springframework.modulith.core.ArchitecturallyEvidentType;
/**
+ * Information about observed module.
+ *
* @author Oliver Drotbohm
+ * @since 1.4
*/
-interface ObservedModule {
+public interface ObservedModule {
/**
* Returns the name of the application module.
@@ -86,7 +90,7 @@ interface ObservedModule {
* method invocation on a Spring bean.
*
* @param invocation must not be {@literal null}.
- * @since 1.3
+ * @since 1.4
*/
boolean isEventListenerInvocation(MethodInvocation invocation);
}
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ObservedModuleType.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ObservedModuleType.java
index c0c616c5..0362cb2c 100644
--- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ObservedModuleType.java
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ObservedModuleType.java
@@ -37,8 +37,9 @@ import com.tngtech.archunit.core.domain.JavaClass;
* Represents a type in an {@link ObservedModule}.
*
* @author Oliver Drotbohm
+ * @since 1.4
*/
-class ObservedModuleType {
+public class ObservedModuleType {
private static final Collection> IGNORED_TYPES = List.of(Advised.class, TargetClassAware.class);
private static final Predicate IS_USER_METHOD = it -> !Modifier.isPrivate(it.getModifiers())
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/SpringDataRestModuleTracingBeanPostProcessor.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/SpringDataRestModuleObservabilityBeanPostProcessor.java
similarity index 67%
rename from spring-modulith-observability/src/main/java/org/springframework/modulith/observability/SpringDataRestModuleTracingBeanPostProcessor.java
rename to spring-modulith-observability/src/main/java/org/springframework/modulith/observability/SpringDataRestModuleObservabilityBeanPostProcessor.java
index 830baf25..c7c8cdf4 100644
--- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/SpringDataRestModuleTracingBeanPostProcessor.java
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/SpringDataRestModuleObservabilityBeanPostProcessor.java
@@ -15,7 +15,7 @@
*/
package org.springframework.modulith.observability;
-import io.micrometer.tracing.Tracer;
+import io.micrometer.observation.ObservationRegistry;
import java.util.function.Supplier;
@@ -27,6 +27,7 @@ import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.core.env.Environment;
import org.springframework.data.rest.webmvc.BasePathAwareController;
import org.springframework.data.rest.webmvc.RootResourceInformation;
import org.springframework.modulith.core.ApplicationModule;
@@ -37,25 +38,28 @@ import org.springframework.util.Assert;
/**
* @author Oliver Drotbohm
*/
-public class SpringDataRestModuleTracingBeanPostProcessor extends ModuleTracingSupport implements BeanPostProcessor {
+public class SpringDataRestModuleObservabilityBeanPostProcessor extends ModuleObservabilitySupport implements BeanPostProcessor {
private final ApplicationModulesRuntime runtime;
- private final Supplier tracer;
+ private final Supplier observationRegistry;
+ private final Environment environment;
/**
- * Creates a new {@link SpringDataRestModuleTracingBeanPostProcessor} for the given {@link ApplicationModulesRuntime}
- * and {@link Tracer}.
+ * Creates a new {@link SpringDataRestModuleObservabilityBeanPostProcessor} for the given {@link ApplicationModulesRuntime}
+ * and {@link ObservationRegistry}.
*
* @param runtime must not be {@literal null}.
- * @param tracer must not be {@literal null}.
+ * @param observationRegistry must not be {@literal null}.
+ * @param environment must not be {@literal null}.
*/
- public SpringDataRestModuleTracingBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier tracer) {
+ public SpringDataRestModuleObservabilityBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier observationRegistry, Environment environment) {
Assert.notNull(runtime, "ApplicationModulesRuntime must not be null!");
- Assert.notNull(tracer, "Tracer must not be null!");
+ Assert.notNull(observationRegistry, "ObservationRegistry must not be null!");
this.runtime = runtime;
- this.tracer = tracer;
+ this.observationRegistry = observationRegistry;
+ this.environment = environment;
}
/*
@@ -71,7 +75,7 @@ public class SpringDataRestModuleTracingBeanPostProcessor extends ModuleTracingS
return bean;
}
- Advice interceptor = new DataRestControllerInterceptor(runtime, tracer);
+ Advice interceptor = new DataRestControllerInterceptor(runtime, observationRegistry, environment);
Advisor advisor = new DefaultPointcutAdvisor(interceptor);
return addAdvisor(bean, advisor, it -> it.setProxyTargetClass(true));
@@ -80,21 +84,26 @@ public class SpringDataRestModuleTracingBeanPostProcessor extends ModuleTracingS
private static class DataRestControllerInterceptor implements MethodInterceptor {
private final Supplier modules;
- private final Supplier tracer;
+ private final Supplier observationRegistry;
+ private final Environment environment;
/**
* Creates a new {@link DataRestControllerInterceptor} for the given {@link ApplicationModules} and {@link Tracer}.
*
- * @param modules must not be {@literal null}.
- * @param tracer must not be {@literal null}.
+ * @param modules must not be {@literal null}.
+ * @param observationRegistry must not be {@literal null}.
+ * @param environment must not be {@literal null}.
*/
- private DataRestControllerInterceptor(Supplier modules, Supplier tracer) {
+ private DataRestControllerInterceptor(Supplier modules, Supplier observationRegistry,
+ Environment environment) {
Assert.notNull(modules, "ApplicationModules must not be null!");
- Assert.notNull(tracer, "Tracer must not be null!");
+ Assert.notNull(observationRegistry, "ObservationRegistry must not be null!");
+ Assert.notNull(environment, "Environment must not be null!");
this.modules = modules;
- this.tracer = tracer;
+ this.observationRegistry = observationRegistry;
+ this.environment = environment;
}
/*
@@ -112,7 +121,7 @@ public class SpringDataRestModuleTracingBeanPostProcessor extends ModuleTracingS
var observed = new DefaultObservedModule(module);
- return ModuleEntryInterceptor.of(observed, tracer.get()).invoke(invocation);
+ return ModuleEntryInterceptor.of(observed, observationRegistry.get(), environment).invoke(invocation);
}
private ApplicationModule getModuleFrom(Object[] arguments) {
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/ModuleObservabilityAutoConfiguration.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/ModuleObservabilityAutoConfiguration.java
index 2023d3d5..2254e43e 100644
--- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/ModuleObservabilityAutoConfiguration.java
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/ModuleObservabilityAutoConfiguration.java
@@ -15,14 +15,12 @@
*/
package org.springframework.modulith.observability.autoconfigure;
-import brave.TracingCustomizer;
-import brave.baggage.BaggageField;
-import brave.baggage.BaggagePropagationConfig;
-import brave.baggage.BaggagePropagationCustomizer;
import brave.handler.MutableSpan;
import brave.handler.SpanHandler;
import brave.propagation.TraceContext;
-import io.micrometer.tracing.Tracer;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.observation.ObservationFilter;
+import io.micrometer.observation.ObservationRegistry;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -34,9 +32,11 @@ import org.springframework.boot.task.SimpleAsyncTaskExecutorCustomizer;
import org.springframework.boot.task.ThreadPoolTaskExecutorCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
import org.springframework.core.task.support.ContextPropagatingTaskDecorator;
import org.springframework.modulith.observability.ModuleEventListener;
-import org.springframework.modulith.observability.ModuleTracingBeanPostProcessor;
+import org.springframework.modulith.observability.ModuleObservabilityBeanPostProcessor;
+import org.springframework.modulith.observability.ModulePassingObservationFilter;
import org.springframework.modulith.runtime.ApplicationModulesRuntime;
/**
@@ -47,17 +47,18 @@ import org.springframework.modulith.runtime.ApplicationModulesRuntime;
class ModuleObservabilityAutoConfiguration {
@Bean
- static ModuleTracingBeanPostProcessor moduleTracingBeanPostProcessor(ApplicationModulesRuntime runtime,
- ObjectProvider tracer, ConfigurableListableBeanFactory factory) {
- return new ModuleTracingBeanPostProcessor(runtime, () -> tracer.getObject(), factory);
+ static ModuleObservabilityBeanPostProcessor moduleTracingBeanPostProcessor(ApplicationModulesRuntime runtime,
+ ObjectProvider observationRegistry, ConfigurableListableBeanFactory factory, Environment environment) {
+ return new ModuleObservabilityBeanPostProcessor(runtime, observationRegistry::getObject, factory, environment);
}
@Bean
static ModuleEventListener tracingModuleEventListener(ApplicationModulesRuntime runtime,
- ObjectProvider tracer) {
- return new ModuleEventListener(runtime, () -> tracer.getObject());
+ ObjectProvider observationRegistry, ObjectProvider meterRegistry) {
+ return new ModuleEventListener(runtime, observationRegistry::getObject, meterRegistry::getObject);
}
+ // TODO: Have a custom thread pool for modulith
@Bean
@ConditionalOnThreading(Threading.VIRTUAL)
SimpleAsyncTaskExecutorCustomizer simpleAsyncTaskExecutorCustomizer() {
@@ -70,51 +71,31 @@ class ModuleObservabilityAutoConfiguration {
return executor -> executor.setTaskDecorator(new ContextPropagatingTaskDecorator());
}
- /**
- * Brave-specific auto configuration.
- *
- * @author Oliver Drotbohm
- */
- @ConditionalOnClass(TracingCustomizer.class)
- static class ModulithsBraveIntegrationAutoConfiguration {
+ @Bean
+ ObservationFilter modulePassingObservationFilter() {
+ return new ModulePassingObservationFilter();
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(SpanHandler.class)
+ static class BraveConfiguration {
+ /**
+ * Corresponds to {@link ModulithObservations.LowKeys#MODULE_KEY}
+ */
+ private static final String MODULE_KEY_TAG_NAME = "module.key";
@Bean
- BaggagePropagationCustomizer moduleBaggagePropagationCustomizer() {
-
- return builder -> builder
- .add(BaggagePropagationConfig.SingleBaggageField
- .local(BaggageField.create(ModuleTracingBeanPostProcessor.MODULE_BAGGAGE_KEY)));
- }
-
- @Bean
- SpanHandler spanHandler() {
-
+ SpanHandler localServiceNameRenamingSpanHandler() {
return new SpanHandler() {
-
- /*
- * (non-Javadoc)
- * @see brave.handler.SpanHandler#end(brave.propagation.TraceContext, brave.handler.MutableSpan, brave.handler.SpanHandler.Cause)
- */
- @Override
- public boolean end(TraceContext context, MutableSpan span, Cause cause) {
-
- String value = span.tag(ModuleTracingBeanPostProcessor.MODULE_BAGGAGE_KEY);
-
- if (value != null) {
- span.localServiceName(value);
- return true;
+ @Override public boolean end(TraceContext context, MutableSpan span, Cause cause) {
+ String tag = span.tag(MODULE_KEY_TAG_NAME);
+ if (tag != null) {
+ span.localServiceName(tag);
}
-
- BaggageField field = BaggageField.getByName(context, ModuleTracingBeanPostProcessor.MODULE_BAGGAGE_KEY);
- value = field.getValue();
-
- if (value != null) {
- span.localServiceName(value);
- }
-
- return true;
+ return super.end(context, span, cause);
}
};
}
}
+
}
diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/SpringDataRestModuleObservabilityAutoConfiguration.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/SpringDataRestModuleObservabilityAutoConfiguration.java
index 2b71ac46..8ef88e5c 100644
--- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/SpringDataRestModuleObservabilityAutoConfiguration.java
+++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/autoconfigure/SpringDataRestModuleObservabilityAutoConfiguration.java
@@ -15,14 +15,15 @@
*/
package org.springframework.modulith.observability.autoconfigure;
-import io.micrometer.tracing.Tracer;
+import io.micrometer.observation.ObservationRegistry;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
import org.springframework.data.rest.webmvc.RepositoryController;
-import org.springframework.modulith.observability.SpringDataRestModuleTracingBeanPostProcessor;
+import org.springframework.modulith.observability.SpringDataRestModuleObservabilityBeanPostProcessor;
import org.springframework.modulith.runtime.ApplicationModulesRuntime;
/**
@@ -33,9 +34,9 @@ import org.springframework.modulith.runtime.ApplicationModulesRuntime;
class SpringDataRestModuleObservabilityAutoConfiguration {
@Bean
- static SpringDataRestModuleTracingBeanPostProcessor springDataRestModuleTracingBeanPostProcessor(
- ApplicationModulesRuntime runtime, ObjectProvider tracer) {
+ static SpringDataRestModuleObservabilityBeanPostProcessor springDataRestModuleTracingBeanPostProcessor(
+ ApplicationModulesRuntime runtime, ObjectProvider observationRegistry, Environment environment) {
- return new SpringDataRestModuleTracingBeanPostProcessor(runtime, () -> tracer.getObject());
+ return new SpringDataRestModuleObservabilityBeanPostProcessor(runtime, () -> observationRegistry.getObject(), environment);
}
}
diff --git a/spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleTracingBeanPostProcessorIntegrationTests.java b/spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleObservabilityBeanPostProcessorIntegrationTests.java
similarity index 77%
rename from spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleTracingBeanPostProcessorIntegrationTests.java
rename to spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleObservabilityBeanPostProcessorIntegrationTests.java
index 3e12cd76..bc94420b 100644
--- a/spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleTracingBeanPostProcessorIntegrationTests.java
+++ b/spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleObservabilityBeanPostProcessorIntegrationTests.java
@@ -16,11 +16,10 @@
package org.springframework.modulith.observability;
import static org.assertj.core.api.Assertions.*;
-import static org.mockito.Mockito.*;
import example.ExampleApplication;
import example.sample.SampleComponent;
-import io.micrometer.tracing.Tracer;
+import io.micrometer.observation.ObservationRegistry;
import org.junit.jupiter.api.Test;
import org.springframework.aop.Advisor;
@@ -29,24 +28,24 @@ import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.modulith.observability.ModuleTracingBeanPostProcessor.ApplicationModuleObservingAdvisor;
+import org.springframework.modulith.observability.ModuleObservabilityBeanPostProcessor.ApplicationModuleObservingAdvisor;
import org.springframework.modulith.runtime.ApplicationModulesRuntime;
import org.springframework.modulith.runtime.ApplicationRuntime;
import org.springframework.modulith.test.TestApplicationModules;
import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor;
/**
- * Integration tests for {@link ModuleTracingBeanPostProcessor}.
+ * Integration tests for {@link ModuleObservabilityBeanPostProcessor}.
*
* @author Oliver Drotbohm
*/
-class ModuleTracingBeanPostProcessorIntegrationTests {
+class ModuleObservabilityBeanPostProcessorIntegrationTests {
@Test
void decoratesExposedComponentsWithTracingInterceptor() {
SampleComponent bean = SpringApplication
- .run(new Class>[] { ExampleApplication.class, ModuleTracingConfiguration.class }, new String[] {})
+ .run(new Class>[] { ExampleApplication.class, ModuleObservabilityConfiguration.class }, new String[] {})
.getBean(SampleComponent.class);
assertThat(bean).isInstanceOfSatisfying(Advised.class, it -> {
@@ -61,16 +60,15 @@ class ModuleTracingBeanPostProcessorIntegrationTests {
}
@Configuration
- static class ModuleTracingConfiguration {
+ static class ModuleObservabilityConfiguration {
- @Bean
- ModuleTracingBeanPostProcessor foo(ConfigurableApplicationContext context) {
+ @Bean ModuleObservabilityBeanPostProcessor foo(ConfigurableApplicationContext context) {
var runtime = ApplicationRuntime.of(context);
var modulesRuntime = new ApplicationModulesRuntime(() -> TestApplicationModules.of(ExampleApplication.class),
runtime);
- return new ModuleTracingBeanPostProcessor(modulesRuntime, () -> mock(Tracer.class), context.getBeanFactory());
+ return new ModuleObservabilityBeanPostProcessor(modulesRuntime, () -> ObservationRegistry.NOOP, context.getBeanFactory(), context.getEnvironment());
}
}
diff --git a/spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleTracingBeanPostProcessorUnitTests.java b/spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleObservabilityBeanPostProcessorUnitTests.java
similarity index 81%
rename from spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleTracingBeanPostProcessorUnitTests.java
rename to spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleObservabilityBeanPostProcessorUnitTests.java
index 747dcabe..694839ac 100644
--- a/spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleTracingBeanPostProcessorUnitTests.java
+++ b/spring-modulith-observability/src/test/java/org/springframework/modulith/observability/ModuleObservabilityBeanPostProcessorUnitTests.java
@@ -25,14 +25,15 @@ import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.annotation.RabbitListenerAnnotationBeanPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.mock.env.MockEnvironment;
import org.springframework.modulith.runtime.ApplicationModulesRuntime;
/**
- * Unit tests for {@link ModuleTracingBeanPostProcessor}.
+ * Unit tests for {@link ModuleObservabilityBeanPostProcessor}.
*
* @author Oliver Drotbohm
*/
-class ModuleTracingBeanPostProcessorUnitTests {
+class ModuleObservabilityBeanPostProcessorUnitTests {
@Test // GH-498
void doesNotProxyConfiguationProperties() {
@@ -44,7 +45,7 @@ class ModuleTracingBeanPostProcessorUnitTests {
doReturn(SampleProperties.class).when(mock).getUserClass(any(), any());
doReturn(true).when(mock).isApplicationClass(any());
- var processor = new ModuleTracingBeanPostProcessor(mock, () -> null, beanFactory);
+ var processor = new ModuleObservabilityBeanPostProcessor(mock, () -> null, beanFactory, new MockEnvironment());
var bean = new SampleProperties();
var result = processor.postProcessAfterInitialization(bean, "properties");
@@ -56,8 +57,8 @@ class ModuleTracingBeanPostProcessorUnitTests {
void processorIsRegisteredBefore() {
var rabbitProcessor = new RabbitListenerAnnotationBeanPostProcessor();
- var tracingProcessor = new ModuleTracingBeanPostProcessor(mock(ApplicationModulesRuntime.class), () -> null,
- new DefaultListableBeanFactory());
+ var tracingProcessor = new ModuleObservabilityBeanPostProcessor(mock(ApplicationModulesRuntime.class), () -> null,
+ new DefaultListableBeanFactory(), new MockEnvironment());
assertThat(rabbitProcessor.getOrder()).isGreaterThan(tracingProcessor.getOrder());