-
Notifications
You must be signed in to change notification settings - Fork 40
Benchmarks
These numbers come from the BenchmarkDotNet suites in the benchmarks/ folder - see its README to reproduce them. Each sink is driven end to end through its public API, pushing batches of log events at an in-process transport that returns Loki's 204. So what is measured is the sink's own work - serialization plus batching - with the network taken out of the picture.
Three sinks are benchmarked:
-
v8 -
Serilog.Sinks.Grafana.Loki8.3.2, the previous release (Serilog 2.12) - v9 - this sink, the Serilog 4.x rewrite
-
YetAnother -
Serilog.Sinks.Loki.YetAnother4.0.5, a popular, allocation-conscious third-party Loki sink (Serilog 4.x)
This page focuses on the v8 → v9 upgrade. YetAnother is included as an external yardstick - a well-regarded low-allocation sink, run through the identical harness - so v9 is measured against the best of the field, not just against its own past. Its per-sink figures sit alongside v8/v9 in that folder's README.
Each event is either Simple (a templated message with int / string / float / bool / Guid properties) or Exception (a two-level nested exception with real stack traces). Lower is better throughout.
v9 changed the serialization design. v8 built an intermediate object graph and rendered it to a JSON string for every batch; v9 streams JSON bytes straight through a reused, pooled Utf8JsonWriter buffer, with no intermediate string - then a focused optimization pass took it much further (see V9 Optimization Log).
| Workload | Allocated (v8 → v9) | Time (v8 → v9) |
|---|---|---|
| Simple · 1 000 | 7.5 MB → 0.14 MB | 11.5 ms → 5.4 ms |
| Simple · 10 000 | 75 MB → 1.36 MB (~55× less) | 79 ms → 18 ms (~4.5× faster) |
| Exception · 1 000 | 21.9 MB → 6.6 MB | 25.1 ms → 33.5 ms (noisy) |
| Exception · 10 000 | 220 MB → 66 MB (−70 %) | 263 ms → 121 ms (~2.2× faster) |
On the common (Simple) workload v9 allocates ~55× less than v8 and runs ~4.5× faster. v8 also pushed its large intermediate strings onto the Gen2/LOH heap; v9 stays in Gen0 on that path.
Exception logging improves less, because materialising .NET stack traces (ex.StackTrace) is a per-event cost unrelated to the sink, and it dominates that workload for any sink.
- The 10 000-event rows are the throughput numbers. At 1 000 events a fixed per-flush overhead dominates and the means get noisy, so small-batch timings are not a good guide to per-event cost (the Exception · 1 000 time above is one such noisy case).
- Allocation figures are exact (BenchmarkDotNet's memory diagnoser); timings are wall-clock means on an AMD Ryzen 9 3950X, .NET 8.
- v8 is a fixed NuGet package (a stable reference point); v9 is the current build.
- The benchmark uses an in-process transport; against a real Loki the network and ingestion add latency on top, equally for every sink.
The suites run through the repository's FAKE build script, so the same command works on Windows, Linux and macOS:
# from the repo root - all three suites, fake transport (default)
dotnet fsi build.fsx -- --target BenchmarkOptional environment variables: BENCH_FILTER (a BenchmarkDotNet --filter glob such as *Sink*) and LOKI_BENCH_TARGET (push to a real Loki started via docker compose up -d loki instead of the in-process fake).
- The V9 Optimization Log - the change-by-change record of how v9 reached these numbers
- The
benchmarks/folder - methodology, full tables, and how to run them - Upgrading from v8 to v9
- Breaking changes