pub struct Telemetry {Show 23 fields
pub fold: Histogram,
pub view: Histogram,
pub diff: Histogram,
pub append: Histogram,
pub snapshot: Histogram,
pub replay: Histogram,
pub rejected: Counter,
pub deduplicated: Counter,
pub append_failures: Counter,
pub snapshot_failures: Counter,
pub bad_messages: Counter,
pub navigations: Counter,
pub unauthenticated: Counter,
pub throttled: Counter,
pub events_appended: Counter,
pub patch_frames: Counter,
pub patch_bytes: Counter,
pub sessions: Gauge,
pub head: Gauge,
pub shared_arranged: Gauge,
pub session_arranged: Gauge,
pub shared_retained: Gauge,
pub shared_releases: Counter,
/* private fields */
}Expand description
The instruments.
One value, reached through telemetry, because a metric registry that has to be threaded
through every call site gets threaded through some of them.
Fields§
§fold: HistogramHow long one fold step took.
view: HistogramHow long rendering a view took. The dominant cost until Phase 3 (docs/19 §19.4 item 3).
diff: HistogramHow long the diff between two views took.
append: HistogramHow long an append to the log store took — the substrate’s latency, not the program’s.
snapshot: HistogramHow long a snapshot took.
replay: HistogramHow long a cold replay took, and over how many events.
rejected: CounterProposals rejected by validate. Rejections never become events, so nothing in the log
records that anyone tried.
deduplicated: CounterProposals dropped as duplicates by the idempotency key.
append_failures: CounterAppends that failed. If this is non-zero, the log is missing something the program believed.
snapshot_failures: CounterSnapshots that failed. Recoverable — the log is still the truth — but slower to recover.
bad_messages: CounterClient messages that did not parse.
Routes taken on a live subscription — a nav frame that moved the client somewhere new.
Counted because it is the one interaction whose cost differs between the two modes by construction: in Mode A it is a render and a patch on the server, and in Mode B it is a message the server answers with nothing at all.
unauthenticated: CounterConnections refused because the identity did not verify.
Counted separately from rejected, which is validate refusing a command: one is “who
are you” and the other is “you may not do that”, and an operator watching for an attack
needs to tell them apart.
throttled: CounterProposals refused because the actor was over F3’s write quota.
A third counter beside rejected and unauthenticated, for the same reason those two are
apart: “you may not do that”, “who are you” and “not that often” are three different things
for an operator watching an attack, and one number covering all three tells them nothing.
events_appended: Counter§patch_frames: Counter§patch_bytes: Counter§sessions: Gauge§head: GaugeThe seq the process has folded to. A gauge in spirit; stored so the dashboard has it
without touching the app.
Arrangement entries held by the one shared dataflow: the operators that do not read the session, maintained once however many subscribers there are (docs/23).
Entries rather than bytes. Bytes would need Engine::footprint, which walks the accumulator
to charge shared structure to the fold — right for a report, far too expensive to sample on
a live process. Entries are O(operators) to read and they are the number that scales.
session_arranged: GaugeArrangement entries held by connected subscriptions, between them.
This is the one that multiplies by the fanout, and putting the two side by side is the whole
operational question: shared_arranged is paid once, session_arranged is paid per
connection. A program whose second number dwarfs the first has its cut in the wrong place.
Versions of change history the shared dataflow is keeping for subscribers that are behind.
Bounded above by the configured retention depth and below by the laggiest connected subscriber, so on a healthy fanout it sits at 1 and a rising number means renders are not keeping up with events. That makes it a lag signal rather than a memory one, which is the more useful reading of the same number.
How many times the shared dataflow gave up its arrangements because nothing was subscribed.
Each one is a cold start charged to whichever subscriber reconnects first. A process whose
releases track its connection count is one whose clients are flapping, and is the case for
turning AppConfig::retention.release_when_idle off.
Implementations§
Source§impl Telemetry
impl Telemetry
pub fn log( &self, level: &'static str, target: &str, message: String, seq: Option<u64>, )
Sourcepub fn snapshot(&self) -> J
pub fn snapshot(&self) -> J
Everything, as the dashboard’s JSON. Not OTLP: this is shaped for a table on a screen.
Sourcepub fn otlp_metrics(&self, service: &str) -> J
pub fn otlp_metrics(&self, service: &str) -> J
OTLP/HTTP JSON for metrics — the body of a POST to /v1/metrics.
Field names and the numeric enums (aggregationTemporality: 2 is CUMULATIVE) are the
specification’s, so an ordinary collector accepts this without a Beck-specific receiver.
Sourcepub fn openmetrics(&self, service: &str) -> String
pub fn openmetrics(&self, service: &str) -> String
OpenMetrics 1.0.0 text, for a Prometheus scraper — docs/12 §12.8’s chartered row.
The same numbers Telemetry::otlp_metrics exports, read off the same tables, in the other
exposition format the ecosystem speaks. It adds no measurement: every value is already
recorded on the serving path, which is what makes a second export cheap rather than a second
cost.
Three things the format requires and the JSON does not, so they are decided here:
- A name is
[a-zA-Z_:][a-zA-Z0-9_:]*, sobeck.events.appendedcannot be spelled. The dots become underscores, which is the ecosystem’s own transliteration of an OTLP name. - A counter’s name ends
_total. OpenMetrics requires it; the older Prometheus text format merely prefers it, so satisfying the stricter reader satisfies both. - Durations are seconds. The histograms hold microseconds and Prometheus’s convention is
base units, so the values are divided by a million and the names end
_seconds. The boundary is unchanged: a bucket holding observations at or below 1 µs holds the same ones at or below 1e-6 s.
# UNIT and # EOF are OpenMetrics lines an older 0.0.4 parser reads as comments, so one
body serves both readers rather than content-negotiating between them.