Documentation
¶
Overview ¶
Package rlmetrics exposes a record-layer StoreTimer (the Go port of Java's FDBStoreTimer) in the Prometheus text exposition format, ready to scrape — with zero dependencies.
Usage:
timer := recordlayer.NewStoreTimer()
db.SetTimer(timer) // every context now records into it
http.Handle("/metrics/recordlayer", rlmetrics.Handler(timer))
This is the record-layer counterpart to pkg/fdbgo/fdbmetrics, which covers the FDB client's transaction counters. The two are complementary and deliberately separate: fdbmetrics answers "what is the cluster doing to my transactions" (conflicts, retries, GRV latency), rlmetrics answers "what is my application asking the record layer to do" (records saved, indexes scanned, time in commit). An operator wants both, on the same handler mux.
Java has no equivalent. Its only StoreTimer export surfaces are getKeysAndValues() into log messages (StoreTimer.java:747-780) and the subclass hook that fdb-relational uses to mirror events into a Dropwizard MetricRegistry (MetricRegistryStoreTimer.java) — and nothing bridges that registry to the Prometheus CollectorRegistry the relational server already runs (RelationalServer.java:171 wires only gRPC interceptor metrics). So there is no Java behaviour to conform to here; the constraint that does apply is the one on the events themselves, which are a 1:1 port of FDBStoreTimer's taxonomy. StoreTimer.KeysAndValues() is the Java-shaped surface if you want the log-key form instead.
Deliberately NOT a prometheus.Collector, for the same reason fdbmetrics is not: it would pull github.com/prometheus/client_golang into the module. A user who wants a Collector writes a trivial one over the snapshot.
Index ¶
Constants ¶
const Namespace = "fdb_recordlayer_"
Namespace prefixes every metric this package emits. Separate from fdbmetrics' fdb_client namespace because the two measure different layers of the same stack and an operator must be able to tell at a glance which one a number came from.
Variables ¶
This section is empty.
Functions ¶
func Handler ¶
func Handler(src TimerSource) http.Handler
Handler returns an http.Handler that renders the timer's counters in the Prometheus text exposition format (text/plain; version=0.0.4).
A nil *recordlayer.StoreTimer is a valid source: Snapshot returns nil on a nil receiver, and an empty exposition is the honest answer for a database nobody installed a timer on.
Do not call StoreTimer.Reset on a timer being scraped. Everything here is exported as a monotonic counter, and a reset makes the series jump backwards — Prometheus reads that as a process restart and discounts the interval. Reset belongs to tests and to one-shot measurement, not to a live endpoint; a scraper computes its own deltas and needs the running totals to do it.
func WriteText ¶
func WriteText(w io.Writer, snap map[string]*recordlayer.CounterSnapshot) error
WriteText renders one snapshot in the Prometheus text exposition format. Returns the first writer error (the exposition itself cannot fail).
Only events the timer has ACTUALLY recorded appear. That is a property of StoreTimer — counters are created on first use — and it is the right one to preserve rather than paper over with a registry of all declared events: Go declares several events Java populates from its instrumented transaction wrappers (Counts.READS, WRITES, BYTES_READ, BYTES_WRITTEN — see InstrumentedReadTransaction.java:123, InstrumentedTransaction.java:91-92) that no Go call site increments yet. Emitting those as a flat 0 would tell an operator "zero reads happened" when the truth is "reads are not counted", and those two claims call for opposite responses.
Output is sorted by metric name so a diff between two scrapes is readable and the tests can pin whole-output shape rather than substring presence.
Types ¶
type TimerSource ¶
type TimerSource interface {
Snapshot() map[string]*recordlayer.CounterSnapshot
}
TimerSource is the part of *recordlayer.StoreTimer this package consumes — accepted as an interface so tests and wrappers can substitute snapshots.