使用archunit来强制执行日志上下文

huangapple go评论70阅读模式
英文:

Using archunit to enforce log context

问题

I'll provide the translation for the code and error message:

以下是代码的翻译和错误信息:

按照[这个][1]博客文章中建议的方法我正在尝试创建一个ArchUnit规则以强制要求日志记录语句具有上下文信息但是示例中提到的代码无法编译

```java
public static ArchRule noInfoLoggingWithoutContext() {
        ArchCondition<JavaClass> loggerWithOutContext =
                callMethodWhere(
                        target(name("info"))
                                .and(target(owner(assignableTo(Logger.class))))
                                .and(target(rawParameterTypes(new DescribedPredicate<>(
                                        "logger.info without context") {
                                    @Override
                                    public boolean test(List<JavaClass> methodParameters) {
                                        return methodParameters.size() <= 1;
                                    }
                                })))).as("use logger.info without context");
        return noClasses().should(loggerWithOutContext);
 }

上述提到的代码出现以下错误:

所需类型: DescribedPredicate<? super AccessTarget>
提供的类型: DescribedPredicate<HasParameterTypes>

有什么建议,我们如何实现这样的规则?

archunit版本: 1.0.1


请注意,这是您提供的代码和错误信息的翻译。如果需要进一步的帮助或解释,请随时提出。

<details>
<summary>英文:</summary>

Following the method suggested in [this][1] blog post, I am trying to create an archunit rule that will enforce log statements to have contextual information. But the code mentioned in the example is not compiling:

```java
public static ArchRule noInfoLoggingWithoutContext() {
        ArchCondition&lt;JavaClass&gt; loggerWithOutContext =
                callMethodWhere(
                        target(name(&quot;info&quot;))
                                .and(target(owner(assignableTo(Logger.class))))
                                .and(target(rawParameterTypes(new DescribedPredicate&lt;&gt;(&quot;logger.info without context&quot;) {
                                    @Override
                                    public boolean test(List&lt;JavaClass&gt; methodParameters) {
                                        return methodParameters.size() &lt;= 1;
                                    }
                                })))).as(&quot;use logger.info without context&quot;);
        return noClasses().should(loggerWithOutContext);
 }

The above mentioned code fails with the following error:

Required type: DescribedPredicate &lt;? super AccessTarget&gt;
Provided: DescribedPredicate&lt;HasParameterTypes&gt;

Any suggestions, how can we implement such a rule?

archunit version: 1.0.1

答案1

得分: 1

你可能选择了错误的静态导入:

import static com.tngtech.archunit.core.domain.JavaAccess.Predicates.target;

(它返回一个 DescribedPredicate&lt;JavaAccess&lt;?&gt;&gt;
而不是

import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;

(它返回一个 DescribedPredicate&lt;JavaCall&lt;?&gt;&gt;)。

因为 callMethodWhere 接受一个 DescribedPredicate&lt;? super JavaMethodCall&gt;
JavaMethodCall 继承自 JavaCall,后者又继承自 JavaCodeUnitAccess,再者继承自 JavaAccess
所以 "错误" 的 target 方法适用于 callMethodWhere
但它的谓词只能操作 JavaAccess,它具有 nameowner,但没有 rawParameterTypes

无关于你的问题:我建议将整个规则简化为:

import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import org.slf4j.Logger;

import static com.tngtech.archunit.base.DescribedPredicate.describe;
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
import static com.tngtech.archunit.lang.conditions.ArchConditions.callMethodWhere;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.is;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;

public class StackOverflow76250573 {

    @ArchTest
    ArchRule noInfoLoggingWithoutContext =
        noClasses().should(callMethodWhere(target(is(describe("logger.info without context",
            target ->
                target.getOwner().isAssignableTo(Logger.class)
                    && target.getName().equals("info")
                    && target.getRawParameterTypes().size() < 2
        )))));
}
英文:

You probably picked the "wrong" static import

import static com.tngtech.archunit.core.domain.JavaAccess.Predicates.target;

(which returns a DescribedPredicate&lt;JavaAccess&lt;?&gt;&gt;) instead of

import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;

(which returns a DescribedPredicate&lt;JavaCall&lt;?&gt;&gt;).

As callMethodWhere takes a DescribedPredicate&lt;? super JavaMethodCall&gt;,
and as JavaMethodCall extends JavaCall, which in turn extends JavaCodeUnitAccess, which in turn extends JavaAccess, the "wrong" target method worked for callMethodWhere, but its predicates could only operate on JavaAccess, which has a name and an owner, but no rawParameterTypes.


Unrelated to your question: I would simplify the entire rule to

import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import org.slf4j.Logger;

import static com.tngtech.archunit.base.DescribedPredicate.describe;
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
import static com.tngtech.archunit.lang.conditions.ArchConditions.callMethodWhere;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.is;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;

public class StackOverflow76250573 {

    @ArchTest
    ArchRule noInfoLoggingWithoutContext =
        noClasses().should(callMethodWhere(target(is(describe(&quot;logger.info without context&quot;,
            target -&gt;
                target.getOwner().isAssignableTo(Logger.class)
                    &amp;&amp; target.getName().equals(&quot;info&quot;)
                    &amp;&amp; target.getRawParameterTypes().size() &lt; 2
        )))));
}

huangapple
  • 本文由 发表于 2023年5月15日 10:41:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76250573.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定