You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ArchUnit测试实现:禁止Log4j打印带特定注解方法的返回值

场景说明

假设存在如下Person类,其getAccountNumber()方法带有自定义注解@ShouldNotBeLogged:

public class Person {

    private String name;
    private String accountNumber;

    @ShouldNotBeLogged
    public String getAccountNumber() {
        return accountNumber;
    }

}

现需要编写ArchUnit测试规则,实现如下校验逻辑:所有声明了org.apache.logging.log4j.Logger类型静态字段的类,不得在日志中打印带有@ShouldNotBeLogged注解的方法的返回值。

如下方HelloWorld类的logMessage方法就属于违规场景,应当被ArchUnit测试识别上报:该方法通过日志打印了Person对象带@ShouldNotBeLogged注解的getAccountNumber()方法的返回值。

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class HelloWorld {

    private static final Logger logger = LogManager.getLogger(HelloWorld.class);

    public void logMessage(Person person) {
        logger.debug("logging Acc No. - {}", person.getAccountNumber());
    }
}
规则实现

你可以直接通过ArchUnit的方法调用匹配能力实现上述校验,核心逻辑是定位所有持有Log4j静态Logger的类,拦截这些类中所有Logger实例的日志方法调用,检查传入参数是否包含被@ShouldNotBeLogged标记的方法返回值,完整测试代码如下:

import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchRule;
import org.junit.jupiter.api.Test;

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;

public class SensitiveLogCheckTest {

    // 替换为你自己项目需要扫描的根包路径
    private static final JavaClasses CLASSES = new ClassFileImporter()
            .importPackages("cn.your.project.base.package");

    @Test
    void forbid_logging_sensitive_data_marked_by_annotation() {
        ArchRule sensitiveLogRule = noClasses()
                // 筛选所有声明了Log4j Logger静态字段的类
                .that().haveDeclaredFields(field ->
                        field.getRawType().isAssignableTo(org.apache.logging.log4j.Logger.class)
                                && field.isStatic()
                )
                // 校验这类类中不允许出现违规的方法调用
                .should().callMethodWhere(call ->
                        // 匹配所有对Logger实例的方法调用
                        call.getTargetOwner().isAssignableTo(org.apache.logging.log4j.Logger.class)
                        // 检查调用参数中是否存在被@ShouldNotBeLogged标记的方法调用
                        .and(call.getArguments().stream()
                                .anyMatch(argAccess ->
                                        argAccess.getTarget().isAnnotatedWith(ShouldNotBeLogged.class)
                                ))
                )
                .because("日志中禁止输出标记了@ShouldNotBeLogged的敏感信息,避免数据泄露");

        sensitiveLogRule.check(CLASSES);
    }
}

补充说明

  • 上述规则默认覆盖Logger的所有级别日志方法(debug/info/warn/error/trace/fatal等),如果需要单独限制特定日志级别,可以在方法调用匹配逻辑中追加方法名判断
  • 如果需要支持Slf4j、Logback等其他日志框架,只需要修改getTargetOwner匹配的Logger类型为对应框架的Logger全类名即可
  • 该规则可以识别直接在日志参数中调用敏感方法的场景,也就是示例中HelloWorld类的违规写法;如果需要覆盖先把敏感方法返回值存入局部变量/成员变量后再传入日志的场景,可以搭配ArchUnit的数据流分析扩展实现,常规业务场景下当前规则已经可以覆盖90%以上的违规写法

内容的提问来源于stack exchange,提问作者Mohit Charaya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:55:16