Logs, metrics and traces, built in
Two weeks ago, in the post about our tagline,
we listed what was still a proof of concept here, and monitoring came first:
“you read your app’s logs with kubectl on its own cluster.” That line is out
of date. Every project on Basable now has its logs, metrics and traces collected
from the moment it runs, alerts when something goes wrong, and Grafana to look
at all of it. There is nothing to install and nothing to configure.
Logs, from the first line
Everything every container writes to stdout and stderr is collected and kept
for seven days. That includes containers that have since crashed and
restarted, which is usually where the line you need is, and environments that
are asleep. Open an environment’s Logs in the editor, narrow them to a time
range, a workload or a container, or search for a word. A JSON line with a level field, or a line with a
level word such as ERROR, gets its level. A stack trace spread over several
lines can be stitched back together with a parser in the pod’s annotations;
the help page has the recipe.
Metrics, without code
Every container’s CPU, memory, network and file system, its restarts, why it is waiting (CrashLoopBackOff, ImagePullBackOff) and why it last ended (OOMKilled), every 30 seconds, kept for fifteen days. Every request that reaches your app through the platform’s gateway is counted as well, per route and status class, with the time your app took to answer. The editor’s Metrics panel shows each route’s requests per second, its server errors and its 95th percentile response time, and how full each volume is.
Metrics of your own come in two ways: a container that serves the Prometheus format is scraped once its pod opts the port in, or an OpenTelemetry SDK pushes them. A project keeps up to 10,000 series.
Traces, from the gateway to your database
Every request through the gateway starts a trace, and the gateway hands it to
your app in the traceparent header. Every container already has
OTEL_EXPORTER_OTLP_ENDPOINT set, so any OpenTelemetry SDK sends its spans
without an address to configure, and the trace continues from the edge through
your services down to the database query. A log line that carries its trace id
gets a Trace button that opens the whole request as a waterfall. Projects on
Basable’s Rust framework (basable-app 0.8.0 and later) start the SDK by
themselves. Traces are kept for seven days.
Grafana, with your Basable account
All of it is also in Grafana, at grafana.basable.com. You sign in with your Basable account. Each of your organisations is an organisation there, holding its own projects and nobody else’s, and a Basable folder has every project’s overview, logs and traces, with room for dashboards of your own beside them. The Grafana button in the editor opens the project’s overview with the project already chosen.
Grafana holds no key to the stores. Every query it makes goes through Basable, which decides again, query by query, what your account may read. Leave an organisation and its projects disappear from Grafana within a minute.
Alerts
Basable watches every live environment for four things: a container that keeps
crashing, one that runs out of memory and is restarted, a route where more
than half of the requests end in a server error, and a volume more than 90%
full. Mail is off until you turn it on, per environment, and the same block in
.basable/config.yaml takes rules of your own, in PromQL, with the threshold
in the query:
spec:
environments:
live:
alerts:
email: {enabled: true}
rules:
- name: queue-backlog
query: jobs_waiting > 1000
A rule the metrics store cannot parse fails the deploy and names the rule, so a typo does not sit there silently. Alerts can also go to your app as a webhook, on the environment’s own address and nowhere else, signed with an Ed25519 key whose public half is published. From there your app forwards them to a chat or a pager.
Your agent reads them too
The assistant in the editor reads an environment’s logs, metrics and traces
while it works on the project, so “the deploy is green but the page shows an
error” is something it can look into instead of something you paste into the
chat. An agent you connect over MCP, such as Claude Code or
Cursor, has the same tools: get_logs, query_metrics, list_metrics,
search_traces, get_trace and list_alerts. Each answer ends with a link
that opens the same query in Grafana, so you can see what your agent saw.
Kept apart, including from us
Each project is a tenant of its own in the log, metric and trace stores. What a container sends is filed under the project and pod that sent it, whatever the data claims about itself, and a query, yours or your agent’s, only ever reads its own project. A request’s trace keeps no visitor IP address and no query string.
Basable’s staff have no standing access to any of it. When we need to look at a project, to answer a support mail for instance, we open a read grant on that one project, with a reason, for one hour. Every grant is listed on the organisation’s Staff access page with its reason, and the project’s page shows a notice while one is open.
What is not there yet
Retention is fixed: seven days of logs and traces, fifteen days of metrics, and no way yet to keep more. There is no error tracker that groups exceptions for you, and no check from outside that your site answers. Alerts go by mail or to your own app; Slack or a pager is reached through that webhook, not directly. And the security audit logs mentioned in the environment post, what the cluster itself saw, are a separate piece of work that is still open.
Sign up with just your email, deploy something, and open its Logs: the first lines will already be there.