Explains Loki, a label based log aggregation system that indexes metadata instead of full text to reduce storage costs and integrate with Prometheus and Grafana.
Think of walking into a library looking for a book and noticing what the library did not do.Nobody read every page of every book and wrote down where each word appears. Instead, each book carries a few labels on its spine: the author, the subject, the shelf it lives on. Those few labels are enough to lead you straight to what you want among thousands of books.
Loki organizes logs the same way.A log line usually contains a message plus a small set of contextual labels that describe its source (for example which job produced it, which service, or which environment it runs in). One approach to searchable logs is to index every word in every line (full-text indexing). Systems like Elasticsearch do this — it’s powerful but the index grows large (often approaching the size of the logs themselves), meaning you pay to store logs twice and you need to operate and tune the indexing stack.Example of raw log lines:
job=apilogs POST /login 200job=varlogs cron started okjob=apilogs GET /users 404job=syslog disk usage 81%job=apilogs db timeout errjob=varlogs ssh session new
Loki takes the library approach instead. It indexes only the small set of labels attached to each log stream — analogous to the labels on a book’s spine — and does not index the full text of every log line. The full log text is stored separately in compressed chunks and is scanned only after you select the relevant streams.Smaller example showing labels vs log text:
# Indexed labels (small index){job="apilogs", env="production"}# Full log text kept in compressed chunks (not indexed)POST /login 200GET /users 200db timeout err retry=1
How that looks in practiceEvery stream of logs in Loki is identified by a set of labels. Labels are small key/value pairs such as job, env, or service. Loki builds an index over those labels and nothing else. When you query, you first select streams using label matchers and then Loki scans the log lines inside those selected streams (the compressed chunks).Examples of label sets and selectors:
# A typical stream's label set{job="apilogs", env="production"}# Common selectors you would use to pick streams{job="apilogs"}{env="production"}{job="varlogs"}
Under the hood, Loki separates the small label index from the larger compressed log data. The index stays compact because labels typically have low cardinality, while the log text is stored in chunks that are cheaper to store and only decompressed when needed.Illustrative index and chunk separation:
If you already use Prometheus, Loki will feel familiar. Loki reuses Prometheus’ label model and its query language, LogQL, is deliberately similar to PromQL. That similarity makes it straightforward to correlate logs and metrics during troubleshooting.Example: PromQL vs LogQL
# Prometheus metric queryrate(http_requests[5m])# LogQL-style selector (pattern similar to PromQL label selection){job="apilogs"}rate({job="apilogs"}[5m])
Loki integrates directly with Grafana so logs, metrics, and dashboards live together. Use LogQL to filter streams with label matchers first, then inspect log line contents from the selected streams.
Quick comparison: full-text indexing vs Loki
Aspect
Full-text indexing (e.g., Elasticsearch)
Loki (label-based indexing)
Indexed content
Entire log text (every word)
Only small set of labels (job, env, service)
Index size
Large — can approach log size
Small — low-cardinality labels keep it compact
Storage cost
Higher (logs + large index)
Lower (compressed chunks + small index)
Query flow
Search text across index
Select streams by labels, then scan chunks
Good for
Free-text search across many fields
Correlating logs with metrics and efficient retention
Labels: keep them low-cardinality and meaningfulLabels are intended for low-cardinality attributes — the few properties that describe where a log came from. Examples of appropriate labels include job, env, and service. These should each have a small set of possible values so the label index remains compact and efficient. High-cardinality values (request IDs, session IDs, user IDs, timestamps at millisecond precision) should remain inside the log text. Loki can still search those values in the log content when needed, but it does not index them by default.
Avoid using high-cardinality values as labels (for example request_id or per-request timestamps). These explode the label index and negate Loki’s cost and performance advantages.
Good label examples:
job, service, env, region
Bad label examples (keep these in the log message instead):
Next stepsKeeping labels few and meaningful preserves Loki’s performance and cost benefits. Next, we will explore Loki’s architecture and trace a log line from the application that writes it through to how it is stored and queried in Loki.Links and references