GH-928 - Polishing.
License headers, formatting, null checks.
This commit is contained in:
@@ -1,7 +1,20 @@
|
||||
/*
|
||||
* Copyright 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 java.lang.reflect.Method;
|
||||
|
||||
import io.micrometer.common.KeyValues;
|
||||
|
||||
import org.springframework.modulith.observability.ModulithObservations.HighKeys;
|
||||
@@ -11,40 +24,62 @@ import org.springframework.modulith.observability.ModulithObservations.LowKeys;
|
||||
* Default implementation of {@link ModulithObservationConvention}.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Oliver Drotbohm
|
||||
* @since 1.4
|
||||
*/
|
||||
public class DefaultModulithObservationConvention implements ModulithObservationConvention {
|
||||
class DefaultModulithObservationConvention implements ModulithObservationConvention {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.ObservationConvention#getLowCardinalityKeyValues(io.micrometer.observation.Observation.Context)
|
||||
*/
|
||||
@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;
|
||||
|
||||
var keyValues = KeyValues.of(LowKeys.MODULE_KEY.withValue(context.getModule().getIdentifier().toString()));
|
||||
|
||||
return isEventListener(context)
|
||||
? keyValues.and(LowKeys.INVOCATION_TYPE.withValue("event-listener"))
|
||||
: keyValues;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.ObservationConvention#getHighCardinalityKeyValues(io.micrometer.observation.Observation.Context)
|
||||
*/
|
||||
@Override
|
||||
public KeyValues getHighCardinalityKeyValues(ModulithContext context) {
|
||||
|
||||
var method = context.getInvocation().getMethod();
|
||||
|
||||
return KeyValues.of(HighKeys.MODULE_METHOD.withValue(method.getName()));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.ObservationConvention#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "module.requests";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.ObservationConvention#getContextualName(io.micrometer.observation.Observation.Context)
|
||||
*/
|
||||
@Override
|
||||
public String getContextualName(ModulithContext context) {
|
||||
return "[" + context.getApplicationName() + "] " + context.getModule().getDisplayName();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ 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;
|
||||
@@ -163,7 +162,6 @@ class DefaultObservedModule implements ObservedModule {
|
||||
var targetClass = advised.getTargetClass();
|
||||
|
||||
if (module.contains(targetClass)) {
|
||||
|
||||
return AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package org.springframework.modulith.observability;
|
||||
|
||||
import io.micrometer.common.KeyValue;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.Observation.Scope;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -33,16 +33,22 @@ import org.springframework.modulith.core.ApplicationModuleIdentifier;
|
||||
import org.springframework.modulith.observability.ModulithObservations.LowKeys;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link MethodInterceptor} to create {@link Observation}s.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
class ModuleEntryInterceptor implements MethodInterceptor {
|
||||
|
||||
private static Logger LOGGER = LoggerFactory.getLogger(ModuleEntryInterceptor.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ModuleEntryInterceptor.class);
|
||||
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;
|
||||
private final @Nullable ModulithObservationConvention customModulithObservationConvention;
|
||||
private final Environment environment;
|
||||
|
||||
/**
|
||||
@@ -103,7 +109,8 @@ class ModuleEntryInterceptor implements MethodInterceptor {
|
||||
String currentModule = null;
|
||||
|
||||
if (currentObservation != null) {
|
||||
KeyValue moduleKey = currentObservation.getContextView().getLowCardinalityKeyValue(LowKeys.MODULE_KEY.asString());
|
||||
|
||||
var moduleKey = currentObservation.getContextView().getLowCardinalityKeyValue(LowKeys.MODULE_KEY.asString());
|
||||
currentModule = moduleKey != null ? moduleKey.getValue() : null;
|
||||
}
|
||||
|
||||
@@ -116,18 +123,26 @@ class ModuleEntryInterceptor implements MethodInterceptor {
|
||||
|
||||
LOGGER.trace("Entering {} via {}.", module.getDisplayName(), invokedMethod);
|
||||
|
||||
ModulithContext modulithContext = new ModulithContext(module, invocation, environment);
|
||||
var 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();
|
||||
|
||||
try (Scope scope = observation.start().openScope()) {
|
||||
|
||||
var 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());
|
||||
observation.stop();
|
||||
}
|
||||
|
||||
@@ -39,13 +39,15 @@ public class ModuleEventListener implements ApplicationListener<ApplicationEvent
|
||||
private final Supplier<MeterRegistry> meterRegistry;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ModuleEventListener} for the given {@link ApplicationModulesRuntime} and {@link ObservationRegistry} and {@link MeterRegistry}.
|
||||
* Creates a new {@link ModuleEventListener} for the given {@link ApplicationModulesRuntime} and
|
||||
* {@link ObservationRegistry} and {@link MeterRegistry}.
|
||||
*
|
||||
* @param runtime must not be {@literal null}.
|
||||
* @param observationRegistrySupplier must not be {@literal null}.
|
||||
* @param meterRegistrySupplier must not be {@literal null}.
|
||||
*/
|
||||
public ModuleEventListener(ApplicationModulesRuntime runtime, Supplier<ObservationRegistry> observationRegistrySupplier,
|
||||
Supplier<MeterRegistry> meterRegistrySupplier) {
|
||||
public ModuleEventListener(ApplicationModulesRuntime runtime,
|
||||
Supplier<ObservationRegistry> observationRegistrySupplier, Supplier<MeterRegistry> meterRegistrySupplier) {
|
||||
|
||||
Assert.notNull(runtime, "ApplicationModulesRuntime must not be null!");
|
||||
Assert.notNull(observationRegistrySupplier, "ObservationRegistry must not be null!");
|
||||
@@ -82,8 +84,10 @@ public class ModuleEventListener implements ApplicationListener<ApplicationEvent
|
||||
return;
|
||||
}
|
||||
|
||||
MeterRegistry registry = meterRegistry.get();
|
||||
var registry = meterRegistry.get();
|
||||
|
||||
if (registry != null) {
|
||||
|
||||
Counter.builder(ModulithMetrics.EVENTS.getName()) //
|
||||
.tags(ModulithMetrics.LowKeys.EVENT_TYPE.name().toLowerCase(), event.getClass().getSimpleName()) //
|
||||
.tags(ModulithMetrics.LowKeys.MODULE_NAME.name().toLowerCase(), moduleByType.getDisplayName()) //
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2022-2024 the original author or authors.
|
||||
* Copyright 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.
|
||||
@@ -16,30 +16,46 @@
|
||||
package org.springframework.modulith.observability;
|
||||
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.Observation.ContextView;
|
||||
import io.micrometer.observation.ObservationFilter;
|
||||
|
||||
/**
|
||||
* Ensures that {@link ModulithObservations.LowKeys#MODULE_KEY} gets propagated from parent
|
||||
* to child.
|
||||
*
|
||||
* Ensures that {@link ModulithObservations.LowKeys#MODULE_KEY} gets propagated from parent to child.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Oliver Drotbohm
|
||||
* @since 1.4
|
||||
*/
|
||||
public class ModulePassingObservationFilter implements ObservationFilter {
|
||||
|
||||
@Override
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.ObservationFilter#map(io.micrometer.observation.Observation.Context)
|
||||
*/
|
||||
@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()));
|
||||
|
||||
var moduleKey = ModulithObservations.LowKeys.MODULE_KEY;
|
||||
|
||||
return context.addLowCardinalityKeyValue(moduleKey.withValue(context.getParentObservation().getContextView()
|
||||
.getLowCardinalityKeyValue(moduleKey.asString()).getValue()));
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
private static boolean isModuleKeyValueAbsentInCurrent(Observation.ContextView context) {
|
||||
private static boolean isModuleKeyValueAbsentInCurrent(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;
|
||||
private static boolean isModuleKeyValuePresentInParent(ContextView context) {
|
||||
|
||||
var parentObservation = context.getParentObservation();
|
||||
|
||||
return parentObservation != null
|
||||
&& parentObservation.getContextView()
|
||||
.getLowCardinalityKeyValue(ModulithObservations.LowKeys.MODULE_KEY.asString()) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,67 @@
|
||||
/*
|
||||
* Copyright 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 org.aopalliance.intercept.MethodInvocation;
|
||||
import io.micrometer.observation.Observation.Context;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link Observation.Context} for Modulithic applications.
|
||||
* A {@link Context} for Modulithic applications.
|
||||
*
|
||||
* @author Marcin Grzejsczak
|
||||
* @author Oliver Drotbohm
|
||||
* @since 1.4
|
||||
*/
|
||||
public class ModulithContext extends Observation.Context {
|
||||
public class ModulithContext extends Context {
|
||||
|
||||
private final ObservedModule module;
|
||||
private final ObservedModule module;
|
||||
private final MethodInvocation invocation;
|
||||
private final String applicationName;
|
||||
|
||||
private final MethodInvocation invocation;
|
||||
/**
|
||||
* Creates a new {@link ModulithContext} for the given {@link ObservedModule}, {@link MethodInvocation} and
|
||||
* {@link Environment}.
|
||||
*
|
||||
* @param module must not be {@literal null}.
|
||||
* @param invocation must not be {@literal null}.
|
||||
* @param environment must not be {@literal null}.
|
||||
*/
|
||||
public ModulithContext(ObservedModule module, MethodInvocation invocation, Environment environment) {
|
||||
|
||||
private final String applicationName;
|
||||
Assert.notNull(module, "ObservedModule must not be null!");
|
||||
Assert.notNull(invocation, "MethodInvocation must not be null!");
|
||||
Assert.notNull(environment, "Environment must not be null!");
|
||||
|
||||
public ModulithContext(ObservedModule module, MethodInvocation invocation, Environment environment) {
|
||||
this.module = module;
|
||||
this.invocation = invocation;
|
||||
this.applicationName = environment.getProperty("spring.application.name");
|
||||
}
|
||||
this.module = module;
|
||||
this.invocation = invocation;
|
||||
this.applicationName = environment.getProperty("spring.application.name");
|
||||
}
|
||||
|
||||
public ObservedModule getModule() {
|
||||
return module;
|
||||
}
|
||||
public ObservedModule getModule() {
|
||||
return module;
|
||||
}
|
||||
|
||||
public MethodInvocation getInvocation() {
|
||||
return invocation;
|
||||
}
|
||||
public MethodInvocation getInvocation() {
|
||||
return invocation;
|
||||
}
|
||||
|
||||
public String getApplicationName() {
|
||||
return applicationName;
|
||||
}
|
||||
public String getApplicationName() {
|
||||
return applicationName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,58 @@
|
||||
/*
|
||||
* Copyright 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.common.docs.KeyName;
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.docs.MeterDocumentation;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Oliver Drotbohm
|
||||
* @since 1.4
|
||||
*/
|
||||
enum ModulithMetrics implements MeterDocumentation {
|
||||
|
||||
/**
|
||||
* Counter for the events.
|
||||
*/
|
||||
EVENTS {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.core.instrument.docs.MeterDocumentation#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "modulith.events.processed";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.core.instrument.docs.MeterDocumentation#getType()
|
||||
*/
|
||||
@Override
|
||||
public Meter.Type getType() {
|
||||
return Meter.Type.COUNTER;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.core.instrument.docs.MeterDocumentation#getKeyNames()
|
||||
*/
|
||||
@Override
|
||||
public KeyName[] getKeyNames() {
|
||||
return LowKeys.values();
|
||||
@@ -31,6 +64,11 @@ enum ModulithMetrics implements MeterDocumentation {
|
||||
* Type of the emitted event.
|
||||
*/
|
||||
EVENT_TYPE {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.common.docs.KeyName#asString()
|
||||
*/
|
||||
@Override
|
||||
public String asString() {
|
||||
return "event.type";
|
||||
@@ -41,6 +79,11 @@ enum ModulithMetrics implements MeterDocumentation {
|
||||
* Name of the module.
|
||||
*/
|
||||
MODULE_NAME {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.common.docs.KeyName#asString()
|
||||
*/
|
||||
@Override
|
||||
public String asString() {
|
||||
return "module.name";
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 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.Context;
|
||||
@@ -11,8 +26,12 @@ import io.micrometer.observation.ObservationConvention;
|
||||
*/
|
||||
public interface ModulithObservationConvention extends ObservationConvention<ModulithContext> {
|
||||
|
||||
@Override
|
||||
default boolean supportsContext(Context context) {
|
||||
return context instanceof ModulithContext;
|
||||
}
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.ObservationConvention#supportsContext(io.micrometer.observation.Observation.Context)
|
||||
*/
|
||||
@Override
|
||||
default boolean supportsContext(Context context) {
|
||||
return context instanceof ModulithContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
/*
|
||||
* Copyright 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.common.docs.KeyName;
|
||||
import io.micrometer.observation.Observation;
|
||||
import io.micrometer.observation.Observation.Context;
|
||||
import io.micrometer.observation.Observation.Event;
|
||||
import io.micrometer.observation.ObservationConvention;
|
||||
import io.micrometer.observation.docs.ObservationDocumentation;
|
||||
|
||||
@@ -12,19 +28,40 @@ enum ModulithObservations implements ObservationDocumentation {
|
||||
* Observation related to entering a module.
|
||||
*/
|
||||
MODULE_ENTRY {
|
||||
@Override public Class<? extends ObservationConvention<? extends Context>> getDefaultConvention() {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.docs.ObservationDocumentation#getDefaultConvention()
|
||||
*/
|
||||
@Override
|
||||
public Class<? extends ObservationConvention<? extends Context>> getDefaultConvention() {
|
||||
return DefaultModulithObservationConvention.class;
|
||||
}
|
||||
|
||||
@Override public KeyName[] getLowCardinalityKeyNames() {
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.docs.ObservationDocumentation#getLowCardinalityKeyNames()
|
||||
*/
|
||||
@Override
|
||||
public KeyName[] getLowCardinalityKeyNames() {
|
||||
return LowKeys.values();
|
||||
}
|
||||
|
||||
@Override public KeyName[] getHighCardinalityKeyNames() {
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.docs.ObservationDocumentation#getHighCardinalityKeyNames()
|
||||
*/
|
||||
@Override
|
||||
public KeyName[] getHighCardinalityKeyNames() {
|
||||
return HighKeys.values();
|
||||
}
|
||||
|
||||
@Override public Observation.Event[] getEvents() {
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.docs.ObservationDocumentation#getEvents()
|
||||
*/
|
||||
@Override
|
||||
public Observation.Event[] getEvents() {
|
||||
return Events.values();
|
||||
}
|
||||
};
|
||||
@@ -35,7 +72,13 @@ enum ModulithObservations implements ObservationDocumentation {
|
||||
* Name of the module.
|
||||
*/
|
||||
MODULE_KEY {
|
||||
@Override public String asString() {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.common.docs.KeyName#asString()
|
||||
*/
|
||||
@Override
|
||||
public String asString() {
|
||||
return "module.key";
|
||||
}
|
||||
},
|
||||
@@ -44,7 +87,13 @@ enum ModulithObservations implements ObservationDocumentation {
|
||||
* Type of invocation (e.g. event listener).
|
||||
*/
|
||||
INVOCATION_TYPE {
|
||||
@Override public String asString() {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.common.docs.KeyName#asString()
|
||||
*/
|
||||
@Override
|
||||
public String asString() {
|
||||
return "module.invocation-type";
|
||||
}
|
||||
}
|
||||
@@ -55,23 +104,35 @@ enum ModulithObservations implements ObservationDocumentation {
|
||||
* Method executed on a module.
|
||||
*/
|
||||
MODULE_METHOD {
|
||||
@Override public String asString() {
|
||||
@Override
|
||||
public String asString() {
|
||||
return "module.method";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Events implements Observation.Event {
|
||||
enum Events implements Event {
|
||||
|
||||
/**
|
||||
* Published when an event is sent successfully.
|
||||
*/
|
||||
EVENT_PUBLICATION_SUCCESS {
|
||||
@Override public String getName() {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.Observation.Event#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "event.publication.success";
|
||||
}
|
||||
|
||||
@Override public String getContextualName() {
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.Observation.Event#getContextualName()
|
||||
*/
|
||||
@Override
|
||||
public String getContextualName() {
|
||||
return getName();
|
||||
}
|
||||
},
|
||||
@@ -80,11 +141,22 @@ enum ModulithObservations implements ObservationDocumentation {
|
||||
* Published when an event is sent with a failure.
|
||||
*/
|
||||
EVENT_PUBLICATION_FAILURE {
|
||||
@Override public String getName() {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.Observation.Event#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "event.publication.failure";
|
||||
}
|
||||
|
||||
@Override public String getContextualName() {
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see io.micrometer.observation.Observation.Event#getContextualName()
|
||||
*/
|
||||
@Override
|
||||
public String getContextualName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,8 @@ import io.micrometer.observation.ObservationRegistry;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
@@ -30,6 +28,7 @@ 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.lang.Nullable;
|
||||
import org.springframework.modulith.core.ApplicationModule;
|
||||
import org.springframework.modulith.core.ApplicationModules;
|
||||
import org.springframework.modulith.runtime.ApplicationModulesRuntime;
|
||||
@@ -37,22 +36,25 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Oliver Drotbohm
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
public class SpringDataRestModuleObservabilityBeanPostProcessor extends ModuleObservabilitySupport 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 SpringDataRestModuleObservabilityBeanPostProcessor} for the given {@link ApplicationModulesRuntime}
|
||||
* and {@link ObservationRegistry}.
|
||||
* Creates a new {@link SpringDataRestModuleObservabilityBeanPostProcessor} for the given
|
||||
* {@link ApplicationModulesRuntime} and {@link ObservationRegistry}.
|
||||
*
|
||||
* @param runtime must not be {@literal null}.
|
||||
* @param observationRegistry must not be {@literal null}.
|
||||
* @param environment must not be {@literal null}.
|
||||
*/
|
||||
public SpringDataRestModuleObservabilityBeanPostProcessor(ApplicationModulesRuntime runtime, Supplier<ObservationRegistry> observationRegistry, Environment environment) {
|
||||
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!");
|
||||
@@ -75,8 +77,8 @@ public class SpringDataRestModuleObservabilityBeanPostProcessor extends ModuleOb
|
||||
return bean;
|
||||
}
|
||||
|
||||
Advice interceptor = new DataRestControllerInterceptor(runtime, observationRegistry, environment);
|
||||
Advisor advisor = new DefaultPointcutAdvisor(interceptor);
|
||||
var interceptor = new DataRestControllerInterceptor(runtime, observationRegistry, environment);
|
||||
var advisor = new DefaultPointcutAdvisor(interceptor);
|
||||
|
||||
return addAdvisor(bean, advisor, it -> it.setProxyTargetClass(true));
|
||||
}
|
||||
@@ -90,11 +92,12 @@ public class SpringDataRestModuleObservabilityBeanPostProcessor extends ModuleOb
|
||||
/**
|
||||
* 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}.
|
||||
* @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!");
|
||||
@@ -124,6 +127,7 @@ public class SpringDataRestModuleObservabilityBeanPostProcessor extends ModuleOb
|
||||
return ModuleEntryInterceptor.of(observed, observationRegistry.get(), environment).invoke(invocation);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ApplicationModule getModuleFrom(Object[] arguments) {
|
||||
|
||||
for (Object argument : arguments) {
|
||||
|
||||
@@ -38,13 +38,14 @@ import org.springframework.scheduling.annotation.AsyncAnnotationAdvisor;
|
||||
* Integration tests for {@link ModuleObservabilityBeanPostProcessor}.
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class ModuleObservabilityBeanPostProcessorIntegrationTests {
|
||||
|
||||
@Test
|
||||
void decoratesExposedComponentsWithTracingInterceptor() {
|
||||
|
||||
SampleComponent bean = SpringApplication
|
||||
var bean = SpringApplication
|
||||
.run(new Class<?>[] { ExampleApplication.class, ModuleObservabilityConfiguration.class }, new String[] {})
|
||||
.getBean(SampleComponent.class);
|
||||
|
||||
@@ -62,13 +63,15 @@ class ModuleObservabilityBeanPostProcessorIntegrationTests {
|
||||
@Configuration
|
||||
static class ModuleObservabilityConfiguration {
|
||||
|
||||
@Bean ModuleObservabilityBeanPostProcessor foo(ConfigurableApplicationContext context) {
|
||||
@Bean
|
||||
ModuleObservabilityBeanPostProcessor foo(ConfigurableApplicationContext context) {
|
||||
|
||||
var runtime = ApplicationRuntime.of(context);
|
||||
var modulesRuntime = new ApplicationModulesRuntime(() -> TestApplicationModules.of(ExampleApplication.class),
|
||||
runtime);
|
||||
|
||||
return new ModuleObservabilityBeanPostProcessor(modulesRuntime, () -> ObservationRegistry.NOOP, context.getBeanFactory(), context.getEnvironment());
|
||||
return new ModuleObservabilityBeanPostProcessor(modulesRuntime, () -> ObservationRegistry.NOOP,
|
||||
context.getBeanFactory(), context.getEnvironment());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.modulith.runtime.ApplicationModulesRuntime;
|
||||
* Unit tests for {@link ModuleObservabilityBeanPostProcessor}.
|
||||
*
|
||||
* @author Oliver Drotbohm
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class ModuleObservabilityBeanPostProcessorUnitTests {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user