Telemetry

Struct Telemetry 

Source
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: Histogram

How long one fold step took.

§view: Histogram

How long rendering a view took. The dominant cost until Phase 3 (docs/19 §19.4 item 3).

§diff: Histogram

How long the diff between two views took.

§append: Histogram

How long an append to the log store took — the substrate’s latency, not the program’s.

§snapshot: Histogram

How long a snapshot took.

§replay: Histogram

How long a cold replay took, and over how many events.

§rejected: Counter

Proposals rejected by validate. Rejections never become events, so nothing in the log records that anyone tried.

§deduplicated: Counter

Proposals dropped as duplicates by the idempotency key.

§append_failures: Counter

Appends that failed. If this is non-zero, the log is missing something the program believed.

§snapshot_failures: Counter

Snapshots that failed. Recoverable — the log is still the truth — but slower to recover.

§bad_messages: Counter

Client messages that did not parse.

§navigations: Counter

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: Counter

Connections 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: Counter

Proposals 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: Gauge

The seq the process has folded to. A gauge in spirit; stored so the dashboard has it without touching the app.

§shared_arranged: Gauge

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: Gauge

Arrangement 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.

§shared_retained: Gauge

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.

§shared_releases: Counter

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

Source

pub fn log( &self, level: &'static str, target: &str, message: String, seq: Option<u64>, )

Source

pub fn records(&self, limit: usize) -> Vec<Record>

The most recent records, newest first.

Source

pub fn snapshot(&self) -> J

Everything, as the dashboard’s JSON. Not OTLP: this is shaped for a table on a screen.

Source

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.

Source

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_:]*, so beck.events.appended cannot 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.

Source

pub fn otlp_logs(&self, service: &str, limit: usize) -> J

OTLP/HTTP JSON for logs — the body of a POST to /v1/logs.

Trait Implementations§

Source§

impl Debug for Telemetry

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Telemetry

Source§

fn default() -> Telemetry

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more