Skip to content
Labels vs Free Text
step 1/5

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…