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

如何为@Slf4j生成的每条日志添加Prometheus指标?

无需修改@Slf4j用法实现日志级别Prometheus指标统计

方案一:日志框架原生扩展(推荐)

Lombok的@Slf4j本质是生成对应日志框架(如Logback、Log4j2)的Logger实例,直接在日志框架层面添加统计逻辑是最优雅的方案——完全不侵入业务代码,性能也最优。

以Logback为例实现

  1. 自定义Prometheus统计Appender
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import io.prometheus.client.Counter;

public class PrometheusLogAppender extends AppenderBase<ILoggingEvent> {
    // 定义Prometheus计数器,按日志级别、Logger名称维度统计
    private static final Counter LOG_COUNTER = Counter.build()
            .name("application_logs_total")
            .help("Total logs counted by level and logger class")
            .labelNames("level", "logger_name")
            .register();

    @Override
    protected void append(ILoggingEvent event) {
        // 根据日志事件更新计数器
        LOG_COUNTER.labels(event.getLevel().toString(), event.getLoggerName())
                .inc();
    }
}
  1. 在logback.xml中配置该Appender
    将自定义Appender添加到根Logger或指定Logger的引用列表中,不影响原有日志输出逻辑:
<configuration>
    <!-- 原有日志Appender配置(如控制台、文件输出) -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!-- ... 原有配置 ... -->
    </appender>

    <!-- 新增Prometheus统计Appender -->
    <appender name="PROMETHEUS" class="com.your.package.PrometheusLogAppender" />

    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="PROMETHEUS" />
    </root>
</configuration>

配置完成后,所有@Slf4j生成的Logger输出的日志都会被自动统计,Prometheus可直接拉取application_logs_total指标。

Log4j2实现思路

自定义继承AbstractAppender的统计类,在append方法中处理LogEvent并更新Prometheus计数器,最后在log4j2.xml中配置该Appender即可,逻辑与Logback一致。

方案二:Spring AOP切面实现

如果无法修改日志框架配置,可以用AOP拦截Logger的日志方法调用,同样无需改动@Slf4j的使用代码。

具体实现

  1. 确保项目引入Spring AOP依赖(Spring Boot项目可直接用spring-boot-starter-aop)。
  2. 定义日志统计切面
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import io.prometheus.client.Counter;

@Aspect
@Component
public class LogMetricsAspect {
    private static final Counter LOG_COUNTER = Counter.build()
            .name("application_logs_total")
            .help("Total logs counted by level and logger class")
            .labelNames("level", "logger_name")
            .register();

    // 切点:拦截org.slf4j.Logger所有级别的日志方法
    @Pointcut("execution(* org.slf4j.Logger.trace(..)) || " +
              "execution(* org.slf4j.Logger.debug(..)) || " +
              "execution(* org.slf4j.Logger.info(..)) || " +
              "execution(* org.slf4j.Logger.warn(..)) || " +
              "execution(* org.slf4j.Logger.error(..))")
    public void logMethodPointcut() {}

    // 日志方法执行完成后更新计数器
    @AfterReturning("logMethodPointcut()")
    public void countLogEvents(JoinPoint joinPoint) {
        Logger targetLogger = (Logger) joinPoint.getTarget();
        String loggerName = targetLogger.getName();
        // 从方法名获取日志级别(如info、error)
        String logLevel = joinPoint.getSignature().getName().toUpperCase();
        LOG_COUNTER.labels(logLevel, loggerName).inc();
    }
}
  1. 注意事项
  • 该切面会拦截所有org.slf4j.Logger实例的方法调用,包括手动创建的Logger,不止@Slf4j生成的。
  • 性能上略逊于日志框架扩展方案,但绝大多数业务场景下可忽略这个开销。

方案对比

方案核心优势局限性
日志框架原生扩展性能最优,无额外开销,完全贴合日志体系标准需要修改对应日志框架的配置文件
Spring AOP切面无需改动日志框架配置,实现简单快捷依赖Spring环境,存在轻微方法拦截开销

优先推荐日志框架原生扩展方案,它是最贴合日志系统设计的实现方式,完全满足你“不修改现有@Slf4j用法”的需求。

内容的提问来源于stack exchange,提问作者Duje Drobac

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 13:25:18