RousselTMLEARNING

Observability

Grafana Loki best practices: labels, queries, storage and costs

Loki best practices: choosing labels and cardinality, structured metadata, efficient LogQL queries, structured logs, retention, limits, multi-tenant security and review checklist.

1. Labels: the golden rule #

Few, stable, bounded.

Choosing your labels #

Available in: ✓ OSS ✓ Enterprise ✓ Cloud Loki open source, Enterprise Logs and Grafana Cloud Logs

Loki best practices
Label cardinality determines costs and performance.
Good labelBad labelWhy
app, namespace, envuser_id, ipEach value = a separate stream
level (5 values)request_id, trace_idUnbounded cardinality
cluster, jobFull url, timestampExplosion in the number of streams
# Analyser la cardinalité
logcli series '{env="prod"}' --since=1h --analyze-labels
logcli labels pod --since=24h | wc -l
sum(loki_ingester_memory_streams)
# Déplacer l'information à forte cardinalité en structured metadata
stage.structured_metadata { values = { trace_id = "" } }
Common mistake: Do not exceed a few tens of thousands of active streams per tenant without sizing the ingesters accordingly.

2. Usable logs #

Structuring at the source.

Format and levels #

  • Log in JSON or logfmt with level, msg, trace_id, service.
  • One line = one event; avoid ungrouped multiline stack traces (stage.multiline).
  • Normalize levels (debug, info, warn, error) and reduce the debug level in production.
loki.process "app" {
  forward_to = [loki.write.default.receiver]
  stage.multiline { firstline = "^\\d{4}-\\d{2}-\\d{2}"  max_wait_time = "3s" }
  stage.json      { expressions = { level = "level", trace_id = "trace_id" } }
  stage.labels    { values = { level = "" } }
  stage.structured_metadata { values = { trace_id = "" } }
  stage.drop      { expression = ".*healthcheck.*" }
}

3. Fast queries #

Efficient LogQL.

Rules #

# ✅ Sélecteur précis + filtre de ligne AVANT le parseur
{app="checkout", env="prod"} |= "error" | json | status >= 500
# ❌ Sélecteur large puis tout filtrer après parsing
{env="prod"} | json | app="checkout" | status >= 500

# Mesurer ce qu'une requête lit
logcli query '{app="checkout"} |= "error"' --since=6h --stats
# Précalculer ce qui est demandé souvent (recording rule)
- record: app:log_errors:rate5m
  expr: sum by (app) (rate({env="prod"} |= "error" [5m]))
  • Reduce the time range and the number of streams before refining.
  • Prefer pattern or logfmt to regexp.
  • Enable the results cache and the Query Frontend for dashboards.

4. Costs, security and review #

Staying in control.

Retention and limits #

limits_config:
  retention_period: 744h
  retention_stream:
    - { selector: '{env="dev"}',   priority: 1, period: 72h }
    - { selector: '{app="audit"}', priority: 2, period: 8760h }
  ingestion_rate_mb: 10
  per_stream_rate_limit: 5MB
  max_streams_per_user: 100000
# Suivre ce qui est rejeté
sum by (reason) (rate(loki_discarded_samples_total[5m]))
Review questionExpected answer
How many active streams per tenant?Monitored and bounded by max_streams_per_user
Personal data in the logs?Masked at the source (stage.replace)
Retention differentiated by criticality?Yes (short for dev, long for audit)
Isolation between teams?Separate tenants, authentication in front of Loki
Good practice: Measure the cost per application (bytes ingested) and share it with the teams: it is the best lever for reducing noise.

Reference diagram and quick check #

Visualize the principle and check it from the command line.

Reference diagram #

Active streams depending on labels
Watch loki_ingester_memory_streams.
sum(loki_ingester_memory_streams)
logcli series '{env="prod"}' --since=1h --analyze-labels

Related articles

The LGTM stack (Loki, Grafana, Tempo, Mimir): architecture and setup

Understand Grafana Labs' LGTM stack: Loki for logs, Grafana for visualization, Tempo for traces and Mimir for…

Grafana Loki: the Prometheus-inspired log system

Discover Grafana Loki: the label-indexing philosophy, architecture (distributor, ingester, querier, compactor…

Installing Grafana Loki (Docker Compose, binary and Helm)

Install and validate Grafana Loki: minimal configuration, Docker Compose with Grafana and Alloy, binary insta…

Keep learning

Support us

♥ SUPPORT US

Support RousselTM Learning

Courses, articles, labs and certificates stay free with no intrusive ads. A voluntary contribution, of any amount you choose, pays for hosting, lab environments and new content.

Contribute with PayPal Any amount · card or PayPal accountLearn more
QR code PayPal
Or scan this QR code with your phone

Thank you, every contribution counts!