Observability
Health checks
app.use(HealthMiddleware.builder()
.path("/health")
.check("db", () -> dataSource.getConnection().isValid(1))
.build());
GET /health → 200 {"status":"UP","checks":{"db":"UP"}}, or 503 with the
failing checks marked DOWN.
Metrics
MetricsMiddleware records method, matched route pattern (/users/{id},
not the raw path — bounded cardinality), status and duration through the
MetricsCollector SPI.
// dependency-free, expose however you like
InMemoryMetricsCollector metrics = new InMemoryMetricsCollector();
app.use(new MetricsMiddleware(metrics));
app.get("/metrics", ctx -> ctx.json(metrics.snapshot()));
// or Micrometer (ligero-metrics-micrometer) for Prometheus/Datadog/...
MeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
app.use(new MetricsMiddleware(new MicrometerMetricsCollector(registry)));
Access logs
app.use(new RequestLoggingMiddleware()); // GET /users -> 200 (431 µs)
app.use(RequestLoggingMiddleware.json()); // {"method":"GET","path":"/users","status":200,...}
The JSON form includes the request id when RequestIdMiddleware runs first.
Distributed tracing
Tracing is vendor-neutral by design: the core defines a Tracer SPI and a
TracingMiddleware; the client decides the backend. The first adapter is
ligero-otel (OpenTelemetry) — New Relic, Datadog, Jaeger and friends work
through it via the OTel SDK/agent exporters, or can implement the SPI directly.
implementation 'com.ligero:ligero-otel:0.2.0-SNAPSHOT'
// With the OTel Java agent (or SDK autoconfigure), ServiceLoader finds the tracer:
app.use(TracingMiddleware.fromServiceLoader());
// Or wire an explicit SDK:
app.use(new TracingMiddleware(new OtelTracer(openTelemetrySdk)));
Per request you get a SERVER span that:
- joins the incoming W3C
traceparent(distributed traces across services), - is named by the matched route pattern (
GET /users/{id}— bounded cardinality), - carries
http.request.method,url.path,http.route,http.response.status_code, - records exceptions and marks the span as
ERRORon failures, - exposes its trace id as the
traceIdcontext attribute for log correlation.
Without any tracing backend, RequestIdMiddleware alone still parses
traceparent and exposes traceId for logs.