task-188: 指标标签规范契约(moduleType/instanceId 必带、null 归一 unknown、无用户级标签、磁盘按 path、标签名冻结)+ 8 条测试
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
package com.nanri.aiimage.metrics;
|
||||
|
||||
import io.micrometer.core.instrument.Meter;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* task-188:指标标签规范契约(spec 11 §1)。
|
||||
* moduleType/instanceId 必带(任务/文件/上传族);null/blank 归一 unknown;不记录用户级标签;
|
||||
* 值清洗;磁盘按 path 标签。标签名冻结。
|
||||
*/
|
||||
class MetricTagSpecTest {
|
||||
|
||||
private final SimpleMeterRegistry registry = new SimpleMeterRegistry();
|
||||
private final TaskObservabilityMetrics metrics = new TaskObservabilityMetrics("server-110", registry);
|
||||
|
||||
private void seedAllFamilies() {
|
||||
metrics.taskCreated("similarasin");
|
||||
metrics.taskRunningDelta("similarasin", 1);
|
||||
metrics.taskTerminal("similarasin", "success");
|
||||
metrics.taskTerminal("similarasin", "failed");
|
||||
metrics.taskDuration("similarasin", 10L);
|
||||
metrics.taskHeartbeatAge("similarasin", 10L);
|
||||
metrics.fileJobState("similarasin", "running");
|
||||
metrics.fileJobDuration("similarasin", 10L);
|
||||
metrics.upload("similarasin", 1L, 1L, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void taskFamilyCarriesModuleAndInstanceLabels() {
|
||||
seedAllFamilies();
|
||||
for (String name : List.of("aiimage.task.created", "aiimage.task.running", "aiimage.task.success",
|
||||
"aiimage.task.duration", "aiimage.task.heartbeat.age")) {
|
||||
assertTrue(hasTagKey(name, "moduleType"), name + " 应带 moduleType");
|
||||
assertTrue(hasTagKey(name, "instanceId"), name + " 应带 instanceId");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void fileJobAndUploadCarryModuleAndInstanceLabels() {
|
||||
seedAllFamilies();
|
||||
for (String name : List.of("aiimage.file-job.running", "aiimage.file-job.duration",
|
||||
"aiimage.upload.duration", "aiimage.upload.size")) {
|
||||
assertTrue(hasTagKey(name, "moduleType"), name + " 应带 moduleType");
|
||||
assertTrue(hasTagKey(name, "instanceId"), name + " 应带 instanceId");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullModuleNormalizedToUnknown() {
|
||||
metrics.taskCreated(null);
|
||||
metrics.taskCreated(" ");
|
||||
assertEquals("unknown",
|
||||
registry.get("aiimage.task.created").counter().getId().getTag("moduleType"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullInstanceNormalizedToUnknown() {
|
||||
TaskObservabilityMetrics noInstance = new TaskObservabilityMetrics(null, registry);
|
||||
noInstance.taskCreated("brand");
|
||||
assertEquals("unknown",
|
||||
registry.get("aiimage.task.created").counter().getId().getTag("instanceId"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void noUserLevelLabels() {
|
||||
seedAllFamilies();
|
||||
for (Meter meter : registry.getMeters()) {
|
||||
for (Tag tag : meter.getId().getTags()) {
|
||||
assertFalse(List.of("userId", "user_id", "uid", "operatorId", "operator_id").contains(tag.getKey()),
|
||||
"指标不应带用户级标签: " + tag.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void labelValueTrimmed() {
|
||||
metrics.taskCreated(" publish ");
|
||||
assertEquals("publish",
|
||||
registry.get("aiimage.task.created").counter().getId().getTag("moduleType"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tagKeysFrozen() {
|
||||
metrics.taskCreated("brand");
|
||||
Meter meter = registry.get("aiimage.task.created").counter();
|
||||
List<String> keys = meter.getId().getTags().stream().map(Tag::getKey).sorted().toList();
|
||||
assertEquals(List.of("instanceId", "moduleType"), keys, "任务族标签应只有 moduleType/instanceId");
|
||||
}
|
||||
|
||||
@Test
|
||||
void diskFamilyUsesPathLabel() {
|
||||
metrics.disk("/tmp/x", 10L, 1L);
|
||||
assertTrue(registry.get("aiimage.tmpdisk.used").gauge().getId().getTags().stream()
|
||||
.anyMatch(t -> t.getKey().equals("path") && t.getValue().equals("/tmp/x")));
|
||||
assertFalse(registry.get("aiimage.tmpdisk.used").gauge().getId().getTags().stream()
|
||||
.anyMatch(t -> t.getKey().equals("instanceId")), "磁盘指标按 path,不必带 instanceId");
|
||||
}
|
||||
|
||||
private boolean hasTagKey(String name, String key) {
|
||||
return registry.find(name).meters().stream()
|
||||
.flatMap(m -> m.getId().getTags().stream())
|
||||
.anyMatch(t -> t.getKey().equals(key));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user