Why

The usual path for Kafka observability is a JMX exporter sidecar — an extra process per broker, with its own scrape window, its own failure modes, and a metric model that doesn’t quite match what the rest of the stack speaks.

monedula-metrics-reporter removes the sidecar. It plugs into Kafka’s own MetricsReporter interface and pushes metrics directly to an OpenTelemetry collector over OTLP — gRPC or HTTP, your call. Broker context (cluster id, node id) is attached as resource attributes, so the same metric stream works across brokers without per-host wiring.

All export I/O happens on a daemon thread. If the collector is slow or down, nothing reaches the threads Kafka uses to serve traffic.

For the full background — the two metric systems hiding inside Kafka, why imported Grafana dashboards so often show No Data, and how native OTLP untangles it — read Do Kafka metrics have to be so difficult?.

Configure

Drop the shadow jar into $KAFKA_HOME/libs/, then in server.properties:

metric.reporters=dev.monedula.metricsreporter.OtlpMetricReporter
otlp.metric.reporter.endpoint=http://otel-collector:4317
otlp.metric.reporter.transport=grpc

The same plugin works on Kafka clients — register it via metric.reporters on the producer or consumer config and you get the matching client-side stream into the same collector.

A complete demo stack (broker + collector + Prometheus + Grafana) lives under quickstart/ in the repo.

Compatibility

Kafka 3.x and 4.x. Java 17+. Both the modern MetricsReporter SPI and the legacy Yammer registry are wired, so you get coverage of the metrics Kafka emits today without leaving the Yammer ones on the table.