Skip to content

Commit

Permalink
Provide a new Logging Rule checking a Logger Usage Based on Classes M…
Browse files Browse the repository at this point in the history
…atching Regex

Closes gh-54
  • Loading branch information
mnhock committed Jun 25, 2024
1 parent e89fc80 commit 5d213fe
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 8 deletions.
18 changes: 15 additions & 3 deletions docs/USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,10 @@ The default mode is `WITHOUT_TESTS`, which excludes test classes from the import

The default mode is `WITHOUT_TESTS`, which checks only test classes.

| Category | Method Name | Rule Description |
|----------|-------------------|----------------------------------------------------------------------------------------------------|
| General | `loggersShouldFollowConventions` | Ensure that the specified logger follow a specific naming pattern and have the required modifiers |
| Category | Method Name | Rule Description |
|----------|-----------------------------------|---------------------------------------------------------------------------------------------------|
| General | `loggersShouldFollowConventions` | Ensure that the specified logger follow a specific naming pattern and have the required modifiers |
| General | `classesShouldUseLogger` | Ensure that classes matching a given regex have a field of a specified logger type |

### Test Rules

Expand Down Expand Up @@ -329,6 +330,17 @@ Taikai.builder()
.check();
```

- **Ensure Classes Use Specified Logger**: Ensure that classes matching a given regex have a field of a specified logger type.

```java
Taikai.builder()
.namespace("com.company.yourproject")
.logging(logging -> logging
.classesShouldUseLogger(org.slf4j.Logger.class, ".*Service")
.build()
.check();
```

## 7. Test Rules

Test configuration involves specifying constraints related to testing frameworks and practices.
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/com/enofex/taikai/internal/ArchConditions.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.enofex.taikai.internal.Modifiers.isFieldPublic;
import static com.enofex.taikai.internal.Modifiers.isFieldStatic;

import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaField;
import com.tngtech.archunit.core.domain.JavaMethod;
import com.tngtech.archunit.lang.ArchCondition;
Expand Down Expand Up @@ -56,4 +57,27 @@ public void check(JavaField field, ConditionEvents events) {
}
};
}

/**
* Creates a condition that checks if a class has a field of the specified type.
*
* @param typeName the name of the type to check for in the fields of the class
* @return an architectural condition for checking if a class has a field of the specified type
*/
public static ArchCondition<JavaClass> haveFieldOfType(String typeName) {
return new ArchCondition<>("have a field of type %s".formatted(typeName)) {
@Override
public void check(JavaClass item, ConditionEvents events) {
boolean hasFieldOfType = item.getAllFields().stream()
.anyMatch(field -> field.getRawType().getName().equals(typeName));

if (!hasFieldOfType) {
events.add(SimpleConditionEvent.violated(item,
"%s does not have a field of type %s".formatted(
item.getName(),
typeName)));
}
}
};
}
}
32 changes: 27 additions & 5 deletions src/main/java/com/enofex/taikai/logging/LoggingConfigurer.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.enofex.taikai.logging;

import static com.enofex.taikai.internal.ArchConditions.haveFieldOfType;
import static com.enofex.taikai.logging.LoggerConventions.followLoggerConventions;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;

Expand All @@ -16,16 +17,37 @@ public LoggingConfigurer(ConfigurerContext configurerContext) {
super(configurerContext);
}

public LoggingConfigurer classesShouldUseLogger(String typeName, String regex) {
return classesShouldUseLogger(typeName, regex, null);
}

public LoggingConfigurer classesShouldUseLogger(String typeName, String regex,
Configuration configuration) {
return addRule(TaikaiRule.of(classes()
.that().haveNameMatching(regex)
.should(haveFieldOfType(typeName)), configuration));
}

public LoggingConfigurer classesShouldUseLogger(Class<?> clazz, String regex) {
return classesShouldUseLogger(clazz, regex, null);
}

public LoggingConfigurer classesShouldUseLogger(Class<?> clazz, String regex,
Configuration configuration) {
return addRule(TaikaiRule.of(classes()
.that().haveNameMatching(regex)
.should(haveFieldOfType(clazz.getName())), configuration));
}

public LoggingConfigurer loggersShouldFollowConventions(String typeName, String regex,
Set<JavaModifier> requiredModifiers) {
return loggersShouldFollowConventions(typeName, regex, requiredModifiers, null);
}

public LoggingConfigurer loggersShouldFollowConventions(String typeName, String regex,
Set<JavaModifier> requiredModifiers, Configuration configuration) {
return addRule(TaikaiRule.of(classes().should(
followLoggerConventions(typeName, regex, requiredModifiers)),
configuration));
return addRule(TaikaiRule.of(classes()
.should(followLoggerConventions(typeName, regex, requiredModifiers)), configuration));
}

public LoggingConfigurer loggersShouldFollowConventions(Class<?> clazz, String regex,
Expand All @@ -35,8 +57,8 @@ public LoggingConfigurer loggersShouldFollowConventions(Class<?> clazz, String r

public LoggingConfigurer loggersShouldFollowConventions(Class<?> clazz, String regex,
Set<JavaModifier> requiredModifiers, Configuration configuration) {
return addRule(TaikaiRule.of(classes().should(
followLoggerConventions(clazz.getName(), regex, requiredModifiers)),
return addRule(TaikaiRule.of(classes()
.should(followLoggerConventions(clazz.getName(), regex, requiredModifiers)),
configuration));
}
}
1 change: 1 addition & 0 deletions src/test/java/com/enofex/taikai/Usage.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public static void main(String[] args) {
.constantsShouldFollowConventions()
.interfacesShouldNotHavePrefixI()))
.logging(logging -> logging
.classesShouldUseLogger(Logger.class, ".*Service")
.loggersShouldFollowConventions(Logger.class, "logger", EnumSet.of(PRIVATE, FINAL)))
.test(test -> test
.junit5(junit5 -> junit5
Expand Down

0 comments on commit 5d213fe

Please sign in to comment.