Skip to content

Commit

Permalink
extend ClassInstrumentationConfiguration (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
EddeCCC committed Sep 11, 2024
1 parent b0f1722 commit 9a1bc17
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.slf4j.LoggerFactory;
import rocks.inspectit.gepard.agent.instrumentation.cache.PendingClassesCache;
import rocks.inspectit.gepard.agent.internal.instrumentation.InstrumentationState;
import rocks.inspectit.gepard.agent.internal.instrumentation.model.ClassInstrumentationConfiguration;
import rocks.inspectit.gepard.agent.internal.schedule.NamedRunnable;
import rocks.inspectit.gepard.agent.resolver.ConfigurationResolver;

Expand Down Expand Up @@ -70,10 +71,12 @@ Set<Class<?>> getNextBatch(int batchSize) {
checkedClassesCount++;

try {
boolean shouldInstrument = configurationResolver.shouldInstrument(clazz);
boolean isInstrumented = instrumentationState.isInstrumented(clazz);
ClassInstrumentationConfiguration instrumentationConfiguration =
configurationResolver.getActiveConfiguration(clazz);
boolean shouldRetransform =
instrumentationState.shouldRetransform(clazz, instrumentationConfiguration);

if (shouldInstrument != isInstrumented) classesToRetransform.add(clazz);
if (shouldRetransform) classesToRetransform.add(clazz);
} catch (Exception e) {
log.error("Could not check instrumentation status for {}", clazz.getName(), e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@ public static InstrumentationState create() {
return new InstrumentationState();
}

public boolean shouldRetransform(
Class<?> clazz, ClassInstrumentationConfiguration currentConfig) {
ClassInstrumentationConfiguration activeConfig =
activeInstrumentations.asMap().entrySet().stream()
.filter(entry -> entry.getKey().isEqualTo(clazz)) // find class
.map(Map.Entry::getValue) // get configuration
.findAny()
.orElse(null);

if (Objects.nonNull(activeConfig)) return !activeConfig.equals(currentConfig);
return currentConfig.isActive();
}

/**
* Checks, if the provided class is already instrumented.
*
Expand All @@ -39,7 +52,7 @@ public boolean isInstrumented(Class<?> clazz) {
.findAny()
.orElse(null);

if (Objects.nonNull(activeConfig)) return activeConfig.isInstrumented();
// if (Objects.nonNull(activeConfig)) return activeConfig.isInstrumented();
return false;
}

Expand All @@ -53,7 +66,7 @@ public boolean isInstrumented(InstrumentedType instrumentedType) {
ClassInstrumentationConfiguration activeConfig =
activeInstrumentations.getIfPresent(instrumentedType);

if (Objects.nonNull(activeConfig)) return activeConfig.isInstrumented();
// if (Objects.nonNull(activeConfig)) return activeConfig.isInstrumented();
return false;
}

Expand All @@ -62,8 +75,8 @@ public boolean isInstrumented(InstrumentedType instrumentedType) {
*
* @param type the instrumented type
*/
public void addInstrumentedType(InstrumentedType type) {
ClassInstrumentationConfiguration newConfig = new ClassInstrumentationConfiguration(true);
public void addInstrumentedType(
InstrumentedType type, ClassInstrumentationConfiguration newConfig) {
activeInstrumentations.put(type, newConfig);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
package rocks.inspectit.gepard.agent.internal.instrumentation.model;

import java.util.Collections;
import java.util.Objects;
import java.util.Set;

/**
* Stores the instrumentation configuration for a specific class. Currently, a class can only be
* instrumented or not. Later, we could add a list of active rules for example.
*/
public class ClassInstrumentationConfiguration {
public record ClassInstrumentationConfiguration(Set<InstrumentationScope> activeScopes) {

/** The configuration representing that no instrumentation of the class if performed. */
public static final ClassInstrumentationConfiguration NO_INSTRUMENTATION =
new ClassInstrumentationConfiguration(Collections.emptySet());

/** Currently, only true */
private final boolean isInstrumented;
@Override
public boolean equals(Object o) {
if (o instanceof ClassInstrumentationConfiguration otherConfig)
return activeScopes.equals(otherConfig.activeScopes);
return false;
}

public ClassInstrumentationConfiguration(boolean isInstrumented) {
this.isInstrumented = isInstrumented;
@Override
public int hashCode() {
return Objects.hash(activeScopes);
}

public boolean isInstrumented() {
return isInstrumented;
/**
* Checks, if this configuration induces bytecode changes to the target class.
*
* @return true, if this configuration expects instrumentation
*/
public boolean isActive() {
return !activeScopes.isEmpty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package rocks.inspectit.gepard.agent.internal.instrumentation.model;

import java.util.List;
import java.util.Objects;
import rocks.inspectit.gepard.agent.internal.configuration.model.instrumentation.Scope;

/**
* @param fqn
* @param methods
*/
public record InstrumentationScope(String fqn, List<String> methods) {

/**
* @param scope
* @return
*/
public static InstrumentationScope create(Scope scope) {
return new InstrumentationScope(scope.getFqn(), scope.getMethods());
}

@Override
public boolean equals(Object o) {
if (o instanceof InstrumentationScope otherScope)
return fqn.equals(otherScope.fqn) && methods.equals(otherScope.methods);
return false;
}

@Override
public int hashCode() {
return Objects.hash(fqn, methods);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package rocks.inspectit.gepard.agent.resolver;

import java.util.Set;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import rocks.inspectit.gepard.agent.internal.configuration.model.instrumentation.InstrumentationConfiguration;
import rocks.inspectit.gepard.agent.internal.instrumentation.model.ClassInstrumentationConfiguration;
import rocks.inspectit.gepard.agent.internal.instrumentation.model.InstrumentationScope;
import rocks.inspectit.gepard.agent.resolver.scope.ScopeResolver;

/**
Expand All @@ -27,13 +30,35 @@ public static ConfigurationResolver create(ConfigurationHolder holder) {
return new ConfigurationResolver(holder);
}

/**
* @param clazz
* @return
*/
public ClassInstrumentationConfiguration getActiveConfiguration(Class<?> clazz) {
String className = clazz.getName();
Set<InstrumentationScope> activeScopes = scopeResolver.getActiveScopes(className);

if (activeScopes.isEmpty()) return ClassInstrumentationConfiguration.NO_INSTRUMENTATION;
return new ClassInstrumentationConfiguration(activeScopes);
}

public ClassInstrumentationConfiguration getActiveConfiguration(TypeDescription typeDescription) {
String className = typeDescription.getName();
Set<InstrumentationScope> activeScopes = scopeResolver.getActiveScopes(className);

// TODO Das sollte eigtl nicht passieren können?
if (activeScopes.isEmpty()) return ClassInstrumentationConfiguration.NO_INSTRUMENTATION;
return new ClassInstrumentationConfiguration(activeScopes);
}

/**
* Checks, if the provided class requires instrumentation.
*
* @param clazz the class object
* @return true, if the provided class should be instrumented
*/
public boolean shouldInstrument(Class<?> clazz) {
// TODO REMOVE
String className = clazz.getName();
return shouldInstrument(className);
}
Expand All @@ -57,7 +82,6 @@ public boolean shouldInstrument(TypeDescription type) {
*/
public ElementMatcher.Junction<MethodDescription> getMethodMatcher(
TypeDescription typeDescription) {

return scopeResolver.buildMethodMatcher(typeDescription);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package rocks.inspectit.gepard.agent.resolver.scope;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import rocks.inspectit.gepard.agent.internal.configuration.model.instrumentation.InstrumentationConfiguration;
import rocks.inspectit.gepard.agent.internal.configuration.model.instrumentation.Scope;
import rocks.inspectit.gepard.agent.internal.instrumentation.model.InstrumentationScope;
import rocks.inspectit.gepard.agent.resolver.ConfigurationHolder;
import rocks.inspectit.gepard.agent.resolver.matcher.CustomElementMatchers;
import rocks.inspectit.gepard.agent.resolver.matcher.MatcherChainBuilder;
Expand All @@ -24,14 +28,27 @@ public ScopeResolver(ConfigurationHolder holder) {
this.holder = holder;
}

/**
* @param fullyQualifiedName
* @return
*/
public Set<InstrumentationScope> getActiveScopes(String fullyQualifiedName) {
if (shouldIgnore(fullyQualifiedName)) return Collections.emptySet();

List<Scope> scopes = getAllMatchingScopes(fullyQualifiedName);
return scopes.stream()
.filter(Scope::isEnabled)
.map(InstrumentationScope::create)
.collect(Collectors.toSet());
}

/**
* Checks, if the provided class name requires instrumentation.
*
* @param fullyQualifiedName the full name of the class
* @return true, if the provided class should be instrumented
*/
public boolean shouldInstrument(String fullyQualifiedName) {

List<Scope> scopes = getScopes();

return !shouldIgnore(fullyQualifiedName)
Expand All @@ -47,7 +64,6 @@ public boolean shouldInstrument(String fullyQualifiedName) {
*/
public ElementMatcher.Junction<MethodDescription> buildMethodMatcher(
TypeDescription typeDescription) {

List<Scope> scopes = getAllMatchingScopes(typeDescription.getName());

if (containsAllMethodsScope(scopes)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.slf4j.LoggerFactory;
import rocks.inspectit.gepard.agent.internal.instrumentation.InstrumentationState;
import rocks.inspectit.gepard.agent.internal.instrumentation.InstrumentedType;
import rocks.inspectit.gepard.agent.internal.instrumentation.model.ClassInstrumentationConfiguration;
import rocks.inspectit.gepard.agent.resolver.ConfigurationResolver;
import rocks.inspectit.gepard.agent.transformation.advice.InspectitAdvice;

Expand Down Expand Up @@ -60,7 +61,8 @@ public DynamicType.Builder<?> transform(
builder = builder.visit(Advice.to(InspectitAdvice.class).on(methodMatcher));

// Mark type as instrumented
instrumentationState.addInstrumentedType(currentType);
ClassInstrumentationConfiguration config = resolver.getActiveConfiguration(typeDescription);
instrumentationState.addInstrumentedType(currentType, config);
} else if (instrumentationState.isInstrumented(currentType)) {
log.debug("Removing transformation from {}", typeDescription.getName());
// Mark type as uninstrumented or deinstrumented
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ void testTransformTransformsOnShouldInstrumentTrue() {
transformer.transform(builder, typeDescription, TEST_CLASS.getClassLoader(), null, null);

verify(builder).visit(any());
verify(instrumentationState).addInstrumentedType(any());
verify(instrumentationState).addInstrumentedType(any(), any());
}

@Test
Expand Down

0 comments on commit 9a1bc17

Please sign in to comment.