hermod
Rust implementation of the hermod trace-forward protocol. Allows Rust applications (such as alternative Cardano nodes and tooling) to forward structured traces to a hermod-tracer acceptor and to act as a trace acceptor themselves.
Features
- Wire-compatible: Byte-identical CBOR encoding to the Haskell
hermod-tracingimplementation - Both roles: Ship as a forwarder or receive as an acceptor
- Async I/O: Built on Tokio for high-performance async networking
- Tracing integration: Works with the Rust
tracingecosystem viahermod::tracer - Dispatcher: Route, filter, and rate-limit traces before forwarding
- Automatic reconnection: Exponential backoff on connection failure
- Standalone binary:
hermod-acceptorbinary for drop-in use with any forwarder
Architecture
Your Rust app
│ tracing::info!("...")
▼
hermod::tracer — tracing subscriber that captures Rust log events
│
▼
hermod::dispatcher — filter/route/rate-limit (optional)
│
▼
hermod::forwarder — CBOR-encodes and sends via Unix socket
│ (trace-forward protocol over Ouroboros Network mux)
▼
hermod-tracer acceptor — Haskell or hermod-acceptor binary
Protocol Messages
The trace-forward protocol uses three CBOR-encoded messages:
| Message | Wire format | Direction |
|---|---|---|
MsgTraceObjectsRequest |
array(3)[1, blocking: bool, array(2)[0, count: u16]] |
Acceptor → Forwarder |
MsgTraceObjectsReply |
array(2)[3, array(N)[TraceObject...]] |
Forwarder → Acceptor |
MsgDone |
array(1)[2] |
Acceptor → Forwarder |
TraceObject Fields
| Field | Type | Description |
|---|---|---|
to_human |
Option<String> |
Human-readable text (optional) |
to_machine |
String |
Machine-readable JSON |
to_namespace |
Vec<String> |
Hierarchical namespace, e.g. ["node", "chain"] |
to_severity |
Severity |
Debug / Info / Notice / Warning / Error / Critical / Alert / Emergency |
to_details |
DetailLevel |
DMinimal / DNormal / DDetailed / DMaximum |
to_timestamp |
DateTime<Utc> |
UTC timestamp (CBOR tag 1000) |
to_hostname |
String |
Source hostname |
to_thread_id |
String |
Source thread ID |
Usage
As a Forwarder (sending traces)
use ;
use HermodTracerBuilder;
use PathBuf;
use info;
async
Sending TraceObjects Directly
use ;
use ;
use Utc;
let config = default;
let forwarder = new;
let handle = forwarder.handle;
spawn;
handle.send.await?;
As an Acceptor (receiving traces)
use ;
use PathBuf;
let config = AcceptorConfig ;
let = new;
spawn;
while let Some = handle.recv.await
Standalone Acceptor Binary
# Print all received traces as JSON to stdout
Building
Testing
See TESTING.md for conformance test details.
Wire Protocol Compatibility
This implementation maintains byte-level compatibility with the Haskell hermod-tracing library:
- Same CBOR encoding for all messages and types
- Haskell Generic Serialise conventions: product types as
array(N+1)[constructor_index, fields...], nullary enum variants asarray(1)[constructor_index] UTCTimeencoded as CBOR tag 1000 +map(2){1: i64_secs, -12: u64_psecs}(picoseconds)- Indefinite-length CBOR arrays for Haskell
[a](non-empty lists)
License
Apache-2.0