You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Built-in metrics exporter: push node/cluster stats as ss4o docs to a monitoring cluster via _bulk
#1261
Add a built-in, opt-in metrics exporter: a background task that periodically collects xerj's own node/cluster/index stats, serializes them as ss4o (Simple Schema for Observability) documents, and pushes them via _bulk to an external ES/OpenSearch-compatible "monitoring" target (or another xerj node).
Prior art: I built the same thing for OpenSearch as a plugin — https://github.com/Vinz2168/opensearch-monitoring-exporter (polls Health/NodesStats/IndicesStats/ClusterState, writes ss4o docs into ss4o_metrics-opensearch-yyyy.MM.dd on a dedicated monitoring cluster, no Data Prepper / OTel Collector hop). In xerj it would be engine code, not a plugin.
Why: today xerj exposes /v1/metrics (Prometheus text, pull) and _nodes/stats / _cluster/health (pull). Teams that already use OpenSearch Dashboards' Observability → Metrics UI (or another xerj node) as their monitoring store currently need a scraper + pipeline to land those numbers there. A push exporter writes them durably in the shape that UI already reads, with nothing extra to deploy.
What already exists (checked in the tree)
Need
Existing piece
Push _bulk to an external target with bounded batches, capped/jittered backoff, per-item read-back, healthy stats
WalTapConfig (xerj-common/src/config.rs) + PUT /_xerj/wal_tap
Node/cluster numbers
es_compat::nodes_stats, es_compat::cluster_health — but computed inline in the HTTP handlers
Internal counters/gauges
Prometheus registry in xerj-common/src/metrics.rs (served at /v1/metrics)
wal_tap alone is not the answer — it replicates WAL contents (documents), not metrics — but its delivery half is reusable as-is.
Sketch
Extract collectors: move the bodies of nodes_stats / cluster_health (and per-index stats) into pure fn build_*(&AppState) -> Value, called by both the HTTP handlers and the exporter — one source of truth, no drift between what _nodes/stats says and what gets exported.
metrics_export module: tokio task, every interval_secs → collect → ss4o docs → shared _bulk sender factored out of wal_tap. Bounded queue, drop-oldest with a counter when the target is down (memory must not grow).
ss4o mapping, two shapes:
one doc per Prometheus-registry sample (name, kind, value, unit, attributes@… with .→@ like Data Prepper) — the most faithful ss4o/OTel shape;
category docs (cluster_health, node_os, node_fs, node_indices, per-index) for the _nodes/stats-style data.
Config[metrics_export]: enabled (default false), target_url, target_auth, index (default ss4o_metrics-xerj-%{yyyy.MM.dd}), interval_secs, max_batch_docs, request_timeout_secs, max_retry_backoff_secs; runtime PUT/GET/DELETE /_xerj/metrics_export + /_stats, superuser-only like wal_tap (it is an outbound channel to an arbitrary host).
TLS: wal_tap currently has no custom CA / client cert. Add ca_cert_path (PEM) and client_identity_path (mTLS) to the shared sender — wal_tap gets them for free.
Index template: idempotent PUT _index_template for the ss4o mapping on the target at arm time (opt-out flag).
Honest differences vs the OpenSearch plugin
No JVM: heap/GC/JVM-thread metrics don't exist. Export process RSS, OS threads, rayon/tokio pool stats under their real names — not relabelled as "heap" (note: _nodes/stats currently fills heap_used_percent with RSS/host-memory).
RSS/meminfo/CPU are read from /proc → Linux-only; on macOS those fields are 0/estimated today. The exporter should omit, not zero, what it can't measure.
No keystore: secrets via env var or file, same as wal_tap.target_auth.
Single-node: no "which node ships cluster-level docs" election problem.
Open questions for the maintainer
Is a push exporter in scope for the engine, or should this stay an external tool (e.g. a xerj subcommand / companion binary scraping /v1/metrics)?
Preferred doc shape: per-sample ss4o, category docs, or both?
OK to factor the _bulk delivery out of wal_tap into a shared module (and add CA/mTLS there) as a prerequisite PR?
Should the extraction of nodes_stats/cluster_health into pure functions land first as a standalone refactor?
Happy to implement once the shape is agreed.
Drafted with an AI coding agent (Claude Code) after reading the xerj source and the OpenSearch plugin; file pointers above were verified in the tree, nothing has been implemented or benchmarked yet.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Proposal
Add a built-in, opt-in metrics exporter: a background task that periodically collects xerj's own node/cluster/index stats, serializes them as ss4o (Simple Schema for Observability) documents, and pushes them via
_bulkto an external ES/OpenSearch-compatible "monitoring" target (or another xerj node).Prior art: I built the same thing for OpenSearch as a plugin — https://github.com/Vinz2168/opensearch-monitoring-exporter (polls Health/NodesStats/IndicesStats/ClusterState, writes ss4o docs into
ss4o_metrics-opensearch-yyyy.MM.ddon a dedicated monitoring cluster, no Data Prepper / OTel Collector hop). In xerj it would be engine code, not a plugin.Why: today xerj exposes
/v1/metrics(Prometheus text, pull) and_nodes/stats/_cluster/health(pull). Teams that already use OpenSearch Dashboards' Observability → Metrics UI (or another xerj node) as their monitoring store currently need a scraper + pipeline to land those numbers there. A push exporter writes them durably in the shape that UI already reads, with nothing extra to deploy.What already exists (checked in the tree)
_bulkto an external target with bounded batches, capped/jittered backoff, per-item read-back,healthystatswal_tap—engine/crates/xerj-engine/src/wal_tap.rsWalTapConfig(xerj-common/src/config.rs) +PUT /_xerj/wal_tapes_compat::nodes_stats,es_compat::cluster_health— but computed inline in the HTTP handlersxerj-common/src/metrics.rs(served at/v1/metrics)wal_tapalone is not the answer — it replicates WAL contents (documents), not metrics — but its delivery half is reusable as-is.Sketch
nodes_stats/cluster_health(and per-index stats) into purefn build_*(&AppState) -> Value, called by both the HTTP handlers and the exporter — one source of truth, no drift between what_nodes/statssays and what gets exported.metrics_exportmodule: tokio task, everyinterval_secs→ collect → ss4o docs → shared_bulksender factored out ofwal_tap. Bounded queue, drop-oldest with a counter when the target is down (memory must not grow).name,kind,value,unit,attributes@…with.→@like Data Prepper) — the most faithful ss4o/OTel shape;cluster_health,node_os,node_fs,node_indices, per-index) for the_nodes/stats-style data.[metrics_export]:enabled(default false),target_url,target_auth,index(defaultss4o_metrics-xerj-%{yyyy.MM.dd}),interval_secs,max_batch_docs,request_timeout_secs,max_retry_backoff_secs; runtimePUT/GET/DELETE /_xerj/metrics_export+/_stats, superuser-only likewal_tap(it is an outbound channel to an arbitrary host).wal_tapcurrently has no custom CA / client cert. Addca_cert_path(PEM) andclient_identity_path(mTLS) to the shared sender —wal_tapgets them for free.PUT _index_templatefor the ss4o mapping on the target at arm time (opt-out flag).Honest differences vs the OpenSearch plugin
_nodes/statscurrently fillsheap_used_percentwith RSS/host-memory)./proc→ Linux-only; on macOS those fields are 0/estimated today. The exporter should omit, not zero, what it can't measure.wal_tap.target_auth.Open questions for the maintainer
xerjsubcommand / companion binary scraping/v1/metrics)?_bulkdelivery out ofwal_tapinto a shared module (and add CA/mTLS there) as a prerequisite PR?nodes_stats/cluster_healthinto pure functions land first as a standalone refactor?Happy to implement once the shape is agreed.
Drafted with an AI coding agent (Claude Code) after reading the xerj source and the OpenSearch plugin; file pointers above were verified in the tree, nothing has been implemented or benchmarked yet.
All reactions