Observability as first-class
On most platforms, observability is something you set up later. In Flui, metrics and logs are there from the start: the operation that brings up a cluster also brings up the place where its metrics and logs go. They cover both the apps you deploy and the platform’s own components, and you read them the same way on your first app and on your two hundredth.
This chapter explains the intent and the shape of that choice. The detailed inventory of what runs inside the control cluster is in the next chapter.
Part of the platform from the start
In Flui, observability is part of the platform from the first minute the installation is alive, and other parts of the platform depend on it:
- It is part of the bootstrap. The operation that brings up the control cluster also brings up the backend that collects metrics and logs, and the installation is not considered ready until that backend is. Workload clusters added later feed into the same backend. You do not stand up a second observability stack; you point the new cluster’s agents at the one that already exists.
- It is modelled around the platform’s own concepts. The CLI and the dashboard show metrics and logs in terms of clusters, servers and applications, the things you already reason about, so you do not have to translate to namespaces, labels and query languages first.
- The platform itself relies on it. Alerts are evaluated against the metrics backend, and the memory limit Flui proposes when an application runs out of memory is read from the same data. Without observability, those features have nothing to read.
As a result, Flui cannot run in a useful state without observability, and monitoring is never left for later.
What is in scope
Flui’s built-in observability covers:
- Metrics: host-level metrics on every node, cluster-level metrics on every object, and the baseline per-application metrics (CPU, memory, restart count, replica health) that Flui shows for every app it manages.
- Logs: application logs from every cluster, indexed centrally and queryable per app, per cluster, per time range.
- HTTP traffic: request rate, status codes and latency for each application, measured where requests enter the cluster.
- Dashboards: Flui’s own dashboard and CLI, which show what matters for a cluster and for an application, chosen by Flui instead of left as a blank canvas.
- Alerts: conditions evaluated against the metrics backend, recorded as episodes and readable per application. See alerts, below.
- What your agents did: once an agent holds a credential on this installation, the calls it makes form a register you can read. See below.
Some kinds of telemetry are not part of the built-in stack: end-to-end request tracing across services, application performance profiling, and uptime checks from outside the platform. Applications that need them add their own tooling.
No database storage for logs or metrics
Flui’s database holds state about the installation (clusters, nodes, applications, operations, releases, builds) and nothing else. Logs and metrics live in their own purpose-built backends, with their own retention and capacity policies.
Two records that are not telemetry do live in Flui’s own database: the alert episodes described below, and the register of what agents did. Both record events with a beginning and an end, closer to an operation than to a log line, and neither grows with your traffic.
When you query logs or metrics through Flui, the API acts as a thin proxy: it resolves which application you are asking about, scopes the query to that application’s data, forwards it to the right backend and streams the answer back. No log line and no metric sample is ever written to Flui’s own database.
This has two effects:
- The control plane stays small. Flui’s database does not grow with traffic; it grows with the number of resources you manage.
- The backends can be replaced independently. Swapping the metrics or log store would not change the surfaces you use.
Alerts are recorded as episodes
Alerts are the part of observability that comes to you, so you do not have to be watching a metric to notice a problem.
Rules are evaluated on the control cluster against the metrics already being collected, so there is nothing extra to install or wire up. What Flui adds is the shape of the record.
One row per episode. A condition that stays true is
re-reported every few hours for as long as it lasts. Those
repeats update the same row instead of stacking up, so
flui app alerts my-api reads as a history of incidents,
not a mailbox. Each row carries whether it is firing or
resolved, a severity, a one-line summary, and when it
started and ended.
Estimated end times. The notice that a condition cleared is sent once. If it goes missing (the API restarting at the wrong moment is enough), the row would stay as a permanent false alarm. So a firing row that has been quiet for six hours is closed, marked as closed by timeout, and given the time it was last seen as its end. The CLI prints those with an asterisk, and the wording everywhere is “stopped reporting”, never “recovered at”. Read it as the last moment the condition was known to be true.
Retention. Resolved history is kept for ninety days by default and then deleted. A firing row is never deleted, however old it is, because an old alert that is still firing is the current incident.
Alerts belong to applications. Each one is attributed to the application it is about, and you see the alerts of the applications you may read. Alerts about the machines themselves are a separate list for whoever runs the installation, because their text carries host names and internal identifiers a tenant should not be able to collect.
Where to read them:
flui app alerts <app>: newest first,--firingfor only what is still firing,--output jsonfor scripting;- the Alerts section on the application in the dashboard;
- an agent, through the
app_alertstool.
Where an alert goes. When an alert starts or clears,
the person the application belongs to gets a notice in the
dashboard and, for a critical one, an email. An alert that
belongs to no application goes to the administrators, who
can choose to get warnings by email too
(flui alerts warnings --on). Any alert can also go to
another address or to a signed webhook, with
flui alerts destination add. Email needs mail to be set
up on the installation, and Flui does not place phone
calls.
One limit: an empty alert list does not mean everything is fine. It means nothing was recorded.
What your agents did
Metrics and logs answer what your applications did. Once you connect an agent to this installation, you also need to know what the agent did, and Flui records that too, per credential.
Every call an agent makes through the tool surface, or through the assistant inside Flui, is a row: when, which action, whether it was allowed, and what it started. Calls made straight at the API (an agent driving Flui with plain HTTP and no tool surface in front of it) are recorded too, on the routes that stop and ask a person first. Without this record, they would be the least visible and least supervised calls in the product.
Arguments are not kept. A value is shown as it was sent only when it belongs to a set written in Flui’s own source: a fixed choice, a number, a flag. Every free-form string is withheld, because the answers to a catalog install can carry an administrator password and this table is meant to be read. What a call actually touched is recovered from the operation it started, which Flui wrote itself.
Your own register needs no management access. You should not need to be an administrator to decide whether to disconnect an agent you connected. Somebody who administers access on the installation reads the whole installation’s register instead, and the page says which of the two you are looking at. Other people’s rows read as absent, not forbidden, because a refusal would confirm that the hidden call took place.
This is the one observability surface with no CLI. It is the Agents page in the dashboard, or the API with your own credential.
How workload clusters feed the control cluster
The control cluster receives metrics and logs from every workload cluster. The flow is push-based: every node runs a log shipper and every cluster runs a metrics agent, and both send to the central backend over the cluster’s private network.
If the control cluster is unreachable, workloads keep running (each cluster is autonomous in steady state), and the metrics agent buffers to local disk. When the link returns, recent metrics back-fill.
Why Flui pushes
The conventional model is pull, where a central scraper reaches into each target. Flui pushes instead, for three reasons:
- The trust boundary points outward: workload clusters start the connection, and the control cluster never reaches in.
- Short outages back-fill from the agent’s local buffer instead of leaving holes in the time series.
- The control cluster does not need a registry of every endpoint to scrape.
What the user sees
There are three surfaces, all backed by the same data:
| Surface | What it shows | When to use it |
|---|---|---|
| CLI | Single-app logs (filtered by level and full-text search), runtime status, metrics, HTTP traffic, recent crashes and alerts | Debugging a specific app, scripting, CI |
| Dashboard | Per-app live charts, traffic and log streams, plus cluster-level views | Day-to-day operation |
| Agent (MCP) | An application’s logs, metrics, HTTP traffic and alerts, through its tools | Letting an agent look into a problem or report on it for you |
None of the three is authoritative over the others. They are different views of the same data.
The register of what your agents did is the exception. It is not in the CLI, because it is Flui’s own record of who asked for what rather than a query over telemetry.
Where this chapter goes from here
- The control cluster: the detailed inventory of which components run, in which role, at what cost.
- The app concept: how the app surface is wired to the observability backend.
- When your agent stops to ask you: answering a request, and reading the register of what your agents have done.
- The action cycle: why an agent’s write stops and asks a person first.