Architecture

Prometheus Architecture: How It Actually Works

prometheus/prometheus Apache-2.0 1 diagram
How to read this page

Symvanta parsed this repository into a code graph: every function, class, and method is a node, and every call or import between them is an edge. Everything on this page is computed from that graph at the commit shown above. The terms:

Module (or cluster)
A group of symbols that call each other far more than they call anything else. An algorithm called Louvain community detection finds these groups from the call traffic alone; nobody draws them by hand.
Modularity (the Q number)
A 0-to-1 score of how cleanly those groups separate. Higher means more call traffic stays inside its own group; scores around 0.7 and above read as clean boundaries.
Hub
The most depended-upon symbol inside one module.
Load-bearing symbols
PageRank, the algorithm Google originally used to rank web pages, run over the call graph instead: it surfaces the functions the rest of the codebase leans on hardest.
Arrows and their numbers
How many calls cross from one module into another. A heavier arrow means tighter coupling between those two parts.
Dependency cycle
File A imports B, which imports A again, sometimes through a longer loop. Cycles are not bugs, but a change inside one tends to ripple around the whole loop.
Mutually recursive symbols
Functions that call each other, usually the natural shape of parsers and tree-walking code.

Prometheus is a single Go binary that scrapes targets, writes samples into a local time series database, and answers PromQL queries against it. Symvanta's graph of the repo at e75af38 detects 53 functional modules at modularity Q=0.71, and the weight sits almost entirely in storage: the three largest clusters are built from tsdb, labels, chunkenc, and wlog, with the scrape loop, service discovery, and remote write arranged around them.

The clearest structural signal is where the cycles are. All 8 dependency cycles live in the web UI (web/ui/react-app, web/ui/mantine-ui, and the codemirror-promql module). The Go packages that make up the server have none.

Module map

The diagram shows the 10 largest of the 53 detected modules, with edges weighted by how many calls cross between them. The biggest holds 855 symbols and its hub is tsdb.memChunk.len, which puts the chunk layer at the center of the codebase. Module names come from the packages their members live in; the symbol counts, hubs, and edge weights are what the graph computed.

prometheus/prometheus module map: the 10 largest of 53 detected modules with call-weighted edges, generated by Symvanta
Module map of prometheus/prometheus, generated by Symvanta. Link to this diagram Open full size

Where to start reading

These are the most depended-upon symbols by PageRank over the call graph, followed by the HTTP surface registered in web/web.go. Four entries from the raw ranking are left out below: Set, Put, Inc, and Error are one-word Go methods that dozens of packages define independently, and the graph groups them by name, so they rank high without pointing anywhere useful.

  • tsdb.memChunk.len
  • tsdbutil.DirLocker.Lock
  • stats.Timer.Duration
  • Appender
  • encoding.Encbuf.PutUvarint
  • labels.NewMatcher
  • scrape.foreachAppendable
  • chunkenc.bstream.bytes
  • GET /graph
  • GET /federate
  • GET /consoles/*filepath
  • GET /user/*filepath
  • GET /-/healthy
  • HEAD /-/healthy
  • GET /-/ready
  • HEAD /-/ready
  • GET /-/quit
  • GET /-/reload

Key subsystems

tsdb chunks and label matching

Chunk access (tsdb.memChunk.len, chunkenc.NewNopIterator) sits with label handling (labels.NewFastRegexMatcher, strutil.SanitizeLabelName) and postings iteration inside one 855-symbol cluster, because a query touches all three on its way to a sample.

tsdb head and WAL

The mutable half of the database: the recent window held in memory and the log that lets it survive a restart. 628 symbols covering tsdb.open, tsdb.NewHead, tsdb.DefaultHeadOptions, and the write-ahead log (wlog.NewSize, wlog.WL.Log).

Storage append and iterate

Everything that writes samples passes through the Appender and Iterator interfaces collected here, including the newer AppenderV2. The two heaviest edges on the map run between this 812-symbol cluster and the head and WAL cluster: 262 calls out, 319 back.

HTTP API v1

Where the query engine meets the network. apiFuncResult, apiError, Query, and SearchResult read from the storage clusters and shape what goes back over the wire, 486 symbols in all.

Config loading and file handling

config.LoadFile, fileutil.Flock, tombstone writes, decode buffers: 517 symbols of plumbing that every other cluster calls. Its PageRank hub is the bare Error method, which is what a cluster in that position looks like in Go.

Scrape loop and appendables

scrape.foreachAppendable and the appendable test doubles, 311 symbols. The ingest path shows up in two edge weights: 56 calls into the discovery registry, 44 into the append interfaces.

Canonical request flow

The sequence worth reading first is the database opening. Lock the data directory, clear temporary state, open the write-ahead log and repair it if the process died mid-write, build the chunk pool and the compactor, then create the head block and replay the WAL into it. Every step below is a call edge out of tsdb.open, in the order the work happens.

  1. tsdb.Open (tsdb/db.go:910)
  2. tsdb.open (tsdb/db.go:992)
  3. tsdbutil.NewDirLocker
  4. tsdbutil.DirLocker.Lock
  5. tsdbutil.RemoveTmpDirs
  6. wlog.DeleteTempCheckpoints
  7. wlog.NewSize
  8. wlog.WL.Repair
  9. chunkenc.NewPool
  10. tsdb.NewLeveledCompactorWithOptions
  11. tsdb.NewHead
  12. tsdb.Head.Init

Health signals

Symvanta detected 8 dependency cycles across 53 modules (modularity Q=0.71). The largest cycle spans 16 files in the graph area. 10 sets of mutually recursive symbols were also detected, the largest being promql (9 symbols).

See your own codebase mapped like this.

Book a demo →

Auto-generated by Symvanta from the public repo prometheus/prometheus at commit e75af38 , licensed Apache-2.0 .

Machine-readable companion: data.json (module counts, subsystems, load-bearing symbols, health signals).

Get this for your codebase →