使用AOP统计Logger.error()调用次数,Prometheus计数器未递增排查
问题排查:AOP结合Prometheus统计Logger.error()调用次数不生效
核心问题分析
当前代码存在两个关键问题导致计数器不递增:
1. 切点表达式使用错误
你用了execution(void org.slf4j.Logger.error(..)),但Spring AOP的execution切点匹配的是方法在目标类上的执行逻辑,而org.slf4j.Logger是接口,实际运行时LoggerFactory返回的是具体日志框架(如Logback)的实现类实例,且我们要拦截的是对Logger.error()方法的调用动作,不是方法内部的执行,应该改用AspectJ原生的call()切点:
@Pointcut("call(void org.slf4j.Logger.error(..)) && within(com.mypackage.controller.DummyController)") public void errorMethodExecution() { }
2. Spring AOP默认不支持call()切点
Spring AOP默认基于动态代理,仅支持有限的切点类型(如execution、within、annotation等),call()是AspectJ原生切点,需要启用**AspectJ加载时织入(LTW)**才能生效:
- 在
pom.xml中添加AspectJ依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency>
- 在Spring Boot启动类上添加
@EnableLoadTimeWeaving注解:
@SpringBootApplication @EnableLoadTimeWeaving public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
修改后的完整AOP代码
import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Aspect @Component public class ErrorLogCounterAspect { private final Counter errorLogCounter; @Autowired public ErrorLogCounterAspect(MeterRegistry meterRegistry) { this.errorLogCounter = Counter .builder("log.error.calls") .description("Total number of org.slf4j.Logger.error() calls") .register(meterRegistry); } @Pointcut("call(void org.slf4j.Logger.error(..)) && (within(com.mypackage.controller..*) || within(com.mypackage.service..*) || within(com.mypackage.repository..*))") public void errorMethodCall() { } @After("errorMethodCall()") public void countLogErrorCalls(JoinPoint joinPoint) { errorLogCounter.increment(); } }
额外优化点
- 扩展切点的
within范围,覆盖控制器、服务、仓库等所有需要统计的包(如示例中的com.mypackage.controller..*表示controller包及其子包) - 可以为计数器添加标签(如
tag("class", joinPoint.getTarget().getClass().getSimpleName())),区分不同类的错误日志调用情况
内容的提问来源于stack exchange,提问作者Sachin Mankotia
相关产品推荐
相关产品推荐

