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

为何在Datadog指标探索器中找不到Micrometer实现的计数器?

问题描述

我尝试用Micrometer集成Datadog,创建了heartBeatExecutionCounter和heartBeatSuccessCounter两个计数器指标,定义的指标名称分别是ep_heartbeat_job_execution_count和ep_heartbeat_job_success_count。但在Datadog指标探索器里搜不到这两个指标,查看日志发现无法向Datadog发送指标,报错信息如下:

2022-12-17 23:40:00,006  WARN [datadog-metrics-publisher] (DatadogMeterRegistry.java:149) - failed to send metrics to datadog
java.lang.NoClassDefFoundError: io/micrometer/common/util/StringUtils
    at io.micrometer.datadog.DatadogNamingConvention.name(DatadogNamingConvention.java:62) ~[micrometer-registry-datadog-1.10.2.jar:1.10.2]
    at io.micrometer.core.instrument.Meter$Id.getConventionName(Meter.java:319) ~[micrometer-core-1.8.4.jar:1.8.4]
    at io.micrometer.core.instrument.MeterRegistry.getConventionName(MeterRegistry.java:253) ~[micrometer-core-1.8.4.jar:1.8.4]
    at io.micrometer.datadog.DatadogMeterRegistry.writeMetric(DatadogMeterRegistry.java:254) ~[micrometer-registry-datadog-1.10.2.jar:1.10.2]
    at io.micrometer.datadog.DatadogMeterRegistry.lambda$writeMeter$12(DatadogMeterRegistry.java:212) ~[micrometer-registry-datadog-1.10.2.jar:1.10.2]
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[?:?]
    at java.util.Collections$2.tryAdvance(Collections.java:4747) ~[?:?]
    at java.util.Collections$2.forEachRemaining(Collections.java:4755) ~[?:?]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[?:?]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[?:?]
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) ~[?:?]
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) ~[?:?]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:?]
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497) ~[?:?]
    at java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:274) ~[?:?]
    at java.util.ArrayList$SubList$2.forEachRemaining(ArrayList.java:1511) ~[?:?]
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[?:?]
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[?:?]
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[?:?]
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:?]
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[?:?]
    at io.micrometer.datadog.DatadogMeterRegistry.publish(DatadogMeterRegistry.java:138) ~[micrometer-registry-datadog-1.10.2.jar:1.10.2]
    at io.micrometer.core.instrument.push.PushMeterRegistry.publishSafely(PushMeterRegistry.java:52) ~[micrometer-core-1.8.4.jar:1.8.4]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) ~[?:?]
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) ~[?:?]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) ~[?:?]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
    at java.lang.Thread.run(Thread.java:834) ~[?:?]

实现代码

计数器定义

private MeterRegistry registry = DatadogUtils.getRegistry();
 
// 记录任务成功执行次数的计数器
private Counter heartBeatSuccessCounter = Counter.builder("ep_heartbeat_job_success_count")
        .description("EpHeartBeatJob任务成功执行的次数")
        .register(registry);

// 记录任务总执行次数的计数器
private Counter heartBeatExecutionCounter = Counter.builder("ep_heartbeat_job_execution_count")
        .description("EpHeartBeatJob任务总执行次数")
        .register(registry);

计数器递增逻辑

@Override
public void execute(JobExecutionContext context) {
    // 递增总执行次数计数器
    heartBeatExecutionCounter.increment();
    try {
        log.info("Job ** {} ** starting @ {}", context.getJobDetail().getKey().getName(), context.getFireTime());
        if (isLocalEnv()) {
            epHeartBeatService.startTask();
        } else {
            outageMillisPerDay += epHighAvailablityService.startTask();
            log.info("Accumulated outage = {} milliseconds", outageMillisPerDay);

            calendar.setTime(context.getFireTime());
            if (outageMillisPerDay > OUTAGE_MILLIS_ALLOWED_PER_WEEK) {
                //&& calendar.get(Calendar.DAY_OF_WEEK)==0) {
                throw new Exception("实际停机时间超过允许值");
            }
        }

        // 递增成功执行次数计数器
        heartBeatSuccessCounter.increment();

        log.info("Job ** {} ** completed.  Next job scheduled @ {}", context.getJobDetail().getKey().getName(), context.getNextFireTime());
        log.info("====================================================");
    } catch (Exception e) {
        log.error(e.getMessage(), e);
    }
}

Datadog工具类

import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.datadog.DatadogConfig;
import io.micrometer.datadog.DatadogMeterRegistry;

public class DatadogUtils {

    private static DatadogConfig config = new DatadogConfig() {
        @Override
        public String apiKey() {
            return "my_key";
        }

        @Override
        public String get(String key) {return null;};
    };

    private static final MeterRegistry registry = new DatadogMeterRegistry(config, Clock.SYSTEM);

    public static MeterRegistry getRegistry() {
        return registry;
    }
}

build.gradle依赖配置

dependencies {
    ...
    implementation 'io.micrometer:micrometer-core:latest.release'
}

请问我的实现哪里出了问题?


问题分析与解决

核心问题:版本不兼容+依赖缺失

从报错NoClassDefFoundError: io/micrometer/common/util/StringUtils可以定位两个关键问题:

  1. 版本不匹配:你使用的micrometer-registry-datadog版本是1.10.2,但micrometer-core版本是1.8.4,两者版本差异过大。Micrometer从1.10.x版本开始,将StringUtils从io.micrometer.core.util迁移到了io.micrometer.common.util,低版本core包中没有这个类,导致运行时找不到。
  2. 依赖缺失:你的build.gradle仅引入了micrometer-core,未显式引入micrometer-registry-datadog依赖,代码能编译可能是间接依赖引入了该包,但版本不符合要求。

解决步骤

1. 统一Micrometer版本并添加正确依赖

修改build.gradle,指定统一的Micrometer版本,同时显式引入Datadog注册表依赖,避免版本冲突:

def micrometerVersion = '1.10.2'
dependencies {
    ...
    implementation "io.micrometer:micrometer-core:${micrometerVersion}"
    implementation "io.micrometer:micrometer-registry-datadog:${micrometerVersion}"
}

不要使用latest.release,固定版本能有效避免版本不一致问题。

2. 完善Datadog配置

你的DatadogConfig实现中get(String key)方法直接返回null,会导致默认配置无法生效,建议修改为:

private static DatadogConfig config = new DatadogConfig() {
    @Override
    public String apiKey() {
        return "my_key";
    }

    @Override
    public String get(String key) {
        // 继承默认配置
        return DatadogConfig.super.get(key);
    }
};

如果是国内环境或自定义端点,可添加URI配置:

@Override
public String uri() {
    return "https://api.datadoghq.cn"; // 海外环境用https://api.datadoghq.com
}

3. 验证指标发送

重启应用后,触发任务执行使计数器递增,等待Datadog默认的1分钟上报周期,再去指标探索器搜索(注意Datadog会自动转换命名格式,可尝试搜索ep.heartbeat.job.success.count)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:30:41