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.
Environment
Section titled “Environment”- Hardware: Apple M4 Max
- Runtime: Bun 1.2.x
- Rust: 1.94.1 (edition 2024)
- Methodology: All JS benchmarks write to
/dev/nullto isolate serialization cost from disk I/O. 100K iterations with 10K warmup. Rust benchmarks use Criterion with statistical analysis.
TypeScript: Aires vs Pino vs Winston
Section titled “TypeScript: Aires vs Pino vs Winston”Simple message
Section titled “Simple message”| Library | ns/op | ops/sec | vs fastest |
|---|---|---|---|
| aires (js) | 536 | 1.86M | baseline |
| winston | 974 | 1.03M | 1.8x slower |
| pino | 1,094 | 914K | 2.0x slower |
Message + 3 attributes
Section titled “Message + 3 attributes”| Library | ns/op | ops/sec | vs fastest |
|---|---|---|---|
| aires (js) | 753 | 1.33M | baseline |
| pino | 1,578 | 634K | 2.1x slower |
| winston | 2,521 | 397K | 3.3x slower |
Message + 8 attributes (HTTP request log)
Section titled “Message + 8 attributes (HTTP request log)”| Library | ns/op | ops/sec | vs fastest |
|---|---|---|---|
| aires (js) | 647 | 1.54M | baseline |
| pino | 1,654 | 605K | 2.6x slower |
| winston | 2,546 | 393K | 3.9x slower |
Scoped logger (child/with)
Section titled “Scoped logger (child/with)”| Library | ns/op | ops/sec | vs fastest |
|---|---|---|---|
| aires (js) | 596 | 1.68M | baseline |
| pino child | 1,315 | 760K | 2.2x slower |
| winston child | 1,394 | 717K | 2.3x slower |
Error with stack trace
Section titled “Error with stack trace”| Library | ns/op | ops/sec | vs fastest |
|---|---|---|---|
| aires (js) | 1,731 | 578K | baseline |
| pino | 2,237 | 447K | 1.3x slower |
| winston | 3,633 | 275K | 2.1x slower |
Rust: Serialization Microbenchmarks
Section titled “Rust: Serialization Microbenchmarks”These measure the Rust core directly, via Criterion with statistical analysis.
| Operation | Time | Throughput |
|---|---|---|
| Event creation | 212 ns | 4.7M events/sec |
| JSON serialize (single event) | 200 ns | 5.0M events/sec |
| Proto encode (single event) | 62 ns | 16.1M events/sec |
| Proto encode (256 batch, heap) | 17.4 us | 14.7M events/sec |
| Proto encode (256 batch, arena) | 42.9 us | 5.9M events/sec |
| Batch build (256 events) | 46.6 us | 5.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.
End-to-End Comparison
Section titled “End-to-End Comparison”| Path | Per-event cost | Events/sec | vs pino |
|---|---|---|---|
| winston (JSON to fd) | ~2,500 ns | 400K | 0.6x |
| pino (JSON to fd) | ~1,500 ns | 670K | 1.0x |
| aires JS fallback (JSON to fd) | ~650 ns | 1.5M | 2.3x |
| aires native (proto to channel) | ~62 ns | 16M | 25x |
Reproducing
Section titled “Reproducing”TypeScript benchmarks
Section titled “TypeScript benchmarks”Rust benchmarks
Section titled “Rust benchmarks”Criterion HTML reports are generated in target/criterion/.
Full script
Section titled “Full script”The TypeScript benchmark source is at benchmarks/bench.ts. It measures:
- Simple message —
log("hello world") - 3 attributes — message + userId, traceId, path
- 8 attributes — full HTTP request log
- Scoped logger — pino child, winston child, aires
.with() - 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).