MetricsUtil.java
package com.licensis.notaire.observability;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* Metrics utility for application observability
* Integrates with Micrometer for Prometheus metrics
*/
@Component
public class MetricsUtil {
private final MeterRegistry meterRegistry;
private static final String APP_NAMESPACE = "notaire";
private final java.util.Map<String, java.util.concurrent.atomic.AtomicInteger> activeOperationsGauges = new java.util.concurrent.ConcurrentHashMap<>();
public MetricsUtil(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
/**
* Increment a counter for an operation
*/
public void incrementCounter(String operation, String status) {
Counter.builder(APP_NAMESPACE + "_operation_total")
.description("Total operations count")
.tag("operation", operation)
.tag("status", status)
.register(meterRegistry)
.increment();
}
/**
* Record the duration of an operation
*/
public void recordDuration(String operation, long duration, TimeUnit unit) {
Timer.builder(APP_NAMESPACE + "_operation_duration")
.description("Operation duration")
.tag("operation", operation)
.publishPercentiles(0.5, 0.95, 0.99)
.register(meterRegistry)
.record(duration, unit);
}
/**
* Record a database operation
*/
public void recordDatabaseOperation(String operation, String table, long duration) {
meterRegistry.timer(
APP_NAMESPACE + "_database_operation_duration",
"operation", operation,
"table", table
).record(duration, TimeUnit.MILLISECONDS);
}
/**
* Count API errors by type
*/
public void recordApiError(String endpoint, String errorType, int statusCode) {
meterRegistry.counter(
APP_NAMESPACE + "_api_errors_total",
"endpoint", endpoint,
"errorType", errorType,
"status", String.valueOf(statusCode)
).increment();
}
/**
* Record cache hits/misses
*/
public void recordCacheHit(String cacheName) {
meterRegistry.counter(
APP_NAMESPACE + "_cache_hits_total",
"cache", cacheName
).increment();
}
public void recordCacheMiss(String cacheName) {
meterRegistry.counter(
APP_NAMESPACE + "_cache_misses_total",
"cache", cacheName
).increment();
}
/**
* Gauge for active operations
*/
public void setActiveOperations(String operation, int count) {
activeOperationsGauges.computeIfAbsent(operation, op -> {
java.util.concurrent.atomic.AtomicInteger value = new java.util.concurrent.atomic.AtomicInteger(0);
io.micrometer.core.instrument.Gauge.builder(APP_NAMESPACE + "_active_operations", value, java.util.concurrent.atomic.AtomicInteger::get)
.tag("operation", op)
.register(meterRegistry);
return value;
}).set(count);
}
}