From 52dcb593c6c98e297fef742f9a06608cbc6e7c92 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 14 Nov 2024 16:52:07 +0100 Subject: [PATCH] WIP. Current code works with tracing 1.5.0 - leaving this for future reference --- pom.xml | 10 +++ .../DefaultModulithObservationConvention.java | 65 +++++++++++-------- .../LocalServiceRenamingSpanFilter.java | 24 +++++++ .../observability/ModuleEntryInterceptor.java | 57 +++++++++------- ...ModuleObservabilityBeanPostProcessor.java} | 17 +++-- ...t.java => ModuleObservabilitySupport.java} | 2 +- .../ModulePassingObservationFilter.java | 45 +++++++++++++ .../observability/ModulithContext.java | 11 +++- ...ModuleObservabilityBeanPostProcessor.java} | 25 ++++--- .../ModuleObservabilityAutoConfiguration.java | 32 +++++++-- ...tModuleObservabilityAutoConfiguration.java | 10 +-- ...cingBeanPostProcessorIntegrationTests.java | 11 ++-- ...duleTracingBeanPostProcessorUnitTests.java | 5 +- 13 files changed, 228 insertions(+), 86 deletions(-) create mode 100644 spring-modulith-observability/src/main/java/org/springframework/modulith/observability/LocalServiceRenamingSpanFilter.java rename spring-modulith-observability/src/main/java/org/springframework/modulith/observability/{ModuleTracingBeanPostProcessor.java => ModuleObservabilityBeanPostProcessor.java} (86%) rename spring-modulith-observability/src/main/java/org/springframework/modulith/observability/{ModuleTracingSupport.java => ModuleObservabilitySupport.java} (96%) create mode 100644 spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModulePassingObservationFilter.java rename spring-modulith-observability/src/main/java/org/springframework/modulith/observability/{SpringDataRestModuleTracingBeanPostProcessor.java => SpringDataRestModuleObservabilityBeanPostProcessor.java} (78%) diff --git a/pom.xml b/pom.xml index 109eb6f3..d7d670bd 100644 --- a/pom.xml +++ b/pom.xml @@ -47,6 +47,8 @@ 6.2.0-RC3 3.1.1 1.17.6 + + 1.5.0-SNAPSHOT @@ -96,6 +98,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/src/main/java/org/springframework/modulith/observability/DefaultModulithObservationConvention.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/DefaultModulithObservationConvention.java index 1f1cb5e5..e92e7df0 100644 --- 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 @@ -3,35 +3,48 @@ 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 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) { - // TODO: Change this to application name - return "[" + context.getModule().getDisplayName() + "] " + context.getModule() - .getDisplayName(); - } + @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/LocalServiceRenamingSpanFilter.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/LocalServiceRenamingSpanFilter.java new file mode 100644 index 00000000..919536e6 --- /dev/null +++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/LocalServiceRenamingSpanFilter.java @@ -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; + } +} 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 20c67b49..d93086c6 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 @@ -17,6 +17,7 @@ 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.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 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 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 @@ private ModuleEntryInterceptor(ObservedModule module, ObservationRegistry observ * @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; + this.environment = environment; } - public static ModuleEntryInterceptor of(ObservedModule module, ObservationRegistry observationRegistry) { - return of(module, observationRegistry, null); + 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) { + ModulithObservationConvention custom, Environment environment) { - return CACHE.computeIfAbsent(module.getName(), __ -> { - return new ModuleEntryInterceptor(module, observationRegistry, custom); + return CACHE.computeIfAbsent(module.getIdentifier(), __ -> { + return new ModuleEntryInterceptor(module, observationRegistry, custom, environment); }); } @@ -88,18 +94,19 @@ public static ModuleEntryInterceptor of(ObservedModule module, ObservationRegist * (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 @@ public static ModuleEntryInterceptor of(ObservedModule module, ObservationRegist 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(); } diff --git a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleTracingBeanPostProcessor.java b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleObservabilityBeanPostProcessor.java similarity index 86% rename from spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleTracingBeanPostProcessor.java rename to spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleObservabilityBeanPostProcessor.java index 5aedc988..88f50677 100644 --- a/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleTracingBeanPostProcessor.java +++ b/spring-modulith-observability/src/main/java/org/springframework/modulith/observability/ModuleObservabilityBeanPostProcessor.java @@ -34,6 +34,7 @@ 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 @@ * * @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; private final Map 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, - ConfigurableListableBeanFactory factory) { + public ModuleObservabilityBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier 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 @@ private boolean isInfrastructureBean(String beanName) { 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)); }); } 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 96% 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 c951d51e..5a68d7ea 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 @@ -26,7 +26,7 @@ /** * @author Oliver Drotbohm */ -class ModuleTracingSupport implements BeanClassLoaderAware { +class ModuleObservabilitySupport implements BeanClassLoaderAware { private ClassLoader classLoader; 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..18122f48 --- /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.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; + } +} \ 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 index d8cdbf45..ddd33246 100644 --- 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 @@ -3,6 +3,8 @@ 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 ObservedModule getModule() { public MethodInvocation getInvocation() { return invocation; } + + public String getApplicationName() { + return applicationName; + } } 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 78% 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 b08a9f93..da7623dd 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 @@ -28,6 +28,7 @@ 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 @@ /** * @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; + 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) { + public SpringDataRestModuleObservabilityBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier 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 Object postProcessAfterInitialization(Object bean, String beanName) throw 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 @@ private static class DataRestControllerInterceptor implements MethodInterceptor private final Supplier modules; 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 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 observationRegistry) { + private DataRestControllerInterceptor(Supplier modules, Supplier 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 Object invoke(MethodInvocation invocation) throws Throwable { 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) { 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 eeeba7fa..bf453db6 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,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.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 @@ class ModuleObservabilityAutoConfiguration { @Bean - static ModuleTracingBeanPostProcessor moduleTracingBeanPostProcessor(ApplicationModulesRuntime runtime, - ObjectProvider observationRegistry, ConfigurableListableBeanFactory factory) { - return new ModuleTracingBeanPostProcessor(runtime, observationRegistry::getObject, factory); + static ModuleObservabilityBeanPostProcessor moduleTracingBeanPostProcessor(ApplicationModulesRuntime runtime, + ObjectProvider observationRegistry, ConfigurableListableBeanFactory factory, Environment environment) { + return new ModuleObservabilityBeanPostProcessor(runtime, observationRegistry::getObject, factory, environment); } @Bean @@ -62,4 +70,20 @@ SimpleAsyncTaskExecutorCustomizer simpleAsyncTaskExecutorCustomizer() { 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(); + } + } } 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 7b00cad7..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 @@ -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 @@ class SpringDataRestModuleObservabilityAutoConfiguration { @Bean - static SpringDataRestModuleTracingBeanPostProcessor springDataRestModuleTracingBeanPostProcessor( - ApplicationModulesRuntime runtime, ObjectProvider observationRegistry) { + static SpringDataRestModuleObservabilityBeanPostProcessor springDataRestModuleTracingBeanPostProcessor( + ApplicationModulesRuntime runtime, ObjectProvider observationRegistry, Environment environment) { - return new SpringDataRestModuleTracingBeanPostProcessor(runtime, () -> observationRegistry.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/ModuleTracingBeanPostProcessorIntegrationTests.java index 57202e12..e57dda43 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/ModuleTracingBeanPostProcessorIntegrationTests.java @@ -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.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 @@ void decoratesExposedComponentsWithTracingInterceptor() { @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()); } } 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/ModuleTracingBeanPostProcessorUnitTests.java index 42fe2745..e8da23b3 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/ModuleTracingBeanPostProcessorUnitTests.java @@ -24,10 +24,11 @@ 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 @@ void doesNotProxyConfiguationProperties() { 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");