package nu.marginalia.status; import io.prometheus.client.Counter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.time.Duration; import java.time.Instant; import java.util.function.Supplier; public class StatusMetric { private final String name; private final Supplier checker; // We also push the metrics to Prometheus for additional statistics and monitoring private static final Counter successCounter = Counter.build("external_status_metric_success", "Status Metric Success") .labelNames("name") .register(); private static final Counter failureCounter = Counter.build("external_status_metric_failure", "Status Metric Failure") .labelNames("name") .register(); private static final Logger logger = LoggerFactory.getLogger(StatusMetric.class); public StatusMetric(String name, Supplier checker) { this.name = name; this.checker = checker; } public String getName() { return name; } public MeasurementResult update() { long startTime = System.nanoTime(); Instant now = Instant.now(); try { if (checker.get()) { long endTime = System.nanoTime(); successCounter.labels(name).inc(); return new MeasurementResult.Success(name, now, Duration.ofNanos(endTime - startTime)); } } catch (Exception e) { logger.error("Failed to check status metric: " + name, e); } failureCounter.labels(name).inc(); return new MeasurementResult.Failure(name, now); } public sealed interface MeasurementResult { String name(); Instant when(); record Success(String name, Instant when, Duration callDuration) implements MeasurementResult {} record Failure(String name, Instant when) implements MeasurementResult {} } }