pub struct AuditLogger { /* private fields */ }Expand description
The main audit logger, dispatching events to configured sinks.
Thread-safe and designed for high-throughput operation.
Sinks can be added at any time, even after wrapping in Arc.
§Retention Policy
AuditLogger itself does not enforce a retention policy — it
forwards events to sinks and forgets them. Retention is the
responsibility of each sink:
MemorySink: bounded bymax_capacity(FIFO eviction).WriterSink: appends forever; pair with external log rotation (e.g.logrotate, cloud blob lifecycle rules).TracingSink: inherits the tracing subscriber’s retention.
For production deployments, configure a log rotation / archival
pipeline and monitor the chronix_audit_events_total counter to
ensure events are not silently dropped.
Implementations§
Source§impl AuditLogger
impl AuditLogger
Sourcepub fn with_hmac_key(self, key: Vec<u8>) -> Self
pub fn with_hmac_key(self, key: Vec<u8>) -> Self
Create an audit logger with an HMAC key.
When set, each event is sealed with HMAC-SHA-256 instead of plain SHA-256. An attacker with database write access cannot recompute the hash chain without possessing the key.
Sourcepub fn resume_from(self, last_id: u64, last_hash: Option<String>) -> Self
pub fn resume_from(self, last_id: u64, last_hash: Option<String>) -> Self
Continue an existing chain instead of starting a new one.
A restart used to reset the sequence to 1 and the previous hash to
None, so every restart began a fresh chain in the same file. A
verifier then could not tell a restart from a truncation: both look
like an event whose prev_hash is None in the middle of the log.
Anchoring on the last event already on disk makes the file one
chain across the whole life of the deployment.
Sourcepub fn add_sink(&self, sink: Box<dyn AuditSink>)
pub fn add_sink(&self, sink: Box<dyn AuditSink>)
Add a sink. Can be called at any time, including after
wrapping in Arc.
Sourcepub fn validate_has_durable_sink(&self) -> Result<()>
pub fn validate_has_durable_sink(&self) -> Result<()>
**** Validate that at least one durable audit sink is configured.
Returns Ok(()) if at least one sink reports is_durable() == true.
Returns an error if no durable sinks are present, which means audit
events would be lost on process restart — a compliance violation in
regulated environments.
Call this at startup after configuring all sinks.
Sourcepub fn has_durable_sink(&self) -> bool
pub fn has_durable_sink(&self) -> bool
Check if at least one durable sink is configured.
Sourcepub fn log(&self, event: AuditEvent)
pub fn log(&self, event: AuditEvent)
Log an audit event to all sinks.
Assigns a monotonic sequence number, seals the event into the hash chain, and writes it.
§Sealing and writing are one step
They were two, with the lock released in between — so two concurrent
callers could seal in one order and write in the other, leaving a file
in which B precedes A while B.prev_hash names A. That is
exactly what verify_hash_chain reports as tampering, and it
happened with no write failing and nothing logged: an ordinary pair of
simultaneous requests made a tamper-evident trail permanently
unverifiable. A trail whose whole purpose is to be checkable cannot
have a benign reason to fail its own check, because then no failure of
it means anything.
So the chain lock is held across the emission. Audit events are rare relative to requests, and the file sink serialises on its own mutex anyway, so the lock is not a new bottleneck — it is the existing one, now covering the invariant it always should have.
Sourcepub fn next_sequence(&self) -> u64
pub fn next_sequence(&self) -> u64
Current sequence number (next ID to be assigned).
Sourcepub fn sink_count(&self) -> usize
pub fn sink_count(&self) -> usize
Number of sinks.
Sourcepub fn log_strict(&self, event: AuditEvent) -> Result<()>
pub fn log_strict(&self, event: AuditEvent) -> Result<()>
Strict audit logging — fail-closed mode for regulated environments.
Unlike log, this attempts all sinks even when some
fail, and returns a PartialDelivery
error if any sink could not emit. This gives the caller full visibility
into which sinks succeeded vs failed so it can make an informed decision
on whether to abort the protected operation.
Sourcepub fn flush_strict(&self) -> Result<()>
pub fn flush_strict(&self) -> Result<()>
Strict flush — tries all sinks, reports partial failures.
Use this together with log_strict for
fail-closed audit contexts where all buffered events must be
durably persisted before acknowledging the protected operation.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for AuditLogger
impl !RefUnwindSafe for AuditLogger
impl !UnwindSafe for AuditLogger
impl Send for AuditLogger
impl Sync for AuditLogger
impl Unpin for AuditLogger
impl UnsafeUnpin for AuditLogger
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more