Reading — step 1 of 5
Read
~1 min readIngestion
Labels vs Free Text
Modern log systems split log data into:
- Structured labels:
{env=prod, service=api, level=error, host=ip-10-0-1-23}. Low cardinality. Indexed. - Log line (free text): arbitrary message. Searched by full-text or substring.
Why separate?
- Indexing every word of every log = expensive (Elasticsearch's pain). Indexing labels only = cheap (Loki's win).
- Queries usually filter by label first (e.g.,
service=api AND level=error), THEN scan matching log lines for substring.
Cardinality matters: each unique label combination = one stream. If you put request_id as a label, you get 1 stream per request — explodes. Rule: labels should be a few hundred or thousand combos, not millions.
GOOD labels: env, service, level, host, region, k8s_pod_name (in many setups)
BAD labels: user_id, request_id, trace_id, full URL
For high-cardinality fields, store them in the log MESSAGE (free text) and search there.
In our system:
POST /push
{
"streams": [
{ "labels": "{env=prod,service=api}", "values": [["1778042096","ERROR: db conn lost"], ...] }
]
}
Each (labels, time, line) triple is a log entry. Labels are interned to a stream ID for storage.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…