Eventline
Causality-aware execution journal for systems-level programs.
Eventline records what happened, when it happened, and in what causal context — without assuming logging, tracing, or telemetry semantics. Built for daemons, CLI tools, and eventually Linux distributions.
Features
- Append-only journal — never mutates or removes records
- Scoped execution — track outcomes and durations
- Event kinds — Info, Warning, Error, Debug (separate from outcomes)
- Runtime log levels — filter events globally (Debug, Info, Warning, Error)
- Flexible filtering — by outcome, depth, duration, event kind, message content
- Human-readable output — Unicode bullets, optional color coding
- High-throughput batching —
JournalBufferfor batch writes - Dual-layer API — pure core + optional runtime facade
- Deterministic replay — safe concurrent reads, reliable audit trails
Quick Start
Runtime API (Fire-and-Forget)
For applications and daemons:
use runtime;
use ;
use ;
Core Journal API (Explicit Control)
For libraries or embedded systems:
use ;
let mut journal = new;
journal.scoped;
journal.write_to_file.unwrap;
Architecture
┌─────────────┐
│ Macros │ event_info!(), event_scope!()
└──────┬──────┘
↓
┌─────────────┐
│ Runtime │ Global, thread-safe facade (optional)
└──────┬──────┘
↓
┌─────────────┐
│ Journal │ Pure, append-only core (always available)
└─────────────┘
Core Layer (always available):
- Journal — Pure data structure
- Scope — Logical units of work
- Record — Individual events
- Filter — Composable criteria
Runtime Layer (optional):
- runtime — Global facade
- Macros — Zero-overhead convenience
- Log levels — filter events at runtime
Key Concepts
Outcomes vs Events
Event kinds describe what happened:
Info— routine progressWarning— unexpected but recoverableError— something went wrongDebug— verbose diagnostics
Scope outcomes describe the result:
Success— completed normallyFailure— completed with errorsAborted— interrupted by panic
This separation enables:
- Warnings during successful operations
- Errors that don't cause failure
- Clear diagnostics vs results
Filtering at Render Time
Filtering happens when reading the journal, not when writing:
use ;
// Show only failed scopes
let filter = scope;
// Show only warnings and errors
let filter = event;
// Complex: failed scopes with deep nesting
let filter = scope;
render_journal_tree;
Benefits:
- Zero overhead when not filtering
- Complete journal always preserved
- Multiple views from same data
- Composable with AND, OR, NOT
Advanced Usage
Batched Logging
let mut journal = new;
let mut buffer = journal.create_buffer;
let scope = buffer.enter_scope;
for item in items
buffer.exit_scope;
journal.flush_buffer; // Atomic ID rebase
Custom Output
use JournalWriter;
use io;
let mut file = create?;
new
.with_bullet
.write_to_all?;
Nested Scopes
scoped;
Design Principles
Append-Only Invariant
Once written, entries are never modified or removed:
- Deterministic replay
- Safe concurrent reads
- Reliable audit trails
Separation of Concerns
- Journal — Pure data
- JournalWriter — Rendering policy
- JournalBuffer — Batching mechanism
- Filter — Selection criteria
- Runtime — Optional global facade
Test-Friendly
Installation
[]
= "0.1.1"
Roadmap
- Custom formatters (JSON, binary)
- Structured data (key-value pairs)
- Zero-copy query interface
- Tag-based filtering
- Async runtime support
Philosophy
Eventline is designed to:
- Be intuitive for humans reading logs
- Enable deterministic replay of execution
- Serve as foundation for distribution-wide logging
- Make debugging and monitoring pleasant
It is not:
- A metrics system (use Prometheus)
- A distributed tracing backend
- A replacement for structured logging (yet)
Focuses on local, human-readable execution traces with optional runtime log filtering.
License
MIT