WIP. Current code works with tracing 1.5.0 - leaving this for future reference
This commit is contained in:
10
pom.xml
10
pom.xml
@@ -47,6 +47,8 @@
|
||||
<spring-framework.version>6.2.0-RC3</spring-framework.version> <!-- For Javadoc links only -->
|
||||
<spring-cloud-aws-bom.version>3.1.1</spring-cloud-aws-bom.version>
|
||||
<testcontainers.version>1.17.6</testcontainers.version>
|
||||
<!-- TODO: For snapshots -->
|
||||
<micrometer-tracing.version>1.5.0-SNAPSHOT</micrometer-tracing.version>
|
||||
|
||||
</properties>
|
||||
|
||||
@@ -96,6 +98,14 @@ limitations under the License.
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<!-- TODO: For snapshots -->
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-tracing-bom</artifactId>
|
||||
<version>${micrometer-tracing.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
|
||||
@@ -3,35 +3,48 @@ 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.3
|
||||
*/
|
||||
public class DefaultModulithObservationConvention implements ModulithObservationConvention {
|
||||
|
||||
@Override
|
||||
public KeyValues getLowCardinalityKeyValues(ModulithContext context) {
|
||||
ObservedModule currentModule = context.getModule();
|
||||
if (currentModule != null) {
|
||||
return KeyValues.of(LowKeys.MODULE_KEY.withValue(currentModule.getName()));
|
||||
}
|
||||
return KeyValues.empty();
|
||||
}
|
||||
@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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyValues getHighCardinalityKeyValues(ModulithContext context) {
|
||||
Method method = context.getInvocation().getMethod();
|
||||
return KeyValues.of(HighKeys.MODULE_METHOD.withValue(method.getName()));
|
||||
}
|
||||
private boolean isEventListener(ModulithContext context) {
|
||||
try {
|
||||
return context.getModule().isEventListenerInvocation(context.getInvocation());
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "module.requests";
|
||||
}
|
||||
@Override
|
||||
public KeyValues getHighCardinalityKeyValues(ModulithContext context) {
|
||||
Method method = context.getInvocation().getMethod();
|
||||
return KeyValues.of(HighKeys.MODULE_METHOD.withValue(method.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextualName(ModulithContext context) {
|
||||
// TODO: Change this to application name
|
||||
return "[" + context.getModule().getDisplayName() + "] " + context.getModule()
|
||||
.getDisplayName();
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return "module.requests";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextualName(ModulithContext context) {
|
||||
return "[" + context.getApplicationName() + "] " + context.getModule().getDisplayName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.springframework.modulith.observability;
|
||||
|
||||
import io.micrometer.tracing.exporter.FinishedSpan;
|
||||
import io.micrometer.tracing.exporter.SpanFilter;
|
||||
|
||||
/**
|
||||
* {@link SpanFilter} that sets a local service name according
|
||||
* to the current module's name.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.3
|
||||
*/
|
||||
public class LocalServiceRenamingSpanFilter implements SpanFilter {
|
||||
|
||||
@Override
|
||||
public FinishedSpan map(FinishedSpan span) {
|
||||
String moduleKey = span.getTags().get(ModulithObservations.LowKeys.MODULE_KEY.asString());
|
||||
if (moduleKey != null) {
|
||||
// Wait for tracing 1.5.0
|
||||
span.setLocalServiceName(moduleKey);
|
||||
}
|
||||
return span;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package org.springframework.modulith.observability;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.micrometer.common.KeyValue;
|
||||
import io.micrometer.observation.Observation;
|
||||
@@ -26,32 +27,34 @@ import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
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<String, ModuleEntryInterceptor> CACHE = new HashMap<>();
|
||||
private static final String MODULE_KEY = ModuleTracingBeanPostProcessor.MODULE_BAGGAGE_KEY;
|
||||
private static Map<ApplicationModuleIdentifier, ModuleEntryInterceptor> CACHE = new HashMap<>();
|
||||
|
||||
private static final ModulithObservationConvention DEFAULT = new DefaultModulithObservationConvention();
|
||||
|
||||
private final ObservedModule module;
|
||||
private final ObservationRegistry observationRegistry;
|
||||
@Nullable private final ModulithObservationConvention customModulithObservationConvention;
|
||||
@Nullable
|
||||
private final ModulithObservationConvention customModulithObservationConvention;
|
||||
private final Environment environment;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ModuleEntryInterceptor} for the given {@link ObservedModule} and {@link ObservationRegistry}.
|
||||
*
|
||||
* @param module must not be {@literal null}.
|
||||
* @param observationRegistry must not be {@literal null}.
|
||||
* @param environment must not be {@literal null}.
|
||||
*/
|
||||
private ModuleEntryInterceptor(ObservedModule module, ObservationRegistry observationRegistry) {
|
||||
this(module, observationRegistry, null);
|
||||
private ModuleEntryInterceptor(ObservedModule module, ObservationRegistry observationRegistry, Environment environment) {
|
||||
this(module, observationRegistry, null, environment);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,26 +64,29 @@ class ModuleEntryInterceptor implements MethodInterceptor {
|
||||
* @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) {
|
||||
ModulithObservationConvention custom, Environment environment) {
|
||||
|
||||
Assert.notNull(module, "ObservedModule must not be null!");
|
||||
Assert.notNull(observationRegistry, "Tracer must not be null!");
|
||||
|
||||
this.module = module; this.observationRegistry = observationRegistry;
|
||||
this.customModulithObservationConvention = custom;
|
||||
}
|
||||
|
||||
public static ModuleEntryInterceptor of(ObservedModule module, ObservationRegistry observationRegistry) {
|
||||
return of(module, observationRegistry, null);
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
public static ModuleEntryInterceptor of(ObservedModule module, ObservationRegistry observationRegistry,
|
||||
ModulithObservationConvention custom) {
|
||||
Environment environment) {
|
||||
return of(module, observationRegistry, null, environment);
|
||||
}
|
||||
|
||||
return CACHE.computeIfAbsent(module.getName(), __ -> {
|
||||
return new ModuleEntryInterceptor(module, observationRegistry, custom);
|
||||
public static ModuleEntryInterceptor of(ObservedModule module, ObservationRegistry observationRegistry,
|
||||
ModulithObservationConvention custom, Environment environment) {
|
||||
|
||||
return CACHE.computeIfAbsent(module.getIdentifier(), __ -> {
|
||||
return new ModuleEntryInterceptor(module, observationRegistry, custom, environment);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -88,18 +94,19 @@ class ModuleEntryInterceptor implements MethodInterceptor {
|
||||
* (non-Javadoc)
|
||||
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
|
||||
*/
|
||||
@Override public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
|
||||
var moduleName = module.getName();
|
||||
var moduleIdentifier = module.getIdentifier();
|
||||
var currentObservation = observationRegistry.getCurrentObservation();
|
||||
String currentModule = null;
|
||||
|
||||
if (currentObservation != null) {
|
||||
KeyValue moduleKey = currentObservation.getContextView().getLowCardinalityKeyValue(MODULE_KEY);
|
||||
KeyValue moduleKey = currentObservation.getContextView().getLowCardinalityKeyValue(LowKeys.MODULE_KEY.asString());
|
||||
currentModule = moduleKey != null ? moduleKey.getValue() : null;
|
||||
}
|
||||
|
||||
if (currentObservation != null && moduleName.equals(currentModule)) {
|
||||
if (currentObservation != null && Objects.equals(moduleIdentifier.toString(), currentModule)) {
|
||||
// Same module
|
||||
return invocation.proceed();
|
||||
}
|
||||
@@ -108,18 +115,18 @@ class ModuleEntryInterceptor implements MethodInterceptor {
|
||||
|
||||
LOGGER.trace("Entering {} via {}.", module.getDisplayName(), invokedMethod);
|
||||
|
||||
boolean isEventListener = module.isEventListenerInvocation(invocation);
|
||||
|
||||
// TODO: Good name for metrics
|
||||
ModulithContext modulithContext = new ModulithContext(module, invocation);
|
||||
ModulithContext modulithContext = new ModulithContext(module, invocation, environment);
|
||||
var observation = Observation.createNotStarted(customModulithObservationConvention, DEFAULT,
|
||||
() -> modulithContext, observationRegistry); if (isEventListener) {
|
||||
observation.lowCardinalityKeyValue(LowKeys.INVOCATION_TYPE.withValue("event-listener"));
|
||||
} try (Observation.Scope scope = observation.openScope()) {
|
||||
Object proceed = invocation.proceed(); observation.event(ModulithObservations.Events.EVENT_PUBLICATION_SUCCESS);
|
||||
() -> 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;
|
||||
observation.error(ex);
|
||||
observation.event(ModulithObservations.Events.EVENT_PUBLICATION_FAILURE);
|
||||
throw ex;
|
||||
} finally {
|
||||
LOGGER.trace("Leaving {}", module.getDisplayName()); observation.stop();
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.modulith.runtime.ApplicationModulesRuntime;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -43,7 +44,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
public class ModuleTracingBeanPostProcessor extends ModuleTracingSupport implements BeanPostProcessor {
|
||||
public class ModuleObservabilityBeanPostProcessor extends ModuleObservabilitySupport implements BeanPostProcessor {
|
||||
|
||||
public static final String MODULE_BAGGAGE_KEY = "org.springframework.modulith.module";
|
||||
|
||||
@@ -51,24 +52,26 @@ public class ModuleTracingBeanPostProcessor extends ModuleTracingSupport impleme
|
||||
private final Supplier<ObservationRegistry> observationRegistry;
|
||||
private final Map<String, Advisor> advisors;
|
||||
private final ConfigurableListableBeanFactory factory;
|
||||
private final Environment environment;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ModuleTracingBeanPostProcessor} for the given {@link ApplicationModulesRuntime} and
|
||||
* Creates a new {@link ModuleObservabilityBeanPostProcessor} for the given {@link ApplicationModulesRuntime} and
|
||||
* {@link Tracer}.
|
||||
*
|
||||
* @param runtime must not be {@literal null}.
|
||||
* @param observationRegistry must not be {@literal null}.
|
||||
*/
|
||||
public ModuleTracingBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier<ObservationRegistry> observationRegistry,
|
||||
ConfigurableListableBeanFactory factory) {
|
||||
public ModuleObservabilityBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier<ObservationRegistry> observationRegistry,
|
||||
ConfigurableListableBeanFactory factory, Environment environment) {
|
||||
|
||||
Assert.notNull(runtime, "ApplicationModulesRuntime must not be null!");
|
||||
Assert.notNull(observationRegistry, "Tracer must not be null!");
|
||||
Assert.notNull(observationRegistry, "ObservationRegistry must not be null!");
|
||||
|
||||
this.runtime = runtime;
|
||||
this.observationRegistry = observationRegistry;
|
||||
this.advisors = new HashMap<>();
|
||||
this.factory = factory;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -120,8 +123,8 @@ 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, observationRegistry.get()));
|
||||
return advisors.computeIfAbsent(module.getIdentifier().toString(), __ -> {
|
||||
return new ApplicationModuleObservingAdvisor(type, ModuleEntryInterceptor.of(module, observationRegistry.get(), environment));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor;
|
||||
/**
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
class ModuleTracingSupport implements BeanClassLoaderAware {
|
||||
class ModuleObservabilitySupport implements BeanClassLoaderAware {
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
@@ -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.3
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ 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.
|
||||
*
|
||||
@@ -15,9 +17,12 @@ public class ModulithContext extends Observation.Context {
|
||||
|
||||
private final MethodInvocation invocation;
|
||||
|
||||
public ModulithContext(ObservedModule module, 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() {
|
||||
@@ -27,4 +32,8 @@ public class ModulithContext extends Observation.Context {
|
||||
public MethodInvocation getInvocation() {
|
||||
return invocation;
|
||||
}
|
||||
|
||||
public String getApplicationName() {
|
||||
return applicationName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,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;
|
||||
@@ -38,25 +39,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<ObservationRegistry> observationRegistry;
|
||||
private final Environment environment;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpringDataRestModuleTracingBeanPostProcessor} for the given {@link ApplicationModulesRuntime}
|
||||
* Creates a new {@link SpringDataRestModuleObservabilityBeanPostProcessor} for the given {@link ApplicationModulesRuntime}
|
||||
* and {@link Tracer}.
|
||||
*
|
||||
* @param runtime must not be {@literal null}.
|
||||
* @param observationRegistry must not be {@literal null}.
|
||||
* @param environment must not be {@literal null}.
|
||||
*/
|
||||
public SpringDataRestModuleTracingBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier<ObservationRegistry> observationRegistry) {
|
||||
public SpringDataRestModuleObservabilityBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier<ObservationRegistry> observationRegistry, Environment environment) {
|
||||
|
||||
Assert.notNull(runtime, "ApplicationModulesRuntime must not be null!");
|
||||
Assert.notNull(observationRegistry, "ObservationRegistry must not be null!");
|
||||
|
||||
this.runtime = runtime;
|
||||
this.observationRegistry = observationRegistry;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -72,7 +76,7 @@ public class SpringDataRestModuleTracingBeanPostProcessor extends ModuleTracingS
|
||||
return bean;
|
||||
}
|
||||
|
||||
Advice interceptor = new DataRestControllerInterceptor(runtime, observationRegistry);
|
||||
Advice interceptor = new DataRestControllerInterceptor(runtime, observationRegistry, environment);
|
||||
Advisor advisor = new DefaultPointcutAdvisor(interceptor);
|
||||
|
||||
return addAdvisor(bean, advisor, it -> it.setProxyTargetClass(true));
|
||||
@@ -82,20 +86,25 @@ public class SpringDataRestModuleTracingBeanPostProcessor extends ModuleTracingS
|
||||
|
||||
private final Supplier<ApplicationModules> modules;
|
||||
private final Supplier<ObservationRegistry> 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 modules must not be {@literal null}.
|
||||
* @param observationRegistry must not be {@literal null}.
|
||||
* @param environment must not be {@literal null}.
|
||||
*/
|
||||
private DataRestControllerInterceptor(Supplier<ApplicationModules> modules, Supplier<ObservationRegistry> observationRegistry) {
|
||||
private DataRestControllerInterceptor(Supplier<ApplicationModules> modules, Supplier<ObservationRegistry> observationRegistry,
|
||||
Environment environment) {
|
||||
|
||||
Assert.notNull(modules, "ApplicationModules must not be null!");
|
||||
Assert.notNull(observationRegistry, "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.observationRegistry = observationRegistry;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -113,7 +122,7 @@ public class SpringDataRestModuleTracingBeanPostProcessor extends ModuleTracingS
|
||||
|
||||
var observed = new DefaultObservedModule(module);
|
||||
|
||||
return ModuleEntryInterceptor.of(observed, observationRegistry.get()).invoke(invocation);
|
||||
return ModuleEntryInterceptor.of(observed, observationRegistry.get(), environment).invoke(invocation);
|
||||
}
|
||||
|
||||
private ApplicationModule getModuleFrom(Object[] arguments) {
|
||||
@@ -15,10 +15,15 @@
|
||||
*/
|
||||
package org.springframework.modulith.observability.autoconfigure;
|
||||
|
||||
import io.micrometer.common.KeyValue;
|
||||
import io.micrometer.observation.ObservationFilter;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.tracing.Tracer;
|
||||
import io.micrometer.tracing.exporter.SpanFilter;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;
|
||||
import org.springframework.boot.autoconfigure.thread.Threading;
|
||||
@@ -26,9 +31,12 @@ 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.LocalServiceRenamingSpanFilter;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -39,9 +47,9 @@ import org.springframework.modulith.runtime.ApplicationModulesRuntime;
|
||||
class ModuleObservabilityAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
static ModuleTracingBeanPostProcessor moduleTracingBeanPostProcessor(ApplicationModulesRuntime runtime,
|
||||
ObjectProvider<ObservationRegistry> observationRegistry, ConfigurableListableBeanFactory factory) {
|
||||
return new ModuleTracingBeanPostProcessor(runtime, observationRegistry::getObject, factory);
|
||||
static ModuleObservabilityBeanPostProcessor moduleTracingBeanPostProcessor(ApplicationModulesRuntime runtime,
|
||||
ObjectProvider<ObservationRegistry> observationRegistry, ConfigurableListableBeanFactory factory, Environment environment) {
|
||||
return new ModuleObservabilityBeanPostProcessor(runtime, observationRegistry::getObject, factory, environment);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -62,4 +70,20 @@ class ModuleObservabilityAutoConfiguration {
|
||||
ThreadPoolTaskExecutorCustomizer threadPoolTaskExecutorCustomizer() {
|
||||
return executor -> executor.setTaskDecorator(new ContextPropagatingTaskDecorator());
|
||||
}
|
||||
|
||||
@Bean
|
||||
ObservationFilter modulePassingObservationFilter() {
|
||||
return new ModulePassingObservationFilter();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(Tracer.class)
|
||||
static class MicrometerTracingConfiguration {
|
||||
|
||||
|
||||
@Bean
|
||||
SpanFilter localSpanFilter() {
|
||||
return new LocalServiceRenamingSpanFilter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
package org.springframework.modulith.observability.autoconfigure;
|
||||
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import io.micrometer.tracing.Tracer;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -34,9 +34,9 @@ import org.springframework.modulith.runtime.ApplicationModulesRuntime;
|
||||
class SpringDataRestModuleObservabilityAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
static SpringDataRestModuleTracingBeanPostProcessor springDataRestModuleTracingBeanPostProcessor(
|
||||
ApplicationModulesRuntime runtime, ObjectProvider<ObservationRegistry> observationRegistry) {
|
||||
static SpringDataRestModuleObservabilityBeanPostProcessor springDataRestModuleTracingBeanPostProcessor(
|
||||
ApplicationModulesRuntime runtime, ObjectProvider<ObservationRegistry> observationRegistry, Environment environment) {
|
||||
|
||||
return new SpringDataRestModuleTracingBeanPostProcessor(runtime, () -> observationRegistry.getObject());
|
||||
return new SpringDataRestModuleObservabilityBeanPostProcessor(runtime, () -> observationRegistry.getObject(), environment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +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.observation.ObservationRegistry;
|
||||
import io.micrometer.tracing.Tracer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.aop.Advisor;
|
||||
@@ -30,14 +28,14 @@ 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
|
||||
*/
|
||||
@@ -64,14 +62,13 @@ class ModuleTracingBeanPostProcessorIntegrationTests {
|
||||
@Configuration
|
||||
static class ModuleTracingConfiguration {
|
||||
|
||||
@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, () -> ObservationRegistry.NOOP, context.getBeanFactory());
|
||||
return new ModuleObservabilityBeanPostProcessor(modulesRuntime, () -> ObservationRegistry.NOOP, context.getBeanFactory(), context.getEnvironment());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,10 +24,11 @@ import example.sample.SampleProperties;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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
|
||||
*/
|
||||
@@ -43,7 +44,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");
|
||||
|
||||
Reference in New Issue
Block a user