Skip to content

Benchmark the custom ITextFormatter path - #350

Merged
mishamyte merged 1 commit into
masterfrom
perf/349-benchmark-custom-formatter-path
Aug 8, 2026
Merged

Benchmark the custom ITextFormatter path#350
mishamyte merged 1 commit into
masterfrom
perf/349-benchmark-custom-formatter-path

Conversation

@mishamyte

Copy link
Copy Markdown
Member

First half of #349.

SinkBenchmarks never passes textFormatter — both its real-target and fake-transport branches use the default — so every benchmarked configuration takes the built-in LokiJsonTextFormatter fast path. FormatterBenchmarks measures the public Format surface, which the sink does not use in production (its own comment says so).

So the custom-ITextFormatter route through the serializer (Utf8TextWriter over the pooled body buffer, rather than FormatToBuffer) has no benchmark coverage at all, and an allocation regression on it is invisible to the Allocated signal CI relies on. That blind spot is how #347 shipped.

Change

Adds a CustomFormatterSinkBenchmarks group driving the same end-to-end pipeline through MessageTemplateTextFormatter with Serilog's stock output template — the most common custom formatter, and the shape reported in #347.

Added as a separate group rather than a Formatter param on SinkBenchmarks deliberately: a new param would rename all four existing rows (they would gain Formatter: "Default"), breaking pairing with published baselines and with the numbers in earlier PR comments. A separate class leaves them byte-identical and adds two rows instead of four.

Setup common to both groups is extracted into a private SinkSetup module. Applied to both the Current and NuGet projects — Benchmarks.fs is per-project (only EventGen/BenchConfig/Program are shared), and the method names and params must match for compare-results.fsx, which joins rows by FullName.

Measured locally

| Method | EventCount | Payload   | Mean      | Allocated |
|------- |----------- |---------- |----------:|----------:|
| Push   | 1000       | Exception | 23.109 ms | 7573.8 KB |
| Push   | 1000       | Simple    |  2.810 ms |  116.03 KB |

Baseline and source both allocate a Utf8TextWriter per event at this point, so this PR should show ~0 delta between them. It establishes the number that the second half of #349 then improves.

🤖 Generated with Claude Code

SinkBenchmarks never passes textFormatter, so every benchmarked configuration
takes the built-in LokiJsonTextFormatter fast path. FormatterBenchmarks
measures the public Format surface, which the sink does not use in production.
The custom-formatter route through the serializer -- Utf8TextWriter over the
pooled body buffer -- is therefore not benchmarked at all, and an allocation
regression on it is invisible to the CI signal.

Add a CustomFormatterSinkBenchmarks group driving the same end-to-end pipeline
through MessageTemplateTextFormatter with Serilog's stock output template (the
shape reported in #347). Added as a separate group rather than a Formatter
param on SinkBenchmarks so the existing rows keep their names and pair with
published baselines unchanged.

Setup shared by both groups is extracted into SinkSetup, in both the Current
and NuGet projects -- Benchmarks.fs is per-project, and the names and params
have to match for compare-results.fsx to pair the rows.

Refs #349

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@mishamyte, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 31 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 93556c43-f6d8-40aa-80a3-0bbbde8aad49

📥 Commits

Reviewing files that changed from the base of the PR and between 5a8418f and 9b0afd1.

📒 Files selected for processing (2)
  • benchmarks/Serilog.Sinks.Grafana.Loki.Benchmarks.Current/Benchmarks.fs
  • benchmarks/Serilog.Sinks.Grafana.Loki.Benchmarks.NuGet/Benchmarks.fs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

Benchmark comparison

Baseline: Serilog.Sinks.Grafana.Loki 9.0.1 (latest on NuGet) vs this source.

Allocated is exact and deterministic — treat it as the regression signal.
Mean on shared CI runners is noisy; deltas within ±10% are not meaningful.

Benchmark v9.0.1 alloc source alloc Δ alloc v9.0.1 mean source mean Δ mean
CustomFormatterSinkBenchmarks.Push(EventCount: 1000, Payload: "Exception") 8.44 MB 8.48 MB +0.5% 12.53 ms 11.31 ms −9.7%
CustomFormatterSinkBenchmarks.Push(EventCount: 1000, Payload: "Simple") 120.0 KB 108.0 KB −10.0% 🟢 2.10 ms 3.39 ms +61.8% 🔺
SinkBenchmarks.Push(EventCount: 1000, Payload: "Exception") 7.71 MB 7.79 MB +1.0% 37.23 ms 18.40 ms −50.6% 🟢
SinkBenchmarks.Push(EventCount: 1000, Payload: "Simple") 155.3 KB 136.2 KB −12.3% 🟢 5.25 ms 6.93 ms +31.9% 🔺
SinkBenchmarks.Push(EventCount: 10000, Payload: "Exception") 77.19 MB 77.80 MB +0.8% 114.67 ms 106.49 ms −7.1%
SinkBenchmarks.Push(EventCount: 10000, Payload: "Simple") 1.36 MB 1.36 MB +0.0% 18.33 ms 15.96 ms −12.9% 🟢

@mishamyte
mishamyte merged commit 1d88759 into master Aug 8, 2026
8 checks passed
@mishamyte mishamyte self-assigned this Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant