Portal Community

The Golden Rule: Low-Cardinality Labels Only

A label's cardinality is the number of unique values it can take. Labels should have bounded, low cardinality:

BizFirstGO Standard Label Set

LabelSourceExample ValuesCardinalityPurpose
jobOTel resource service.nameprocessengine, edgestream, octopus, api, worker<10Broad service category filtering
serviceOTel resource service.nameflow-studio-api, processengine-worker<50Specific service name
environmentOTel resource deployment.environmentproduction, staging, development<5Environment separation
levelOTel LogRecord severitytrace, debug, info, warn, error, fatal6Log severity filtering
tenant_idOTel log attribute tenant.idtenant-abc, tenant-xyzHundredsMulti-tenant isolation

Stream Count Estimation

Total unique streams = product of unique values of each label. For BizFirstGO:

# Stream count estimate:
jobs:        5 (processengine, edgestream, octopus, api, worker)
environments: 3 (prod, staging, dev)
levels:      6 (trace, debug, info, warn, error, fatal)
tenants:     500 (example: 500 tenant deployment)

Total streams = 5 × 3 × 6 × 500 = 45,000 streams

# This is within Loki's comfortable range (<100,000 streams).
# Adding execution_id as a label (say, 1M executions/day) would create:
# 5 × 3 × 6 × 500 × 1,000,000 = 45 BILLION streams → catastrophic

What Goes in the Log Line (Not Labels)

High-cardinality context belongs in the structured log body. Loki can filter on log line content using |=, |~, | json — just more slowly than label filtering. This trade-off is acceptable because you almost always start a query with a label selector that narrows the result set before content filtering.

# High-cardinality values in the log body (JSON format)
{
  "timestamp": "...",
  "level": "error",        ← label ✓
  "service": "processengine", ← label ✓
  "tenant_id": "t123",     ← label ✓
  "message": "Node failed",
  "executionId": "exec-abc123",  ← log body, not label ✓
  "nodeKey": "approval-01",      ← log body, not label ✓
  "traceId": "4bf92f...",        ← log body, not label ✓
  "workflowId": "wf-xyz"         ← log body, not label ✓
}
Pattern for Finding Specific Executions

Start with label selector (fast, indexed) → then filter on log body content (slower, but applied to small result set):

{job="processengine", tenant_id="t123", level="error"} |= "executionId=exec-abc123"

Label Naming Conventions