pub struct AccessLogHook { /* private fields */ }Expand description
A DispatchHook that writes one JSON line per call to an arbitrary
Write sink. Entries carry the vgi_rpc.access logger name so the
Python validator’s filter (.logger == "vgi_rpc.access") matches.
Two modes:
AccessLogHook::new/AccessLogHook::to_stderrwrite synchronously on the dispatch thread (acceptable for stderr or in-memory test sinks).AccessLogHook::bufferedqueues into a bounded mpsc channel and drains on a background thread; on overflow it drops the entry and bumps a counter rather than blocking dispatch.
Implementations§
Source§impl AccessLogHook
impl AccessLogHook
Sourcepub fn new<W: Write + Send + 'static>(
sink: W,
server_version: impl Into<String>,
) -> Arc<Self> ⓘ
pub fn new<W: Write + Send + 'static>( sink: W, server_version: impl Into<String>, ) -> Arc<Self> ⓘ
Create an access log hook that writes synchronously to sink.
Suitable for stderr or in-memory sinks; for production file I/O
prefer AccessLogHook::buffered to keep dispatch threads off
the disk path.
Sourcepub fn with_verbose(self: Arc<Self>, verbose: bool) -> Arc<Self> ⓘ
pub fn with_verbose(self: Arc<Self>, verbose: bool) -> Arc<Self> ⓘ
Return a new Arc<AccessLogHook> with verbose request-data
emission enabled. Mirrors Python’s
_access_logger.isEnabledFor(logging.DEBUG) behaviour where
the full base64-encoded request batch is included verbatim
rather than being elided via truncated: "payload_omitted".
Sourcepub fn with_max_record_bytes(self: Arc<Self>, max_bytes: usize) -> Arc<Self> ⓘ
pub fn with_max_record_bytes(self: Arc<Self>, max_bytes: usize) -> Arc<Self> ⓘ
Cap each record at max_bytes, shedding optional fields to fit;
0 disables the cap. Pair it with shipper configs that raise their
per-line limits to match (Vector’s max_line_bytes, Fluent Bit’s
Buffer_Max_Size) — a line above the shipper’s ceiling is dropped
without a word.
Sourcepub fn with_sample_rate(self: Arc<Self>, rate: f64) -> Result<Arc<Self>>
pub fn with_sample_rate(self: Arc<Self>, rate: f64) -> Result<Arc<Self>>
Keep only rate of the successful calls.
Three properties separate a sampler that helps from one that quietly costs someone an incident, and all three are enforced here:
- Errors are never sampled. A rate below 1 exists because successful calls are repetitive, which is exactly what failures are not; a consumer has to be able to read a falling error count as a fix landing rather than as the dice going the other way.
- The decision is deterministic, per call. It is keyed on
stream_idwhen present andrequest_idotherwise, so every record of one stream shares its init’s fate. Random per-record sampling shreds a multi-record call into fragments indistinguishable from data loss, and the calls likeliest to be split are the long streams most worth studying. - The rate rides on every kept record as
sample_rate, because a consumer scaling counts must divide by it, and a rate discoverable only from a deployment’s flags is one that gets guessed wrong.
§Errors
Returns a ValueError when rate is outside 0.0..=1.0. Failing
here rather than at the first request is the point: 100 meaning
“100%” would otherwise silently log everything, and a negative rate
silently nothing.
Sourcepub fn with_claim_redactor(
self: Arc<Self>,
redactor: ClaimRedactor,
) -> Arc<Self> ⓘ
pub fn with_claim_redactor( self: Arc<Self>, redactor: ClaimRedactor, ) -> Arc<Self> ⓘ
Replace the redaction policy applied to claims.
Pass no_redaction to disable it — appropriate only for a service
that owns its logs end to end. A redactor that panics fails closed:
the claims are dropped from the record rather than emitted raw.
Sourcepub fn buffered<W: Write + Send + 'static>(
sink: W,
server_version: impl Into<String>,
capacity: usize,
) -> Arc<Self> ⓘ
pub fn buffered<W: Write + Send + 'static>( sink: W, server_version: impl Into<String>, capacity: usize, ) -> Arc<Self> ⓘ
Create a hook that writes asynchronously: the dispatch thread
pushes a formatted line into a bounded channel of capacity
entries and a background thread drains it into sink.
The queue is bounded and a full queue drops rather than blocks:
an unbounded queue turns a stalled disk into an OOM, and a blocking
send reintroduces exactly the latency the thread was meant to remove.
What makes dropping acceptable rather than silent corruption is that
it is reported — the next record through carries dropped_records,
so the loss shows up in the log itself and not only in a counter
nobody exports.
This trades durability. With a synchronous sink, a record on disk means the call completed; here a crash loses whatever is still queued. Right for high throughput, wrong for audit — hence opt-in.
The writer thread exits when the hook is dropped (sender closes).
Sourcepub fn to_stderr(server_version: impl Into<String>) -> Arc<Self> ⓘ
pub fn to_stderr(server_version: impl Into<String>) -> Arc<Self> ⓘ
Convenience: write access logs to stderr synchronously (one JSON line per entry).
Sourcepub fn dropped_count(&self) -> u64
pub fn dropped_count(&self) -> u64
Records dropped since the last one that made it onto the queue.
Always zero for synchronous hooks; reset once the count has been
reported in-band as dropped_records.
Trait Implementations§
Source§impl DispatchHook for AccessLogHook
impl DispatchHook for AccessLogHook
Source§fn on_dispatch_start(&self, _info: &DispatchInfo) -> HookToken
fn on_dispatch_start(&self, _info: &DispatchInfo) -> HookToken
on_dispatch_end.