What we store, and what we only pass through
Trace Town reads telemetry you already have. This is the whole of what
it takes, what it keeps, and what it never sees — written against the
code rather than as a policy, so if any of it stops being true that is
a bug and we would like to hear about it.
Signed out, nothing reaches us at all
Pointed at a Prometheus without an account, your browser queries it
directly. There is no server in the path, the credential lives in that
tab’s memory until you reload, and nothing about your system is
transmitted anywhere. Everything below is about signed-in connections,
where our server does the fetching on a schedule.
Read on every poll
Your traces are not fetched. Trace Town asks your provider for
the summary it has already made out of them — how many requests,
how many failed, how slow the slow ones were, and which service called
which. Individual traces and the spans inside them stay where they are.
- Services
- Name, request count, error count, p99 latency, and — if you set
them — a namespace and an archetype hint
- Calls
- Caller name, callee name or hostname, the dependency type, and
counts
Those are aggregates your provider has already computed. None of it is
written to a database and none of it is logged.
Held in memory, briefly
It is not quite true to say a snapshot is fetched and dropped, so here is
what actually happens. Your provider is polled once per connection,
not once per viewer, and everyone watching that town is sent the same
snapshot — which is why two people in an incident see the same town
rather than two towns fifteen seconds apart, and why a crowd costs your
Prometheus the same as one person.
That means the most recent snapshot is held in our server’s memory
between polls, so somebody opening the page mid-interval is shown the
town immediately instead of waiting. A second, shorter memory underneath
it stops viewers on slightly different timers each starting their own
query.
- Snapshot
- Up to about 20 seconds, against a 15-second poll
- Log lines
- About 2 seconds, which is what stops one open Logs tab querying your
provider twenty times a minute
- A provider error
- About 3 seconds, so a provider that is down is asked less rather than
hammered by every viewer’s retry
All of it is process memory only. It never reaches a disk, it does
not survive a restart, it is discarded when the last person stops
watching, and it is thrown away whenever the connection is edited. It is
shared between viewers of the same connection, and a connection
belongs to one team — there is no path by which one team’s
data reaches another.
Stored in our database
- Your account
- The user id, email, name and avatar URL your sign-in provider gives
us
- Your team
- Who is in it and what they may do
- Each connection
- Provider, the name you gave it, the URL, the query window, and the
credential — encrypted with AES-256-GCM before it reaches the
database
- Each town’s arrangement
- Where you dragged each building, how it is zoned, and any archetype
you corrected by hand
Service names are the only thing from your telemetry that we keep,
and only because an arrangement has to remember which building you moved.
No metrics, no rates, no history.
A saved credential is write-only. No route returns it, not even
masked — the API will tell you whether one is set and nothing more. There
is no path from a town back to a key for anybody, including whoever
typed it.
Passed through, never stored
When you open a building’s Logs tab we fetch recent lines
for that one service and show them to you. The timestamp, the severity
and the message go to your browser, are held in memory for the couple
of seconds described above, and are written down nowhere.
Log messages are your application’s own output, passed through
verbatim — so whatever your code writes to a log is what crosses the
wire, including anything it should not have written. Nothing is fetched
until somebody opens that tab on that service. If that is a line you
would rather not cross, connect a metrics provider without a log store
and the tab has nothing to show.
Never read
Individual traces, span attributes, request or response bodies, headers,
query strings, cookies, and URLs beyond a route name. The snapshot every
provider is reduced to has no field for any of them.
Reaching your provider
Every request our server makes to a URL you gave it goes through one
guard: https only, every resolved address must be a public one,
redirects are followed by hand so each hop is checked like the first, and
your credential is dropped the moment a redirect changes origin — a
token for your Grafana is for your Grafana.
A plain http URL is refused when you save it, not on the
first poll. Every target we reach is on the public internet, so http
would mean your credential crossing it unencrypted every fifteen
seconds. Running Trace Town inside your own network is the one
exception, because there it is your own network.
The narrowest credential that works is the right one, and the provider
pages above say what that is for each: a read-only user key for New
Relic, and for Azure a custom role granting the four tables Trace Town
reads and nothing else — no write, and no access to ingestion keys.
Analytics
Only if you accept the cookie notice; nothing is loaded until you do.
What it can send is a fixed list of categories — which provider, roughly
how big a town, which of four kinds of failure. It carries no URLs, no
hostnames, no service names and no error text, because it has nowhere
to put them.
Who else is involved
Sign-in is Firebase Authentication (Google). The service runs on Railway
behind Cloudflare. Analytics, once accepted, is Google Analytics.