Skip to content

perf(logs): remove LogEvent ingest wrapper allocations - #3766

Closed
djwhitt wants to merge 2 commits into
perf/logevent-clean-payload-reusefrom
perf/logevent-ingest-wrappers
Closed

perf(logs): remove LogEvent ingest wrapper allocations#3766
djwhitt wants to merge 2 commits into
perf/logevent-clean-payload-reusefrom
perf/logevent-ingest-wrappers

Conversation

@djwhitt

@djwhitt djwhitt commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Note

Removed from the stack: the isolated benchmark showed only a noisy 2.4% geometric-mean throughput change with approximately neutral memory, which did not justify carrying this additional mapper/validator refactor. The remaining stack continues with #3765#3767#3768#3769.

Summary

  • Return {body, timestamp_inferred} directly from the ingest mapper instead of allocating an intermediate envelope map.
  • Share mapper-field insertion between ingest and database reconstruction while retaining the map shape required by the Ecto changeset path.
  • Omit the unused timestamp_inferred key from the database mapper result.
  • Inline and clearly name legacy message lookup while preserving ID, timestamp, and message precedence behavior.
  • Call the sole active validator directly while preserving its valid-event contract and error fields.
  • Add mapper and validator integration coverage.

This is part 2 of 5 in the stack replacing #3760.

Rationale

The ingest mapper previously returned a three-key envelope containing body, id, and timestamp_inferred. LogEvent.make/2 immediately destructured that envelope, even though the ID was already present in the mapped body. Returning {body, timestamp_inferred} removes that short-lived map from every ingest operation.

The database reconstruction path still returns the map required by its Ecto changeset, but both paths now share mapper-field insertion and message normalization. Its unused top-level timestamp_inferred key is omitted. Validation also calls the sole active validator directly instead of traversing a one-element module list and creating reducer control tuples. The valid-event function contract and validation error shape remain unchanged.

Incremental benchmark

This comparison isolates this PR from its stack parent, #3765:

  • Baseline: f60b8258 (perf/logevent-clean-payload-reuse)
  • Candidate: 9422950b (perf/logevent-ingest-wrappers)
  • Three alternating baseline/candidate runs; each cell is the median of three runs
  • Linux arm64 host, 6 schedulers, 11 GiB memory
  • Elixir 1.19.5, Erlang/OTP 27.3.4.6 / ERTS 15.2.7.4, JIT enabled
  • Benchee: 2 s warmup, 5 s runtime, 3 s memory time, 3 s reduction time, parallelism 1
  • Production-shaped OTEL trace and edge-log payloads across no-transform, copy, drop, key-value, and combined transform configurations

Across all 12 scenarios, geometric-mean throughput improved 2.4%. Individual throughput results ranged from 3.0% lower to 14.5% higher; median latency was unchanged to 5.5% lower. Per-operation memory was approximately neutral (-2.4% to +2.6%) and reductions were unchanged to 1.3% lower. These incremental effects are modest and some throughput results are within run-to-run noise; the main value is removing unnecessary hot-path data structures while simplifying the mapper and validator flow.

Scenario Throughput, base → PR Speedup Median latency, base → PR Memory Reductions
OTEL trace 397.2K → 415.2K ops/s 1.05x 2.38 → 2.25 µs +1.6% +0.0%
OTEL trace + copy 357.9K → 365.7K ops/s 1.02x 2.63 → 2.54 µs -1.8% -1.3%
OTEL trace + drop 358.1K → 369.6K ops/s 1.03x 2.63 → 2.56 µs -1.8% -1.3%
OTEL trace + KV 225.7K → 258.4K ops/s 1.14x 3.63 → 3.63 µs -1.5% +0.0%
OTEL trace + copy + KV 223.6K → 218.3K ops/s 0.98x 3.92 → 3.84 µs -1.6% -1.1%
OTEL trace + all 219.1K → 212.9K ops/s 0.97x 4.25 → 4.17 µs -1.4% -1.1%
Edge log 380.8K → 375.9K ops/s 0.99x 2.46 → 2.46 µs -1.2% +0.0%
Edge log + copy 327.1K → 333.3K ops/s 1.02x 2.87 → 2.83 µs -1.7% -0.7%
Edge log + drop 304.5K → 311.6K ops/s 1.02x 3.04 → 3.00 µs +2.0% -0.7%
Edge log + KV 238.3K → 250.7K ops/s 1.05x 3.68 → 3.63 µs +2.6% -0.7%
Edge log + copy + KV 212.0K → 205.7K ops/s 0.97x 4.12 → 4.08 µs -2.4% -0.7%
Edge log + all 166.6K → 175.5K ops/s 1.05x 4.84 → 4.79 µs +0.7% -0.6%

These measurements isolate LogEvent.make/2; they do not represent end-to-end ingestion throughput.

Stack

  1. perf(logs): reuse clean BigQuery-safe payloads #3765 — Reuse clean BigQuery-safe payloads
  2. perf(logs): remove LogEvent ingest wrapper allocations #3766 — Remove LogEvent ingest wrapper allocations
  3. perf(logs): transform bodies before constructing LogEvent #3767 — Transform bodies before constructing LogEvent
  4. perf(logs): normalize integer timestamps without digit lists #3768 — Normalize integer timestamps without digit lists
  5. perf(logs): fast-path common UTC ISO 8601 timestamps #3769 — Fast-path common UTC ISO 8601 timestamps

Validation

  • ../bin/test test/logflare/log_event_test.exs test/logflare/validator/bq_schema_change_validator_test.exs
  • MIX_ENV=test ../bin/x mix format --check-formatted
  • MIX_ENV=test ../bin/x mix compile --warnings-as-errors
  • MIX_ENV=test ../bin/x mix lint.all

@djwhitt djwhitt closed this Aug 4, 2026
@djwhitt
djwhitt deleted the perf/logevent-ingest-wrappers branch August 4, 2026 00:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant