Skip to content

Observability that runs anywhere you can run a binary

Point your traces, logs and metrics at one process over OpenTelemetry. Get a fast browser client, a chat investigator that works through the evidence, and alerts — without standing up a stack to hold them.

One Go process: OTLP in over gRPC or HTTP, Parquet on disk, DuckDB for queries. No collector to deploy alongside it and 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

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

Health

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

Throughput

The shape of it

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 writes Parquet and queries it with DuckDB, and the answers leave to a browser, the HTTP API, or an agent over MCP. traceslogsmetricsbrowserAPIagent · MCPone processParquet on diskDuckDB in-processOTLP

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.

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
  • Parquet on local disk
  • DuckDB, in the same process
  • 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.

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 published throughput figure: the previous benchmark was withdrawn because its raw reports and driver commit were not retained. Measure your own hardware instead.
  • No migration paths: Fanout is pre-release. A renamed setting is renamed, not aliased, which is why an unknown variable stops the process rather than being ignored.

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