Skip to content

Commit

Permalink
GH-928 - Polishing.
Browse files Browse the repository at this point in the history
License headers, formatting, null checks.
  • Loading branch information
odrotbohm committed Nov 22, 2024
1 parent 738ad3f commit f3d5e3b
Show file tree
Hide file tree
Showing 12 changed files with 319 additions and 89 deletions.
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -11,40 +24,62 @@
* 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;
}

private boolean isEventListener(ModulithContext context) {
try {
return context.getModule().isEventListenerInvocation(context.getInvocation());
} catch (Exception e) {
return false;
}
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) {
Method method = context.getInvocation().getMethod();

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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
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;
Expand Down Expand Up @@ -163,7 +162,6 @@ private Method findModuleLocalMethod(MethodInvocation invocation) {
var targetClass = advised.getTargetClass();

if (module.contains(targetClass)) {

return AopUtils.getMostSpecificMethod(method, targetClass);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -33,16 +33,22 @@
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;

/**
Expand Down Expand Up @@ -103,7 +109,8 @@ public Object invoke(MethodInvocation invocation) throws Throwable {
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;
}

Expand All @@ -116,18 +123,26 @@ public Object invoke(MethodInvocation invocation) throws Throwable {

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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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!");
Expand Down Expand Up @@ -82,8 +84,10 @@ public void onApplicationEvent(ApplicationEvent event) {
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()) //
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,59 @@
/*
* 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.
*
* @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;
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;
}
}
Loading

0 comments on commit f3d5e3b

Please sign in to comment.