Early access is open. Free plan during early access. Start free
Logthread

Guide

Benchmarks

This page says what we measured, on what, and what we have not measured yet. None of it is a service level.

  • Production was measured on 2026-11-04 on Logthread's production service in Mumbai.
  • Development stack was measured on 2026-11-03 on one developer laptop. It shows what the software does with more CPU than production has today.

The raw results (JSON) are available on request.

Production (2026-11-04)#

What it ran on#

  • Service: Logthread production, Mumbai. One Ampere Arm server with 2 cores and 12 GB, running the gateway, the worker and the database. The managed queue is Oracle Cloud Queue, and the production storage and query layer is used throughout.
  • Workspace: a scratch workspace on the Enterprise plan. Its plan limits did not stop any run.
  • Load generator: Logthread's load generator on a laptop in the United States, about 250 ms from Mumbai. Query times include that round trip, about 1 s per call (the "Repeat" column shows it).
  • Records: OTLP or NDJSON logs, gzip, about 155 bytes per record before compression.

Results: ingest#

RunOfferedAcceptedRecords deliveredNotes
2 minutes10 MB/s9.7 to 10.8 MB/s, none rejectedall, onceThe last records were searchable 88 to 118 s after the run ended, while the worker caught up.
2 minutes40 MB/sabout 9.8 MB/s (7.1 million records)all accepted records, onceThe gateway answered 503 to the requests above its rate. Clients retry those; nothing is acknowledged before it is stored in the queue.
1 hour2.8 MB/s (10 GB per hour)all, none rejectedabout 40 million, allSee ingest lag below.

On this server the end-to-end rate it sustains (accepted, processed and stored) is about 5 MB/s, about 18 GB per hour. Short bursts up to about 10 MB/s are absorbed by the queue and caught up within minutes. The limit is the server's CPU. More or larger servers raise it; enterprise capacity is provisioned per contract.

Results: ingest lag at 10 GB per hour#

Time from the gateway acknowledging a record until the search API returns it, during the 1-hour run. 330 probes, 0 failed.

p50p95Max
2.0 s3.0 s13.3 s

Results: query latency at 10 GB per hour#

13.8 million rows in the last hour and 95.9 million in 24 hours. 20 runs per cell, each a different statement so none comes from the result cache. Every time includes about 1 s of round trip from the United States.

QueryWindowp50p95MaxRepeat p50
Search (newest 50)1 h1.87 s2.01 s2.11 s1.23 s
Count (histogram)1 h1.35 s1.55 s1.56 s968 ms
Stats (count by service)1 h1.25 s1.41 s1.45 s869 ms
Search (newest 50)24 h5.05 s5.48 s6.10 s1.27 s
Count (histogram)24 h3.87 s4.45 s4.75 s945 ms
Stats (count by service)24 h3.00 s3.68 s4.10 s1.02 s

The 30-day cells were not completed: the run reached the workspace's hourly read allowance (1 TB read per hour), which the benchmark's own repeated 24-hour and 30-day queries had used up. Each 24-hour query over this volume reads 1 to 3 GB.

Development stack (2026-11-03)#

What we measured#

AreaWorkload
Ingest throughputOTLP logs over HTTP, gzip, about 155 bytes per record before compression. Steady steps from 10 to 90 MB/s, then a 9 MB/s base with a 10x burst (90 MB/s for 30 s) and back.
Ingest lagEvery 10 s one uniquely marked record is sent. The search API is polled until it is returned. Background load of 0.5 MB/s. 30 probes.
Query latencySearch (newest 50), count (histogram) and stats (count by service) over the last 1 hour, 24 hours and 30 days. 20 runs per cell, each a different statement so none comes from the result cache.
Alert delayA log-count rule on a marker, window 5 minutes, evaluated every minute. 20 matching records are sent at a random point of the rule's minute. 5 trials. Time from the records being accepted to the incident.
Dashboard refreshThe panel query a dashboard runs on every refresh (log volume by severity), 1 hour and 24 hours, 20 refreshes 6.5 s apart.
SLOsSave, list (with live status) and delete of scratch SLOs.

"MB/s" in the ingest results is the uncompressed OTLP size, not the size on the wire. A request is gzip-compressed, so the network carries roughly a sixth of it.

What it ran on#

  • Machine: Apple M4 Max, 16 cores, macOS. Docker Desktop with 16 CPUs and 7.7 GiB of memory for containers.
  • Stack: Logthread's development stack. One ingest container running the gateway, worker and redrive roles together, Valkey as the queue (two queues), Postgres, one web container, one jobs container. Containers are linux/arm64.
  • Load generator: Logthread's load generator, on the same machine. It competes with the stack for CPU.
  • Workspace: Enterprise plan, with its ingest rates (100 MB/s sustained, 1,000 MB burst). The limits are not what stopped any run below.
  • Storage and query layer:
  • For the ingest run, the storage write path was replaced by a stand-in that accepts and discards writes. This measures the gateway, the queue and the worker, with no storage cost.
  • For lag, query, alert, dashboard and SLO numbers, the real storage and query layer was used, over the internet, from a development workspace. It is shared with other development workloads, so counts include data that is not ours, and its load varies.
  • Data in the workspace: about 2.8 million rows in 30 days (1.1 million in the last hour, 1.3 million in 24 hours). The 30 day window is the workspace's whole retention. Over 200,000 of the rows were loaded with the backfill option, spread over the past 30 days.

Results: ingest throughput (gateway, queue and worker)#

Records go through the gateway, the queue and the worker, and are delivered to a stand-in that discards them. No request was throttled, rejected or dropped.

StepTarget MB/sAchieved MB/sRecords/sRequest p50 / p99
15 s1010.064,7002.3 / 3.8 ms
15 s2525.0161,6002.2 / 4.6 ms
15 s5050.0323,4002.2 / 4.9 ms
15 s7574.9484,7002.2 / 5.6 ms
15 s9089.3577,3002.6 / 8.2 ms
20 s9 (base)9.058,2002.2 / 4.2 ms
30 s90 (10x burst)89.4578,4002.6 / 7.5 ms
20 s9 (base)9.058,2002.2 / 3.9 ms

Every step was sustained. The queue was empty at the end of the last step, so the worker kept up with the burst.

The highest rate we reached on this machine was about 97 MB/s (about 630,000 records/s). That was a separate short run with no rate limit and 32 workers. At that rate the ingest container used about 760% CPU and no request was throttled. We did not find out whether the limit was the container, the Docker VM or the load generator, so treat 97 MB/s as a ceiling of this setup, not of the software.

Results: ingest lag#

Time from the gateway acknowledging a record until the search API returns it. 30 probes, 0 failed, with 0.5 MB/s of background load.

p50p95Max
2.3 s4.1 s5.5 s

The search was polled about every 0.6 s, so each figure is accurate to about that much. The table is from a run without storage problems. While the storage layer refuses writes, records wait in the queue and lag grows; see Storage outage for how quickly delivery resumes.

Results: query latency#

Rows in the window are the whole workspace. "Repeat" is the same statement asked again straight away, which is what a second viewer of the same dashboard sees.

QueryWindowRows in windowp50p95MaxRepeat p50
Search (newest 50)1 h1,134,4271.67 s2.43 s2.65 s8 ms
Count (histogram)1 h1,134,427439 ms663 ms1.12 s16 ms
Stats (count by service)1 h1,134,427437 ms679 ms689 ms9 ms
Search (newest 50)24 h1,310,9701.79 s2.62 s3.55 s11 ms
Count (histogram)24 h1,310,970446 ms681 ms1.24 s11 ms
Stats (count by service)24 h1,310,970443 ms760 ms1.10 s11 ms
Search (newest 50)30 d2,833,7132.09 s2.83 s3.53 s7 ms
Count (histogram)30 d2,833,713532 ms786 ms1.17 s525 ms
Stats (count by service)30 d2,833,713503 ms679 ms1.30 s498 ms

With 20 runs per cell, p95 is close to the slowest run. These workspaces hold millions of rows, not the billions an Enterprise customer will have, so do not extrapolate the 30 day figures.

Results: alert evaluation delay#

Rule: count above 0 for a marker, window 5 minutes, evaluated every minute. 5 trials, all fired.

Measurep50Max
Records accepted to incident start18.2 s39.7 s
Records accepted to incident seen by polling21.4 s40.7 s

Most of this is the wait for the rule's next evaluation, which depends on where in its minute the records arrive. With 5 trials a p95 is not meaningful, so we show the maximum.

Results: dashboard refresh#

The panel query a dashboard runs on every refresh, one panel at a time, 20 refreshes 6.5 s apart (so each is past the 5 s live cache).

PanelWindowp50p95Max
Log volume by severity1 h832 ms1.63 s2.75 s
Log volume by severity24 h941 ms2.87 s3.00 s

One panel was measured at a time. A dashboard with many panels was not.

Results: SLOs#

OperationRunsp50p95Max
Save (create)52.83 s3.14 s3.14 s
List (5 SLOs with live status)20495 ms583 ms1.11 s
Delete57 ms16 ms16 ms

A save measures the SLO over its window and breaks the bad requests down before it answers; the two run at the same time, and the breakdown is skipped if it takes longer than 6 seconds. (The first run, before they ran together, measured 6.5 s at p50.)

Results: storage outage#

Ingest at 2,000 records/s while the storage write path answered every request with 503 for 60 seconds, then recovered.

MeasureResult
Records the gateway accepted480,000 of 480,000 (clients saw no errors)
Records delivered after the outageAll of them; none lost or parked
Delivery resumed after storage recoveredabout 10 s
Breaker closed after storage recoveredabout 50 s

During the outage records wait in the queue; the worker backs off and probes once per tenant until a write succeeds. When the storage layer sends a Retry-After, the worker waits that long (at most 15 minutes) before probing again.

Timestamps#

The gateway does not reject old records. A record keeps the time it carries, so history can be loaded. Only a record more than 24 hours in the future is given the time it was received. The 30 day cells above rely on this: 99,500 records spread over 30 days were all searchable.

What is not measured yet#

Do not read any number above as a claim about the following.

  • The Enterprise rates. Production today sustains about 5 MB/s end to end on one server, not the Enterprise plan's 100 MB/s with 1,000 MB bursts. Enterprise capacity is provisioned and agreed per contract.
  • More than one server. Every production run used the single server. Scaling out is prepared but was not measured.
  • Many tenants at once. All runs used one workspace.
  • Large data. Query numbers are for up to about 100 million rows, not billions.
  • Duration. The longest run was one hour. No soak over days.
  • Alerts, dashboards and SLOs on production. Those numbers are from the development stack only.
  • A customer's network. Production query times include the round trip from the United States to Mumbai; a customer elsewhere sees a different round trip.
  • Failure behaviour at high rate. The outage test ran on the development stack at 2,000 records/s, and only one kind of failure (storage refusing writes) was tested.

Reproduce#

The benchmark harness drives Logthread's own load generator and public APIs. It needs only an ingest key, an API key with the read, alerts and dashboards scopes, and a member's sign-in for a scratch workspace. It never prints credentials, and it deletes the alert rules and SLOs it creates (log records expire with the workspace's retention). To see these numbers on your own workload, ask us to run it against a scratch workspace in your account; we share the raw results.