Skip to content

See what broke without operating an observability stack.

Send traces, logs and metrics to one process over OpenTelemetry. Investigate incidents in the browser or through an agent, and run alerts — without operating the stack behind them.

One Go process: OTLP in over gRPC or HTTP, authoritative Parquet on disk, indexed trace reads, and embedded DuckDB analytics. No database to operate.

checkoutp95 latency · last 1h
13:2014:22now
p95412ms+38%
errors2.4%+0.2
rps1.2kstable

why is checkout slow right now?

missing index on orders(user_id) — 88% of slow spans block on db-orders

  • Self-hosted on your hardware

  • OTLP native traces, logs and metrics

  • Open local storage authoritative Parquet, embedded queries

  • One small VM reference deployment target

  • Apache-2.0 open source

What you look at

Every service, one screen, no query language.

Section titled “Every service, one screen, no query language.”

Health, latency, error rate and throughput for everything reporting — with the slow one already at the top. The chat investigator works from the same typed queries this view does, so what it tells you and what you are looking at cannot disagree.

demo.fanout.run · Overviewlast 1h

Services

ServiceHealthp95ErrorsRps
checkoutunhealthy412 ms+38%2.4%1.2k
cartdegraded187 ms0.6%2.1k
cataloghealthy42 ms0.0%3.8k
paymenthealthy94 ms0.1%980
authhealthy28 ms0.0%5.4k

5 of 47 services · worst first

Health

Score86+2 vs 1h
Spans/min2.1Mstable
Errors0.4%+0.2
Services472 alerting

Throughput

What it replaces

This is the whole argument. Every other claim on this page follows from it — the short backup procedure, the single configuration, and the absence of an integration layer to debug at three in the morning.

The usual arrangement

  • CollectorReceive OTLP, batch, forward
  • Storage backendPersist telemetry, expire it
  • Query layerAnswer questions over that store
  • Dashboard serviceRender it for people
  • AlertmanagerEvaluate rules, deliver notifications

Five deployments, five configurations, five upgrade cadences — and the failure modes that exist only between them.

Fanout

  • OTLP in over gRPC and HTTP
  • Authoritative Parquet on local disk
  • Indexed traces and DuckDB analytics
  • The browser client, served by the binary
  • The alert engine, on a fixed interval

One binary to pin, one directory to back up, one process to restart.

Inside the binary

Three signals in, one process, answers back out.

Section titled “Three signals in, one process, answers back out.”

Fanout is where your telemetry lands, not something you put in front of the thing it lands in. Traces, logs and metrics arrive over standard OTLP from SDKs or a Collector you already run, and everything after that happens inside one binary.

Traces, logs and metrics arrive over OTLP into a single Fanout process that publishes authoritative Parquet with trace indexes and uses DuckDB for analytics, and the answers leave to a browser, the HTTP API, or an agent over MCP. traceslogsmetricsbrowserAPIagent · MCPone processParquet + trace indexesDuckDB analyticsOTLP

Nothing in the middle crosses a network, and nothing else has to be running for it to answer. The data directory it writes is the whole of its state.

Measured on one machine

422,408 OpenTelemetry items a second. One binary.

Section titled “422,408 OpenTelemetry items a second. One binary.”

On a Hetzner Cloud ccx33 (8 dedicated vCPUs, 32 GB RAM), with telemetrygen on a separate ccx33 in the same location over a private network, Fanout v2026.10.7-alpha accepted 422,408 mixed OpenTelemetry items/s for five minutes: 51,358 spans, 184,883 log records and 186,178 metric points per second. Every generator exited successfully, there were zero dropped rows and no restarts, and the Parquet store passed verification. The run measured ingest only.

Published benchmark · v2026.10.7-alphamethodology

Hetzner ccx33 · 8 dedicated vCPUs · 32 GB RAM · separate ccx33 generators

Sustained mixed ingest

422,408 items/s

302.9 s · 32 processes per signal
Fanout: 7.33 cores average · 13.5 GiB peak RSS
Generator: 7.01 of 8 cores average

  • Spans51,358/s
  • Log records184,883/s
  • Metric points186,178/s
Mixed sweepaccepted items/s
Mixed accepted throughput by processes per signalMedian line and minimum-to-maximum band across 3 repetitions at 1, 2, 4, 8, 16, 32 and 64 processes per signal. The horizontal axis is evenly spaced on a log2 scale; the vertical axis runs from zero to 600,000 accepted items per second. At 1 processes: 41,300 items/s, range 40,269 to 41,362. At 2 processes: 81,075 items/s, range 80,661 to 81,651. At 4 processes: 148,972 items/s, range 130,086 to 154,626. At 8 processes: 244,888 items/s, range 219,064 to 273,901. At 16 processes: 330,232 items/s, range 325,618 to 364,301. At 32 processes: 429,749 items/s, range 429,504 to 471,506. At 64 processes: 422,667 items/s, range 384,338 to 441,460. The diamond marks the single sustained phase: 422,408 items/s at 32 processes per signal over 302.9 seconds. Shading at 32–64 processes marks generator CPU of at least 7 cores.
medianmin–max422,408/s sustained at 32
Mixed median peak429,749 items/s429,504–471,50632 processes per signal
Traces median peak243,696 items/s225,110–267,91664 processes per signal
Logs median peak342,494 items/s299,902–347,72164 processes per signal
Metrics median peak540,102 items/s293,700–543,94164 processes per signal
generators exited successfullydropped rows 0no restartsParquet verified

584.1M items accepted across the suite · raw evidence

Read the methodology, inspect the raw evidence, or run the harness on your own hardware.

Limits

These decide whether Fanout fits, so they are here rather than three pages in. None of them is a roadmap item phrased as a virtue.

  • Not multi-tenant: namespaces scope queries, not access. Anyone who can query the instance can query every namespace in it; an instance is one trust domain.
  • No horizontal scale: ingest, query and maintenance share a process and a machine. There is no scaling one without the others, because they are the same thing.
  • No universal capacity number: the benchmark above describes one release, host and workload. Your payload cardinality, query mix and disk decide the capacity of your instance. Measure your own hardware.
  • No migration paths: Fanout is pre-release. Storage-format changes may require a fresh data directory; preserve backups before upgrading.

Install it and point something at it.

One binary, one data directory. The installer checks the archive against the release checksums before it extracts anything.

curl -fsSL https://raw.githubusercontent.com/labstack/fanout/main/scripts/install.sh | sh