Agent skill
python-micrometer-cardinality-control
Prevent OutOfMemoryError from unbounded metric tags by implementing cardinality limits. Use when adding tags to Micrometer metrics, normalizing URIs or IDs to bounded categories, monitoring metric explosion, or avoiding high-cardinality fields like user IDs and request IDs. Critical for production microservices in GKE with cost-sensitive monitoring backends.
Stars
163
Forks
31
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/python-micrometer-cardinality-control
SKILL.md
Micrometer Cardinality Control
Quick Start
For any metric with dynamic tags, apply this pattern:
java
// ❌ Dangerous: unbounded cardinality
.tag("supplier.id", supplierId) // 10,000+ unique values
// ✅ Safe: normalized to bounded categories
.tag("supplier.category", normalizeSupplier(supplier)) // 5-10 values
private String normalizeSupplier(Supplier s) {
if (s.isTopTier()) return "tier1";
if (s.isDirectSupplier()) return "direct";
return "standard";
}
When to Use
- Add tags to metrics (ensure bounded cardinality)
- Normalize high-cardinality data (URIs, IDs)
- Prevent OutOfMemoryError from metric explosion
- Control monitoring costs
- Debug metric growth
When NOT to use:
- Truly unbounded data (use distributed tracing)
- Per-request details (use structured logging)
Cardinality Rules
Safe Tags (Low Cardinality)
java
// ✅ HTTP method (4-10 values)
.tag("method", "GET")
// ✅ Status class (5 values)
.tag("status.class", "2xx")
// ✅ Environment (3-5 values)
.tag("env", "production")
Dangerous Tags (High Cardinality)
java
// ❌ User ID (millions) → Use tracing
.tag("user.id", userId)
// ❌ Request ID (infinite) → Use tracing
.tag("request.id", requestId)
// ❌ Full URI → Normalize!
.tag("uri", "/api/charges?supplier=123")
Rule of Thumb:
- Safe per metric: < 1,000 combinations
- Safe application-wide: < 10,000 active metrics
Normalization Patterns
URI Normalization
java
@Bean
public MeterFilter uriNormalization() {
return MeterFilter.replaceTagValues("uri", uri -> {
// Strip query parameters
int queryIndex = uri.indexOf('?');
if (queryIndex > 0) uri = uri.substring(0, queryIndex);
// Replace IDs: /charges/123 → /charges/{id}
return uri.replaceAll("/\\d+", "/{id}")
.replaceAll("/[a-f0-9-]{36}", "/{uuid}");
});
}
Business Category Normalization
java
private String normalizeSupplier(String supplierId) {
Supplier supplier = supplierRepository.findById(supplierId);
if (supplier.getAnnualVolume() > 1_000_000) return "enterprise";
if (supplier.getAnnualVolume() > 100_000) return "mid-market";
if (supplier.isDirect()) return "direct";
return "standard";
}
Cardinality Limits
java
@Bean
public MeterFilter cardinalityLimiter() {
// Limit unique URIs to 100
return MeterFilter.maximumAllowableTags(
"http.server.requests",
"uri",
100,
MeterFilter.deny() // Deny new meters after limit
);
}
Monitor Cardinality
java
@Component
public class CardinalityMonitor {
private final MeterRegistry registry;
@Scheduled(fixedRate = 60_000)
public void monitorMetricCount() {
int meterCount = registry.getMeters().size();
if (meterCount > 8000) {
log.error("CRITICAL: {} metrics (threshold 8000)", meterCount);
}
Gauge.builder("micrometer.meter.count", () -> meterCount)
.register(registry);
}
}
Alternatives to High-Cardinality Tags
Use Distributed Tracing
java
// Store user ID in span, NOT metrics
span.setAttribute("user.id", userId);
// Metrics use only bounded tags
Timer.builder("charge.processing")
.tag("status", "processing") // bounded
.register(registry);
Use Structured Logging
java
// Add to MDC for logging, NOT metrics
MDC.put("user.id", userId);
Requirements
- Spring Boot 2.1+
- spring-boot-starter-actuator
- Java 11+
- For tracing: micrometer-tracing-bridge-otel
Anti-Patterns
java
// ❌ NEVER add unbounded tags
.tag("user.id", userId)
.tag("request.id", requestId)
.tag("timestamp", Instant.now())
// ✅ DO normalize to bounded categories
.tag("customer.tier", normalizeCustomer(customer))
.tag("request.type", normalizeRequest(request))
See Also
- python-micrometer-core - Meter types
- python-micrometer-business-metrics - Business KPIs
Didn't find tool you were looking for?