Skip to content

Benchmarks

Aires is designed for high-throughput observability with minimal overhead. Here are real benchmark results comparing Aires against the two most popular Node.js logging libraries.

  • Hardware: Apple M4 Max
  • Runtime: Bun 1.2.x
  • Rust: 1.94.1 (edition 2024)
  • Methodology: All JS benchmarks write to /dev/null to isolate serialization cost from disk I/O. 100K iterations with 10K warmup. Rust benchmarks use Criterion with statistical analysis.
log.info("hello world")
Libraryns/opops/secvs fastest
aires (js)5361.86Mbaseline
winston9741.03M1.8x slower
pino1,094914K2.0x slower
log.info("request completed", { userId: "user-abc", traceId: "trace-123", path: "/api/agents" })
Libraryns/opops/secvs fastest
aires (js)7531.33Mbaseline
pino1,578634K2.1x slower
winston2,521397K3.3x slower
log.info("request completed", {
  userId: "user-abc", traceId: "trace-123", sessionId: "sess-xyz",
  method: "POST", path: "/agents/list", status: "200",
  durationMs: "42", requestSize: "256"
})
Libraryns/opops/secvs fastest
aires (js)6471.54Mbaseline
pino1,654605K2.6x slower
winston2,546393K3.9x slower
const child = log.with({ userId: "user-abc", sessionId: "sess-xyz" })
child.info("request", { path: "/api" })
Libraryns/opops/secvs fastest
aires (js)5961.68Mbaseline
pino child1,315760K2.2x slower
winston child1,394717K2.3x slower
log.error("unhandled error", { err, traceId: "t-1" })
Libraryns/opops/secvs fastest
aires (js)1,731578Kbaseline
pino2,237447K1.3x slower
winston3,633275K2.1x slower

These measure the Rust core directly, via Criterion with statistical analysis.

OperationTimeThroughput
Event creation212 ns4.7M events/sec
JSON serialize (single event)200 ns5.0M events/sec
Proto encode (single event)62 ns16.1M events/sec
Proto encode (256 batch, heap)17.4 us14.7M events/sec
Proto encode (256 batch, arena)42.9 us5.9M events/sec
Batch build (256 events)46.6 us5.5M batches/sec

Proto encoding is 3.2x faster than JSON for the same event payload. This is why Aires uses protobuf over gRPC rather than JSON over HTTP.

Arena allocation (arena-alligator) adds overhead for small batches due to setup cost, but provides lock-free concurrent allocation — critical under high thread contention where the global heap allocator becomes the bottleneck.

PathPer-event costEvents/secvs pino
winston (JSON to fd)~2,500 ns400K0.6x
pino (JSON to fd)~1,500 ns670K1.0x
aires JS fallback (JSON to fd)~650 ns1.5M2.3x
aires native (proto to channel)~62 ns16M25x
cd benchmarks
bun install
bun run bench
cargo bench -p aires-sdk

Criterion HTML reports are generated in target/criterion/.

The TypeScript benchmark source is at benchmarks/bench.ts. It measures:

  1. Simple messagelog("hello world")
  2. 3 attributes — message + userId, traceId, path
  3. 8 attributes — full HTTP request log
  4. Scoped logger — pino child, winston child, aires .with()
  5. Error + stack — error object with stack trace serialization

Each workload runs 100K iterations after a 10K warmup. Timing uses Bun.nanoseconds() for sub-microsecond precision. All loggers write to /dev/null to eliminate I/O variance.

The Rust benchmarks are at packages/sdk-rust/benches/ingest.rs, using Criterion for statistical rigor (100 samples per benchmark, outlier detection, confidence intervals).