
Loki Config Generator
- 360 installs
- 286 repo stars
- Updated July 26, 2026
- akin-ozer/cc-devops-skills
loki-config-generator is a Claude Code skill that produces Grafana Loki configuration for ingestion, retention, storage backends, limits, and compactor settings for developers standing up centralized logging.
About
loki-config-generator is a DevOps skill from akin-ozer/cc-devops-skills that generates production-ready Grafana Loki YAML for centralized log aggregation. The skill addresses ingestion pipelines, retention policies, storage backend selection, rate limits, and compactor tuning so teams can deploy Loki without hand-writing every operational knob. Developers reach for loki-config-generator when bootstrapping observability stacks on Kubernetes or bare metal, migrating from file-based logging, or tuning retention and storage costs. Output targets standard Loki config files ready for Helm, Docker Compose, or direct daemon deployment.
- Ingestion and retention policy templates
- Storage and schema period setup
- Limits and cardinality guardrails
- Compactor and ruler configuration stubs
Loki Config Generator by the numbers
- 360 all-time installs (skills.sh)
- Ranked #317 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/akin-ozer/cc-devops-skills --skill loki-config-generatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 360 |
|---|---|
| repo stars | ★ 286 |
| Last updated | July 26, 2026 |
| Repository | akin-ozer/cc-devops-skills ↗ |
How do you configure Grafana Loki ingestion and retention?
Produce Loki configuration for ingestion, retention, storage backends, limits, and compactor settings when standing up centralized logging.
Who is it for?
Platform and SRE engineers deploying Grafana Loki who need structured config for ingestion, retention, and storage backends.
Skip if: Teams using Elasticsearch, CloudWatch Logs, or Datadog exclusively with no Loki deployment planned.
When should I use this skill?
A developer needs Loki config for ingestion, retention, storage backends, limits, or compactor settings during logging stack setup.
What you get
Loki configuration YAML with ingestion, retention, storage backend, limits, and compactor blocks.
- loki.yaml config
- retention and limits blocks
Files
Loki Configuration Generator
Overview
Generate production-ready Grafana Loki server configurations with best practices. Supports monolithic, simple scalable, and microservices deployment modes with S3, GCS, Azure, or filesystem storage.
Current Stable: Loki 3.6.2 (November 2025)
Important: Promtail deprecated in 3.4 - use Grafana Alloy instead. Seeexamples/grafana-alloy.alloyfor the Alloy pipeline andexamples/grafana-alloy-daemonset.yamlfor the Kubernetes deployment.
When to Use
Invoke when: deploying Loki, creating configs from scratch, migrating to Loki, implementing multi-tenant logging, configuring storage backends, or optimizing existing deployments.
---
Generation Methods
Method 1: Script Generation (Recommended)
Use `scripts/generate_config.py` for consistent, validated configurations:
# Simple Scalable with S3 (production)
python3 scripts/generate_config.py \
--mode simple-scalable \
--storage s3 \
--bucket my-loki-bucket \
--region us-east-1 \
--retention-days 30 \
--otlp-enabled \
--output loki-config.yaml
# Monolithic with filesystem (development)
python3 scripts/generate_config.py \
--mode monolithic \
--storage filesystem \
--no-auth-enabled \
--output loki-dev.yaml
# Production with Thanos storage (Loki 3.4+)
python3 scripts/generate_config.py \
--mode simple-scalable \
--storage s3 \
--thanos-storage \
--otlp-enabled \
--time-sharding \
--output loki-thanos.yamlScript Options:
| Option | Description |
|---|---|
--mode | monolithic, simple-scalable, microservices |
--storage | filesystem, s3, gcs, azure |
--auth-enabled / --no-auth-enabled | Explicitly enable/disable auth |
--otlp-enabled | Enable OTLP ingestion configuration |
--thanos-storage | Use Thanos object storage client (3.4+, cloud backends) |
--time-sharding | Enable out-of-order ingestion (simple-scalable) |
--ruler | Enable alerting/recording rules (not monolithic) |
--horizontal-compactor | main/worker mode (simple-scalable, 3.6+) |
--zone-awareness | Enable multi-AZ placement safeguards |
--limits-dry-run | Log limit rejections without enforcing |
Method 2: Manual Configuration
Follow the staged workflow below when script generation doesn't meet specific requirements or when learning the configuration structure.
Output Formats
For Kubernetes deployments, generate BOTH formats: 1. Native Loki config (loki-config.yaml) - For ConfigMap or direct use 2. Helm values (values.yaml) - For Helm chart deployments
See examples/kubernetes-helm-values.yaml for Helm format.
---
Documentation Lookup
When to Use Context7/Web Search
REQUIRED - Use Context7 MCP for:
- Configuring features from Loki 3.4+ (Thanos storage, time sharding)
- Configuring features from Loki 3.6+ (horizontal compactor, enforced labels)
- Bloom filter configuration (complex, experimental)
- Custom OTLP attribute mappings beyond standard patterns
- Troubleshooting configuration errors
OPTIONAL - Skip documentation lookup for:
- Standard deployment modes (monolithic, simple-scalable)
- Basic storage configuration (S3, GCS, Azure, filesystem)
- Default limits and component settings
- Configurations covered in
references/directory
Context7 MCP (preferred)
resolve-library-id: "grafana loki"
get-library-docs: /websites/grafana_loki, topic: [component]Example topics: storage_config, limits_config, otlp, compactor, ruler, bloom
Web Search Fallback
Use when Context7 unavailable: "Grafana Loki 3.6 [component] configuration documentation site:grafana.com"
---
Configuration Workflow
Stage 1: Gather Requirements
Deployment Mode:
| Mode | Scale | Use Case |
|---|---|---|
| Monolithic | <100GB/day | Testing, development |
| Simple Scalable | 100GB-1TB/day | Production |
| Microservices | >1TB/day | Large-scale, multi-tenant |
Storage Backend: S3, GCS, Azure Blob, Filesystem, MinIO
Key Questions: Expected log volume? Retention period? Multi-tenancy needed? High availability requirements? Kubernetes deployment?
Ask the user directly if required information is missing.
Stage 2: Schema Configuration (CRITICAL)
For all new deployments (Loki 2.9+), use TSDB with v13 schema:
schema_config:
configs:
- from: "2025-01-01" # Use deployment date
store: tsdb
object_store: s3 # s3, gcs, azure, filesystem
schema: v13
index:
prefix: loki_index_
period: 24hKey: Schema cannot change after deployment without migration.
Stage 3: Storage Configuration
S3:
common:
storage:
s3:
s3: s3://us-east-1/loki-bucket
s3forcepathstyle: falseGCS: gcs: { bucket_name: loki-bucket } Azure: azure: { container_name: loki-container, account_name: ${AZURE_ACCOUNT_NAME} } Filesystem: filesystem: { chunks_directory: /loki/chunks, rules_directory: /loki/rules }
Stage 4: Component Configuration
Ingester:
ingester:
chunk_encoding: snappy
chunk_idle_period: 30m
max_chunk_age: 2h
chunk_target_size: 1572864 # 1.5MB
lifecycler:
ring:
replication_factor: 3 # 3 for productionQuerier:
querier:
max_concurrent: 4
query_timeout: 1mCompactor:
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2hStage 5: Limits Configuration
limits_config:
ingestion_rate_mb: 10
ingestion_burst_size_mb: 20
max_streams_per_user: 10000
max_entries_limit_per_query: 5000
max_query_length: 721h
retention_period: 30d
allow_structured_metadata: true
volume_enabled: trueStage 6: Server & Auth
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
auth_enabled: true # false for single-tenantStage 7: OTLP Ingestion (Loki 3.0+)
Native OpenTelemetry ingestion - use otlphttp exporter (NOT deprecated lokiexporter):
limits_config:
allow_structured_metadata: true
otlp_config:
resource_attributes:
attributes_config:
- action: index_label # Low-cardinality only!
attributes: [service.name, service.namespace, deployment.environment]
- action: structured_metadata # High-cardinality
attributes: [k8s.pod.name, service.instance.id]Actions: index_label (searchable, low-cardinality), structured_metadata (queryable), drop
⚠️ NEVER use `k8s.pod.name` as index_label - use structured_metadata instead.
OTel Collector:
exporters:
otlphttp:
endpoint: http://loki:3100/otlpStage 8: Caching
chunk_store_config:
chunk_cache_config:
memcached_client:
host: memcached-chunks
timeout: 500ms
query_range:
cache_results: true
results_cache:
cache:
memcached_client:
host: memcached-resultsStage 9: Advanced Features
Pattern Ingester (3.0+):
pattern_ingester:
enabled: trueBloom Filters (Experimental, 3.3+): Only for >75TB/month deployments. Works on structured metadata only. See examples/ for config.
Time Sharding (3.4+): For out-of-order ingestion:
limits_config:
shard_streams:
time_sharding_enabled: trueThanos Storage (3.4+): New storage client, opt-in now, default later:
storage_config:
use_thanos_objstore: true
object_store:
s3:
bucket_name: my-bucket
endpoint: s3.us-west-2.amazonaws.comStage 10: Ruler (Alerting)
ruler:
storage:
type: s3
s3: { bucket_name: loki-ruler }
alertmanager_url: http://alertmanager:9093
enable_api: true
enable_sharding: trueStage 11: Loki 3.6 Features
- Horizontally Scalable Compactor:
horizontal_scaling_mode: main|worker - Policy-Based Enforced Labels:
enforced_labels: [service.name] - FluentBit v4:
structured_metadataparameter support
Stage 12: Validate Configuration (REQUIRED)
Always validate before deployment:
# Syntax and parameter validation
loki -config.file=loki-config.yaml -verify-config
# Print resolved configuration (shows defaults)
loki -config.file=loki-config.yaml -print-config-stderr 2>&1 | head -100
# Dry-run with Docker (if Loki not installed locally)
docker run --rm -v $(pwd)/loki-config.yaml:/etc/loki/config.yaml \
grafana/loki:3.6.2 -config.file=/etc/loki/config.yaml -verify-configValidation Checklist:
- [ ] No syntax errors from
-verify-config - [ ] Schema uses
tsdbandv13 - [ ]
replication_factor: 3for production - [ ]
auth_enabled: trueif multi-tenant - [ ] Storage credentials/IAM configured
- [ ] Retention period matches requirements
---
Production Checklist
High Availability Requirements
Zone-Aware Replication (CRITICAL for production multi-AZ deployments):
When using replication_factor: 3, ALWAYS enable zone-awareness for multi-AZ deployments:
ingester:
lifecycler:
ring:
replication_factor: 3
zone_awareness_enabled: true # CRITICAL for multi-AZ
# Set zone via environment variable or config
# Each pod should set its zone based on node topology
common:
instance_availability_zone: ${AVAILABILITY_ZONE}Why: Without zone-awareness, all 3 replicas may land in the same AZ. If that AZ fails, you lose data.
Kubernetes Implementation:
# In Helm values or pod spec
env:
- name: AVAILABILITY_ZONE
valueFrom:
fieldRef:
fieldPath: metadata.labels['topology.kubernetes.io/zone']TLS Configuration (Production Required)
Enable TLS for all inter-component and client communication:
server:
http_tls_config:
cert_file: /etc/loki/tls/tls.crt
key_file: /etc/loki/tls/tls.key
client_ca_file: /etc/loki/tls/ca.crt # For mTLS
grpc_tls_config:
cert_file: /etc/loki/tls/tls.crt
key_file: /etc/loki/tls/tls.key
client_ca_file: /etc/loki/tls/ca.crtSee examples/production-tls.yaml for complete TLS configuration.
Production Checklist Summary
| Requirement | Setting | Required For |
|---|---|---|
replication_factor: 3 | common block | All production |
zone_awareness_enabled: true | ingester.lifecycler.ring | Multi-AZ |
auth_enabled: true | root level | Multi-tenant |
| TLS enabled | server block | All production |
| IAM roles (not keys) | storage config | Cloud storage |
| Caching enabled | chunk_store_config, query_range | Performance |
| Pattern ingester | pattern_ingester.enabled | Observability |
| Retention configured | compactor + limits_config | Cost control |
---
Monitoring Recommendations
Key Metrics to Monitor
Configure Prometheus to scrape Loki metrics and alert on these critical indicators:
# Prometheus scrape config
- job_name: 'loki'
static_configs:
- targets: ['loki:3100']Critical Alerts
groups:
- name: loki-critical
rules:
# Ingestion failures
- alert: LokiIngestionFailures
expr: sum(rate(loki_distributor_ingester_append_failures_total[5m])) > 0
for: 5m
labels:
severity: critical
annotations:
summary: "Loki ingestion failures detected"
# High stream cardinality (performance killer)
- alert: LokiHighStreamCardinality
expr: loki_ingester_memory_streams > 100000
for: 10m
labels:
severity: warning
annotations:
summary: "High stream cardinality - review labels"
# Compaction not running (retention broken)
- alert: LokiCompactionStalled
expr: time() - loki_compactor_last_successful_run_timestamp_seconds > 7200
for: 5m
labels:
severity: critical
annotations:
summary: "Loki compaction stalled - retention not enforced"
# Query latency
- alert: LokiSlowQueries
expr: histogram_quantile(0.99, sum(rate(loki_request_duration_seconds_bucket{route=~"loki_api_v1_query.*"}[5m])) by (le)) > 30
for: 10m
labels:
severity: warning
annotations:
summary: "Loki query P99 latency > 30s"
# Ingester memory pressure
- alert: LokiIngesterMemoryHigh
expr: container_memory_usage_bytes{container="ingester"} / container_spec_memory_limit_bytes{container="ingester"} > 0.8
for: 10m
labels:
severity: warning
annotations:
summary: "Loki ingester memory usage > 80%"Key Metrics Reference
| Metric | Description | Action Threshold |
|---|---|---|
loki_ingester_memory_streams | Active streams in memory | >100k: review cardinality |
loki_distributor_ingester_append_failures_total | Ingestion failures | >0: investigate immediately |
loki_request_duration_seconds | Query latency | P99 >30s: add caching/queriers |
loki_ingester_chunks_flushed_total | Chunk flush rate | Low rate: check ingester health |
loki_compactor_last_successful_run_timestamp_seconds | Last compaction | >2h ago: compaction broken |
Grafana Dashboard
Import official Loki dashboards:
- Dashboard ID:
13407- Loki Logs - Dashboard ID:
14055- Loki Operational
---
Log Collection with Grafana Alloy
Promtail is deprecated (support ends Feb 2026). Use Grafana Alloy for new deployments.
Basic Alloy Configuration
See examples/grafana-alloy.alloy for the Alloy pipeline and examples/grafana-alloy-daemonset.yaml for the Kubernetes deployment.
// Kubernetes log discovery
discovery.kubernetes "pods" {
role = "pod"
}
// Relabeling for Kubernetes metadata
discovery.relabel "pods" {
targets = discovery.kubernetes.pods.targets
rule {
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
rule {
source_labels = ["__meta_kubernetes_pod_name"]
target_label = "pod"
}
rule {
source_labels = ["__meta_kubernetes_pod_container_name"]
target_label = "container"
}
}
// Log collection
loki.source.kubernetes "pods" {
targets = discovery.relabel.pods.output
forward_to = [loki.write.default.receiver]
}
// Send to Loki
loki.write "default" {
endpoint {
url = "http://loki-gateway.loki.svc.cluster.local/loki/api/v1/push"
// For multi-tenant
tenant_id = "default"
}
}Migration from Promtail
# Convert Promtail config to Alloy
alloy convert --source-format=promtail --output=alloy-config.alloy promtail.yaml---
Complete Examples
See examples/ directory for full configurations:
monolithic-filesystem.yaml- Development/testingsimple-scalable-s3.yaml- Production with S3microservices-s3.yaml- Large-scale distributedmulti-tenant.yaml- Multi-tenant with per-tenant limitsproduction-tls.yaml- TLS-enabled production configgrafana-alloy.alloy- Log collection pipeline with Alloygrafana-alloy-daemonset.yaml- Kubernetes DaemonSet for Alloykubernetes-helm-values.yaml- Helm chart values
Minimal Monolithic:
auth_enabled: false
server:
http_listen_port: 3100
common:
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
schema_config:
configs:
- from: 2025-01-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: loki_index_
period: 24h
limits_config:
retention_period: 30d
allow_structured_metadata: true
compactor:
working_directory: /loki/compactor
retention_enabled: true---
Helm Deployment
helm repo add grafana https://grafana.github.io/helm-charts
helm install loki grafana/loki -f values.yamlGenerate both native config and Helm values for Kubernetes deployments.
# values.yaml
deploymentMode: SimpleScalable
loki:
schemaConfig:
configs:
- from: "2025-01-01"
store: tsdb
object_store: s3
schema: v13
index:
prefix: loki_index_
period: 24h
limits_config:
retention_period: 30d
allow_structured_metadata: true
# Zone awareness for HA
ingester:
lifecycler:
ring:
zone_awareness_enabled: true
backend:
replicas: 3
# Spread across zones
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
read:
replicas: 3
write:
replicas: 3---
Best Practices
Performance:
chunk_encoding: snappy,chunk_target_size: 1572864- Enable caching (chunks, results)
parallelise_shardable_queries: true
Security:
auth_enabled: truewith reverse proxy auth- IAM roles for cloud storage (never hardcode keys)
- TLS for all communications (see Production Checklist)
Reliability:
replication_factor: 3for productionzone_awareness_enabled: truefor multi-AZ (see Production Checklist)- Persistent volumes for ingesters
- Monitor ingestion rate and query latency (see Monitoring section)
Limits: Set ingestion_rate_mb, max_streams_per_user to prevent overload
---
Common Issues
| Issue | Solution |
|---|---|
| High ingester memory | Reduce max_streams_per_user, lower chunk_idle_period |
| Slow queries | Increase max_concurrent, enable parallelization, add caching |
| Ingestion failures | Check ingestion_rate_mb, verify storage connectivity |
| Storage growing fast | Enable retention, check compression, review cardinality |
| Data loss in AZ failure | Enable zone_awareness_enabled: true |
| Config validation fails | Run loki -verify-config, check YAML syntax |
---
Deprecated (Migrate Away)
boltdb-shipper→tsdblokiexporter→otlphttp- Promtail → Grafana Alloy (support ends Feb 2026)
---
Resources
scripts/generate_config.py - Generate configs programmatically (RECOMMENDED) examples/ - Complete configuration examples for all modes references/ - Full parameter reference and best practices
Related Skills
- logql-generator - LogQL query generation
- fluentbit-generator - Log collection to Loki
# Kubernetes DaemonSet deployment for Grafana Alloy
# Pair with grafana-alloy.alloy mounted as /etc/alloy/config.alloy.
---
apiVersion: v1
kind: Namespace
metadata:
name: alloy
---
apiVersion: v1
kind: ConfigMap
metadata:
name: alloy-config
namespace: alloy
data:
config.alloy: |
// Paste the contents of grafana-alloy.alloy here.
// Or mount that file from a separate ConfigMap.
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: alloy
namespace: alloy
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: alloy
rules:
- apiGroups:
- ""
resources:
- nodes
- nodes/proxy
- nodes/metrics
- services
- endpoints
- pods
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- nonResourceURLs:
- /metrics
- /metrics/cadvisor
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: alloy
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: alloy
subjects:
- kind: ServiceAccount
name: alloy
namespace: alloy
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alloy
namespace: alloy
labels:
app.kubernetes.io/name: alloy
spec:
selector:
matchLabels:
app.kubernetes.io/name: alloy
template:
metadata:
labels:
app.kubernetes.io/name: alloy
spec:
serviceAccountName: alloy
tolerations:
- effect: NoSchedule
operator: Exists
containers:
- name: alloy
image: grafana/alloy:v1.4.0
args:
- run
- /etc/alloy/config.alloy
- --storage.path=/var/lib/alloy/data
- --server.http.listen-addr=0.0.0.0:12345
ports:
- containerPort: 12345
name: http
protocol: TCP
env:
- name: HOSTNAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
volumeMounts:
- name: config
mountPath: /etc/alloy
- name: varlog
mountPath: /var/log
readOnly: true
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: data
mountPath: /var/lib/alloy/data
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
add:
- DAC_READ_SEARCH
readOnlyRootFilesystem: true
volumes:
- name: config
configMap:
name: alloy-config
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: data
emptyDir: {}
# Grafana Alloy Configuration for Loki Log Collection
# Replaces deprecated Promtail (support ends Feb 2026)
# Reference: https://grafana.com/docs/alloy/latest/
#
# Deploy as DaemonSet in Kubernetes to collect logs from all pods
# This file is in Alloy's River configuration format (.alloy extension)
#
# Save as: alloy-config.alloy
# Run with: alloy run alloy-config.alloy
// =============================================================================
// DISCOVERY: Find Kubernetes pods to collect logs from
// =============================================================================
discovery.kubernetes "pods" {
role = "pod"
}
// =============================================================================
// RELABELING: Extract Kubernetes metadata as labels
// =============================================================================
discovery.relabel "pods" {
targets = discovery.kubernetes.pods.targets
// Keep only running pods
rule {
source_labels = ["__meta_kubernetes_pod_phase"]
regex = "Pending|Succeeded|Failed|Unknown"
action = "drop"
}
// Namespace label
rule {
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
// Pod name (stored as structured metadata due to high cardinality)
rule {
source_labels = ["__meta_kubernetes_pod_name"]
target_label = "pod"
}
// Container name
rule {
source_labels = ["__meta_kubernetes_pod_container_name"]
target_label = "container"
}
// App label (common label for service identification)
rule {
source_labels = ["__meta_kubernetes_pod_label_app"]
target_label = "app"
}
// App.kubernetes.io/name label (standard K8s label)
rule {
source_labels = ["__meta_kubernetes_pod_label_app_kubernetes_io_name"]
target_label = "app"
}
// Node name
rule {
source_labels = ["__meta_kubernetes_pod_node_name"]
target_label = "node"
}
// Controller name (deployment, statefulset, etc.)
rule {
source_labels = ["__meta_kubernetes_pod_controller_name"]
target_label = "controller"
}
// Controller kind
rule {
source_labels = ["__meta_kubernetes_pod_controller_kind"]
target_label = "controller_kind"
}
// Set log file path
rule {
source_labels = ["__meta_kubernetes_pod_uid", "__meta_kubernetes_pod_container_name"]
target_label = "__path__"
separator = "/"
replacement = "/var/log/pods/*$1/$2/*.log"
}
}
// =============================================================================
// LOG COLLECTION: Read logs from Kubernetes pods
// =============================================================================
loki.source.kubernetes "pods" {
targets = discovery.relabel.pods.output
forward_to = [loki.process.pipeline.receiver]
}
// =============================================================================
// LOG PROCESSING: Parse and enrich logs
// =============================================================================
loki.process "pipeline" {
forward_to = [loki.write.default.receiver]
// Parse JSON logs (if applicable)
stage.json {
expressions = {
level = "level",
message = "msg",
// Extract trace_id and span_id for correlation
trace_id = "trace_id",
span_id = "span_id",
}
}
// Fallback: Extract level from log line
stage.regex {
expression = "(?P<level>DEBUG|INFO|WARN|ERROR|FATAL)"
}
// Add level label if extracted
stage.labels {
values = {
level = "",
}
}
// Store high-cardinality data as structured metadata (Loki 3.0+)
// This prevents label cardinality explosion
stage.structured_metadata {
values = {
trace_id = "",
span_id = "",
// Pod name moved to structured metadata (high cardinality)
pod_name = "pod",
}
}
// Timestamp parsing (if logs have custom timestamps)
stage.timestamp {
source = "timestamp"
format = "RFC3339"
}
// Drop debug logs in production (optional)
// stage.drop {
// expression = ".*level=debug.*"
// drop_counter_reason = "debug_logs"
// }
// Multi-line log handling (for stack traces)
stage.multiline {
firstline = "^\\d{4}-\\d{2}-\\d{2}|^\\[\\d{4}"
max_wait_time = "3s"
max_lines = 128
}
}
// =============================================================================
// LOKI OUTPUT: Send logs to Loki
// =============================================================================
loki.write "default" {
endpoint {
url = "http://loki-gateway.loki.svc.cluster.local/loki/api/v1/push"
// Multi-tenant: Set tenant ID from namespace or static value
tenant_id = "default"
// For multi-tenant based on namespace:
// tenant_id = "{{ .namespace }}"
// Authentication (if required)
// basic_auth {
// username = env("LOKI_USERNAME")
// password = env("LOKI_PASSWORD")
// }
// TLS configuration (if Loki uses TLS)
// tls_config {
// ca_file = "/etc/alloy/tls/ca.crt"
// cert_file = "/etc/alloy/tls/tls.crt"
// key_file = "/etc/alloy/tls/tls.key"
// insecure_skip_verify = false
// }
}
// Batching and retry configuration
external_labels = {
cluster = "production",
env = "prod",
}
}
// =============================================================================
// OPTIONAL: File-based log collection (for non-Kubernetes or specific files)
// =============================================================================
// local.file_match "var_logs" {
// path_targets = [
// {__path__ = "/var/log/*.log"},
// {__path__ = "/var/log/syslog"},
// ]
// }
//
// loki.source.file "var_logs" {
// targets = local.file_match.var_logs.targets
// forward_to = [loki.write.default.receiver]
// }
// =============================================================================
// OPTIONAL: Journal/Systemd log collection
// =============================================================================
// loki.source.journal "systemd" {
// forward_to = [loki.write.default.receiver]
// relabel_rules = loki.relabel.journal.rules
// labels = {
// job = "systemd-journal",
// }
// }
// =============================================================================
// OPTIONAL: OTLP receiver (receive logs from OpenTelemetry SDKs)
// =============================================================================
// otelcol.receiver.otlp "default" {
// grpc {
// endpoint = "0.0.0.0:4317"
// }
// http {
// endpoint = "0.0.0.0:4318"
// }
// output {
// logs = [otelcol.exporter.loki.default.input]
// }
// }
//
// otelcol.exporter.loki "default" {
// forward_to = [loki.write.default.receiver]
// }
// Kubernetes deployment example:
// - See grafana-alloy-daemonset.yaml for the DaemonSet manifest.
// - Mount this file at /etc/alloy/config.alloy.
// =============================================================================
# Migration from Promtail
# Convert existing Promtail config to Alloy format:
#
# alloy convert --source-format=promtail --output=alloy-config.alloy promtail.yaml
#
# Key differences from Promtail:
# - River configuration language instead of YAML
# - Components connected via forward_to (flow-based)
# - discovery.kubernetes replaces kubernetes_sd_configs
# - loki.source.kubernetes replaces scrape_configs
# - loki.process replaces pipeline_stages
# - loki.write replaces clients
#
# Documentation: https://grafana.com/docs/alloy/latest/reference/components/
# Loki Helm Chart Values - Production Configuration
# For use with: helm install loki grafana/loki -f kubernetes-helm-values.yaml
# Requires Loki Helm chart 6.x+ (supports Loki 3.x)
# Deployment mode: SimpleScalable (recommended) or Distributed (microservices)
deploymentMode: SimpleScalable
# Loki configuration
loki:
# Authentication - enable for multi-tenancy
auth_enabled: true
# Schema configuration - CRITICAL: Use TSDB with v13
schemaConfig:
configs:
- from: "2025-01-01"
store: tsdb
object_store: s3
schema: v13
index:
prefix: loki_index_
period: 24h
# Ingester settings
ingester:
chunk_encoding: snappy
# Querier settings
querier:
max_concurrent: 4
# Pattern Ingester (Loki 3.0+) - enables log pattern detection
pattern_ingester:
enabled: true
# Limits configuration
limits_config:
# Ingestion limits
ingestion_rate_mb: 50
ingestion_burst_size_mb: 100
max_line_size: 256KB
# Stream limits (prevent cardinality explosion)
max_streams_per_user: 100000
max_global_streams_per_user: 500000
# Query limits
max_entries_limit_per_query: 5000
max_query_length: 721h
max_query_parallelism: 32
# Retention
retention_period: 30d
# Structured metadata (required for OTLP)
allow_structured_metadata: true
max_structured_metadata_size: 64KB
max_structured_metadata_entries_count: 128
# Volume API (for Explore Logs / Grafana Drilldown)
volume_enabled: true
# OTLP Configuration (Loki 3.0+)
otlp_config:
resource_attributes:
attributes_config:
- action: index_label
attributes:
- service.name
- service.namespace
- deployment.environment
# Compactor settings (retention)
compactor:
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
# Frontend encoding - protobuf recommended
frontend:
encoding: protobuf
# Common configuration
commonConfig:
replication_factor: 3
# Storage configuration - Choose your backend
storage:
type: s3
bucketNames:
chunks: loki-chunks
ruler: loki-ruler
admin: loki-admin
s3:
region: us-east-1
# Use IAM roles for authentication (recommended)
# Or specify endpoint for MinIO/S3-compatible storage
# endpoint: http://minio.minio.svc.cluster.local:9000
# accessKeyId: ${S3_ACCESS_KEY_ID}
# secretAccessKey: ${S3_SECRET_ACCESS_KEY}
# s3ForcePathStyle: true
# Simple Scalable mode replicas
backend:
replicas: 3
persistence:
size: 10Gi
storageClass: null # Use default storage class
read:
replicas: 3
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 6
targetCPUUtilizationPercentage: 60
write:
replicas: 3
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 6
targetCPUUtilizationPercentage: 60
# Disable components not used in SimpleScalable mode
ingester:
replicas: 0
querier:
replicas: 0
queryFrontend:
replicas: 0
queryScheduler:
replicas: 0
distributor:
replicas: 0
compactor:
replicas: 0
indexGateway:
replicas: 0
bloomCompactor:
replicas: 0
bloomGateway:
replicas: 0
# Single binary mode (disabled for SimpleScalable)
singleBinary:
replicas: 0
# Gateway configuration
gateway:
enabled: true
replicas: 2
service:
type: ClusterIP
# type: LoadBalancer # Uncomment for external access
autoscaling:
enabled: true
minReplicas: 1
maxReplicas: 4
targetCPUUtilizationPercentage: 60
# Memcached for caching (included by default)
memcached:
# Chunks cache
chunk_cache:
enabled: true
host: "{{ .Release.Name }}-memcached-chunks"
service: memcached-client
batch_size: 256
parallelism: 10
# Results cache
results_cache:
enabled: true
host: "{{ .Release.Name }}-memcached-results"
service: memcached-client
default_validity: 12h
# Memcached chunks subchart
memcachedChunks:
enabled: true
replicas: 2
resources:
requests:
memory: 1Gi
cpu: 100m
limits:
memory: 2Gi
cpu: 500m
# Memcached results subchart
memcachedResults:
enabled: true
replicas: 2
resources:
requests:
memory: 512Mi
cpu: 100m
limits:
memory: 1Gi
cpu: 500m
# MinIO for testing (disable in production, use real S3/GCS/Azure)
minio:
enabled: false # Set to true for local testing
# enabled: true
# persistence:
# size: 20Gi
# resources:
# requests:
# cpu: 100m
# memory: 256Mi
# Monitoring
monitoring:
# ServiceMonitor for Prometheus
serviceMonitor:
enabled: true
interval: 15s
labels:
release: prometheus # Match your Prometheus operator labels
# Grafana dashboards
dashboards:
enabled: true
labels:
grafana_dashboard: "1"
# Self-monitoring (sends Loki's logs to itself)
selfMonitoring:
enabled: false
grafanaAgent:
installOperator: false
# Loki Canary for testing
lokiCanary:
enabled: true
# Network policies (optional, for enhanced security)
networkPolicy:
enabled: false
# ingress:
# - from:
# - namespaceSelector:
# matchLabels:
# name: monitoring
# egress:
# - to:
# - namespaceSelector: {}
# Pod disruption budgets
podDisruptionBudget:
enabled: true
minAvailable: 1
# Global settings
global:
# Image settings
image:
registry: docker.io
# repository: grafana/loki
# tag: 3.6.2 # Current stable (Nov 2025) - Specify version or use chart default
# DNS configuration
dnsService: kube-dns
dnsNamespace: kube-system
# Test configuration
test:
enabled: true
timeout: 1mauth_enabled: true
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
log_format: logfmt
graceful_shutdown_timeout: 30s
common:
path_prefix: /loki
storage:
s3:
s3: s3://us-east-1/enterprise-loki-logs
s3forcepathstyle: false
replication_factor: 3
ring:
kvstore:
store: consul
consul:
host: consul:8500
schema_config:
configs:
- from: 2025-01-01
store: tsdb
object_store: s3
schema: v13
index:
prefix: loki_index_
period: 24h
limits_config:
ingestion_rate_mb: 100
ingestion_burst_size_mb: 200
max_line_size: 256KB
max_line_size_truncate: true
max_streams_per_user: 500000
max_global_streams_per_user: 1000000
max_entries_limit_per_query: 5000
max_query_length: 721h
max_query_parallelism: 64
retention_period: 180d
allow_structured_metadata: true
volume_enabled: true
split_queries_by_interval: 15m
# OTLP Configuration (Loki 3.0+)
otlp_config:
resource_attributes:
attributes_config:
- action: index_label
attributes:
- service.name
- service.namespace
- deployment.environment
- cloud.region
scope_attributes:
- action: drop
attributes:
- otel.library.name
log_attributes:
- action: structured_metadata
attributes:
- trace_id
- span_id
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
ingester:
chunk_encoding: snappy
chunk_idle_period: 30m
chunk_retain_period: 15m
max_chunk_age: 2h
chunk_target_size: 1572864 # 1.5MB
# Pattern Ingester (Loki 3.0+)
pattern_ingester:
enabled: true
distributor:
ring:
kvstore:
store: consul
querier:
max_concurrent: 16
query_timeout: 5m
query_frontend:
max_outstanding_per_tenant: 8192
compress_responses: true
encoding: protobuf # Recommended for performance
query_scheduler:
max_outstanding_requests_per_tenant: 800
index_gateway:
mode: ring
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
log_format: logfmt
graceful_shutdown_timeout: 30s
common:
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
instance_addr: 127.0.0.1
kvstore:
store: inmemory
schema_config:
configs:
- from: 2025-01-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: loki_index_
period: 24h
limits_config:
# Ingestion limits
ingestion_rate_mb: 10
ingestion_burst_size_mb: 20
max_line_size: 256KB
max_line_size_truncate: true
# Stream limits
max_streams_per_user: 10000
max_global_streams_per_user: 100000
# Query limits
max_entries_limit_per_query: 5000
max_query_length: 721h
max_query_parallelism: 32
max_query_series: 500
# Retention
retention_period: 30d
# Chunks
max_chunks_per_query: 2000000
# Structured metadata (Loki 2.9+)
allow_structured_metadata: true
max_structured_metadata_size: 64KB
max_structured_metadata_entries_count: 128
# Volume API
volume_enabled: true
# Pattern Ingester (Loki 3.0+)
pattern_ingester:
enabled: true
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
ingester:
chunk_encoding: snappy
chunk_idle_period: 30m
chunk_retain_period: 15m
max_chunk_age: 2h
chunk_target_size: 1572864 # 1.5MB
# Loki Multi-Tenant Configuration
# For production environments with multiple tenants/teams
# Requires: auth_enabled: true, X-Scope-OrgID header in all requests
auth_enabled: true # REQUIRED for multi-tenancy
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
log_format: logfmt
graceful_shutdown_timeout: 30s
# HTTP server tuning for multi-tenant workloads
http_server_read_timeout: 30s
http_server_write_timeout: 30s
http_server_idle_timeout: 120s
common:
path_prefix: /loki
storage:
s3:
s3: s3://us-east-1/multi-tenant-loki-bucket
s3forcepathstyle: false
# Use IAM roles for authentication (recommended)
replication_factor: 3
ring:
kvstore:
store: memberlist
memberlist:
join_members:
- loki-memberlist
schema_config:
configs:
- from: 2025-01-01
store: tsdb
object_store: s3
schema: v13
index:
prefix: loki_index_
period: 24h
# Default limits (applied to all tenants)
limits_config:
# Ingestion limits per tenant
ingestion_rate_mb: 20
ingestion_burst_size_mb: 40
max_line_size: 256KB
max_line_size_truncate: true
# Stream limits per tenant
max_streams_per_user: 50000
max_global_streams_per_user: 100000
# Query limits per tenant
max_entries_limit_per_query: 5000
max_query_length: 721h
max_query_parallelism: 16
max_query_series: 500
# Retention (default for all tenants)
retention_period: 30d
# Chunks
max_chunks_per_query: 2000000
# Structured metadata
allow_structured_metadata: true
max_structured_metadata_size: 64KB
max_structured_metadata_entries_count: 128
# Volume API
volume_enabled: true
# OTLP Configuration (Loki 3.0+)
# IMPORTANT: k8s.pod.name and service.instance.id are NOT index labels (high cardinality)
# See: https://grafana.com/docs/loki/latest/get-started/labels/remove-default-labels/
otlp_config:
resource_attributes:
ignore_defaults: false
attributes_config:
- action: index_label
attributes:
- service.name
- service.namespace
- deployment.environment
- action: structured_metadata
attributes:
- k8s.pod.name # High cardinality - stored as structured metadata
- service.instance.id # High cardinality - stored as structured metadata
log_attributes:
- action: structured_metadata
attributes:
- trace_id
- span_id
# Cardinality limits (important for multi-tenant)
max_label_name_length: 1024
max_label_value_length: 2048
max_label_names_per_series: 30
# Per-stream rate limiting
per_stream_rate_limit: 3MB
per_stream_rate_limit_burst: 15MB
# Per-tenant overrides (higher limits for specific tenants)
# Reference: https://grafana.com/docs/loki/latest/configure/#runtime-configuration-file
# Create a runtime-config.yaml ConfigMap with:
#
# overrides:
# # Premium tenant with higher limits
# tenant-premium:
# ingestion_rate_mb: 100
# ingestion_burst_size_mb: 200
# max_streams_per_user: 200000
# max_global_streams_per_user: 500000
# retention_period: 180d
# max_query_parallelism: 64
#
# # Standard tenant with default limits
# tenant-standard:
# ingestion_rate_mb: 20
# ingestion_burst_size_mb: 40
# retention_period: 30d
#
# # Development tenant with lower limits
# tenant-dev:
# ingestion_rate_mb: 5
# ingestion_burst_size_mb: 10
# max_streams_per_user: 10000
# retention_period: 7d
# Runtime configuration for per-tenant overrides
runtime_config:
file: /etc/loki/runtime-config.yaml
period: 10s # How often to reload
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
ingester:
chunk_encoding: snappy
chunk_idle_period: 30m
chunk_retain_period: 15m
max_chunk_age: 2h
chunk_target_size: 1572864
# Lifecycle configuration
lifecycler:
ring:
replication_factor: 3
# Pattern Ingester (Loki 3.0+)
pattern_ingester:
enabled: true
querier:
max_concurrent: 8
query_timeout: 5m
query_frontend:
# Per-tenant queue limits
max_outstanding_per_tenant: 2048
compress_responses: true
encoding: protobuf
# Query scheduling
scheduler_address: "" # Use embedded scheduler
query_range:
parallelise_shardable_queries: true
cache_results: true
# Split queries for better multi-tenant performance
split_queries_by_interval: 15m
# Query scheduler for fair tenant scheduling
query_scheduler:
# Fair scheduling across tenants
max_outstanding_requests_per_tenant: 100
# Distributor configuration
distributor:
ring:
kvstore:
store: memberlist
# Caching configuration
chunk_store_config:
chunk_cache_config:
memcached:
batch_size: 256
parallelism: 10
memcached_client:
host: memcached-chunks.loki.svc.cluster.local
service: memcached-client
timeout: 500ms
# Results cache for queries
frontend:
encoding: protobuf
# Results caching
results_cache:
cache:
memcached_client:
host: memcached-results.loki.svc.cluster.local
service: memcached-client
timeout: 500ms
max_idle_conns: 100
# TLS Configuration (recommended for production multi-tenant)
# server:
# http_tls_config:
# cert_file: /etc/loki/tls/tls.crt
# key_file: /etc/loki/tls/tls.key
# grpc_tls_config:
# cert_file: /etc/loki/tls/tls.crt
# key_file: /etc/loki/tls/tls.key
# Index Gateway for improved query performance
index_gateway:
mode: ring
ring:
kvstore:
store: memberlist# Loki Production Configuration with TLS
# Simple Scalable deployment with full TLS encryption
# Requires: TLS certificates mounted at /etc/loki/tls/
# Reference: https://grafana.com/docs/loki/latest/configure/#server
auth_enabled: true
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
log_format: logfmt
graceful_shutdown_timeout: 30s
# HTTP TLS Configuration
http_tls_config:
# Server certificate
cert_file: /etc/loki/tls/tls.crt
key_file: /etc/loki/tls/tls.key
# Client CA for mTLS (optional but recommended)
client_ca_file: /etc/loki/tls/ca.crt
# Require client certificates (mTLS)
client_auth_type: RequireAndVerifyClientCert # Options: NoClientCert, RequestClientCert, RequireAnyClientCert, VerifyClientCertIfGiven, RequireAndVerifyClientCert
# gRPC TLS Configuration (inter-component communication)
grpc_tls_config:
cert_file: /etc/loki/tls/tls.crt
key_file: /etc/loki/tls/tls.key
client_ca_file: /etc/loki/tls/ca.crt
client_auth_type: RequireAndVerifyClientCert
common:
path_prefix: /loki
storage:
s3:
s3: s3://us-east-1/production-loki-bucket
s3forcepathstyle: false
# Use IAM roles for authentication (never hardcode credentials)
replication_factor: 3
ring:
kvstore:
store: memberlist
# Zone awareness for multi-AZ deployments
instance_availability_zone: ${AVAILABILITY_ZONE}
memberlist:
join_members:
- loki-memberlist
schema_config:
configs:
- from: "2025-01-01"
store: tsdb
object_store: s3
schema: v13
index:
prefix: loki_index_
period: 24h
limits_config:
# Ingestion limits
ingestion_rate_mb: 50
ingestion_burst_size_mb: 100
max_line_size: 256KB
max_line_size_truncate: true
# Stream limits
max_streams_per_user: 100000
max_global_streams_per_user: 500000
# Query limits
max_entries_limit_per_query: 5000
max_query_length: 721h
max_query_parallelism: 32
max_query_series: 500
# Retention
retention_period: 90d
# Chunks
max_chunks_per_query: 2000000
# Structured metadata (Loki 2.9+)
allow_structured_metadata: true
max_structured_metadata_size: 64KB
max_structured_metadata_entries_count: 128
# Volume API
volume_enabled: true
# OTLP Configuration (Loki 3.0+)
otlp_config:
resource_attributes:
ignore_defaults: false
attributes_config:
- action: index_label
attributes:
- service.name
- service.namespace
- deployment.environment
- action: structured_metadata
attributes:
- k8s.pod.name
- service.instance.id
log_attributes:
- action: structured_metadata
attributes:
- trace_id
- span_id
# Pattern Ingester (Loki 3.0+)
pattern_ingester:
enabled: true
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
ingester:
chunk_encoding: snappy
chunk_idle_period: 30m
chunk_retain_period: 15m
max_chunk_age: 2h
chunk_target_size: 1572864 # 1.5MB
lifecycler:
ring:
replication_factor: 3
zone_awareness_enabled: true # CRITICAL for multi-AZ HA
querier:
max_concurrent: 4
query_timeout: 5m
query_frontend:
max_outstanding_per_tenant: 4096
compress_responses: true
encoding: protobuf
query_range:
parallelise_shardable_queries: true
cache_results: true
# Caching with TLS (if using external memcached with TLS)
chunk_store_config:
chunk_cache_config:
memcached:
batch_size: 256
parallelism: 10
memcached_client:
host: memcached-chunks.loki.svc.cluster.local
service: memcached-client
timeout: 500ms
# TLS for memcached (if supported)
# tls_enabled: true
# Results cache
frontend:
encoding: protobuf
results_cache:
cache:
memcached_client:
host: memcached-results.loki.svc.cluster.local
service: memcached-client
timeout: 500ms
max_idle_conns: 100
# Index Gateway
index_gateway:
mode: ring
ring:
kvstore:
store: memberlist
---
# Kubernetes TLS Secret Configuration
# Create TLS secrets using cert-manager or manually:
#
# # Using cert-manager (recommended)
# apiVersion: cert-manager.io/v1
# kind: Certificate
# metadata:
# name: loki-tls
# namespace: loki
# spec:
# secretName: loki-tls
# duration: 8760h # 1 year
# renewBefore: 720h # 30 days
# issuerRef:
# name: ca-issuer
# kind: ClusterIssuer
# commonName: loki
# dnsNames:
# - loki
# - loki.loki.svc
# - loki.loki.svc.cluster.local
# - "*.loki-headless.loki.svc.cluster.local"
#
# # Manual secret creation
# kubectl create secret tls loki-tls \
# --cert=tls.crt \
# --key=tls.key \
# -n loki
#
# kubectl create secret generic loki-ca \
# --from-file=ca.crt=ca.crt \
# -n loki
---
# Helm values for TLS configuration
# Use with: helm install loki grafana/loki -f values-tls.yaml
#
# loki:
# server:
# http_tls_config:
# cert_file: /etc/loki/tls/tls.crt
# key_file: /etc/loki/tls/tls.key
# client_ca_file: /etc/loki/tls/ca.crt
# grpc_tls_config:
# cert_file: /etc/loki/tls/tls.crt
# key_file: /etc/loki/tls/tls.key
# client_ca_file: /etc/loki/tls/ca.crt
#
# # Mount TLS secrets
# extraVolumes:
# - name: tls
# secret:
# secretName: loki-tls
# - name: ca
# secret:
# secretName: loki-ca
#
# extraVolumeMounts:
# - name: tls
# mountPath: /etc/loki/tls
# readOnly: true
# - name: ca
# mountPath: /etc/loki/tls/ca.crt
# subPath: ca.crt
# readOnly: true# Loki Simple Scalable Mode with Google Cloud Storage (GCS)
# Recommended for production deployments on GCP (100GB-1TB/day)
# Requires: GCS bucket, service account with Storage Admin permissions
auth_enabled: true
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
log_format: logfmt
graceful_shutdown_timeout: 30s
common:
path_prefix: /loki
storage:
gcs:
bucket_name: my-loki-logs-bucket
# Authentication options (choose one):
# 1. Workload Identity (recommended for GKE)
# 2. Service account JSON file mounted as volume
# service_account: /var/secrets/google/key.json
replication_factor: 3
ring:
kvstore:
store: memberlist
memberlist:
join_members:
- loki-memberlist
schema_config:
configs:
- from: 2025-01-01
store: tsdb
object_store: gcs
schema: v13
index:
prefix: loki_index_
period: 24h
storage_config:
tsdb_shipper:
active_index_directory: /loki/index
cache_location: /loki/index_cache
cache_ttl: 24h
limits_config:
# Ingestion limits
ingestion_rate_mb: 50
ingestion_burst_size_mb: 100
max_line_size: 256KB
max_line_size_truncate: true
# Stream limits
max_streams_per_user: 100000
max_global_streams_per_user: 1000000
# Query limits
max_entries_limit_per_query: 5000
max_query_length: 721h
max_query_parallelism: 32
max_query_series: 500
# Retention
retention_period: 90d
# Chunks
max_chunks_per_query: 2000000
# Structured metadata (Loki 3.0+)
allow_structured_metadata: true
max_structured_metadata_size: 64KB
max_structured_metadata_entries_count: 128
# Volume API
volume_enabled: true
# OTLP Configuration (Loki 3.0+)
otlp_config:
resource_attributes:
attributes_config:
- action: index_label
attributes:
- service.name
- service.namespace
- deployment.environment
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
ingester:
chunk_encoding: snappy
chunk_idle_period: 30m
chunk_retain_period: 15m
max_chunk_age: 2h
chunk_target_size: 1572864 # 1.5MB
# Pattern Ingester (Loki 3.0+)
pattern_ingester:
enabled: true
querier:
max_concurrent: 4
query_timeout: 5m
query_frontend:
max_outstanding_per_tenant: 4096
compress_responses: true
encoding: protobuf # Recommended for performance
query_range:
parallelise_shardable_queries: true
cache_results: trueauth_enabled: true
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
log_format: logfmt
graceful_shutdown_timeout: 30s
common:
path_prefix: /loki
storage:
s3:
s3: s3://us-east-1/my-loki-logs
s3forcepathstyle: false
# Authentication via IAM role (recommended)
# Or use environment variables: S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY
replication_factor: 3
ring:
kvstore:
store: memberlist
memberlist:
join_members:
- loki-memberlist
schema_config:
configs:
- from: 2025-01-01
store: tsdb
object_store: s3
schema: v13
index:
prefix: loki_index_
period: 24h
limits_config:
# Ingestion limits
ingestion_rate_mb: 50
ingestion_burst_size_mb: 100
max_line_size: 256KB
max_line_size_truncate: true
# Stream limits
max_streams_per_user: 100000
max_global_streams_per_user: 1000000
# Query limits
max_entries_limit_per_query: 5000
max_query_length: 721h
max_query_parallelism: 32
max_query_series: 500
# Retention
retention_period: 90d
# Chunks
max_chunks_per_query: 2000000
# Structured metadata (Loki 2.9+)
allow_structured_metadata: true
max_structured_metadata_size: 64KB
max_structured_metadata_entries_count: 128
# Volume API
volume_enabled: true
# OTLP Configuration (Loki 3.0+)
otlp_config:
resource_attributes:
attributes_config:
- action: index_label
attributes:
- service.name
- service.namespace
- deployment.environment
# Pattern Ingester (Loki 3.0+)
pattern_ingester:
enabled: true
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
ingester:
chunk_encoding: snappy
chunk_idle_period: 30m
chunk_retain_period: 15m
max_chunk_age: 2h
chunk_target_size: 1572864 # 1.5MB
querier:
max_concurrent: 4
query_timeout: 5m
query_frontend:
max_outstanding_per_tenant: 4096
compress_responses: true
encoding: protobuf # Recommended for performance
query_range:
parallelise_shardable_queries: true
cache_results: true
# Loki Configuration with Thanos Object Storage Client - Azure (Loki 3.4+)
# Simple Scalable deployment using the new Thanos-based storage clients
# The Thanos client provides consistent storage configuration across Grafana's databases
# Reference: https://grafana.com/docs/loki/latest/configure/examples/thanos-storage-configs/
auth_enabled: true
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
log_format: logfmt
graceful_shutdown_timeout: 30s
# Thanos Object Storage Client Configuration (Loki 3.4+)
# Note: use_thanos_objstore is mutually exclusive with legacy storage config
storage_config:
use_thanos_objstore: true
object_store:
# Storage prefix for all objects (optional)
# Note: Cannot contain dashes (-), use underscores instead
storage_prefix: "loki_prod"
azure:
account_name: ${AZURE_STORAGE_ACCOUNT}
container_name: loki-container
# Authentication options (choose one):
# Option 1: Account Key (simple but less secure)
account_key: ${AZURE_STORAGE_KEY}
# Option 2: Managed Identity (recommended for Azure-hosted workloads)
# use_managed_identity: true
# user_assigned_id: <optional-user-assigned-identity-client-id>
# Option 3: Service Principal (for non-Azure environments)
# tenant_id: ${AZURE_TENANT_ID}
# client_id: ${AZURE_CLIENT_ID}
# client_secret: ${AZURE_CLIENT_SECRET}
# Azure-specific settings
max_retries: 5
# endpoint_suffix: blob.core.windows.net # Default, change for sovereign clouds
# Ruler storage must be configured separately when using Thanos
ruler_storage:
backend: azure
azure:
account_name: ${AZURE_STORAGE_ACCOUNT}
account_key: ${AZURE_STORAGE_KEY}
container_name: loki-ruler-container
common:
path_prefix: /loki
replication_factor: 3
ring:
kvstore:
store: memberlist
memberlist:
join_members:
- loki-memberlist
schema_config:
configs:
- from: "2025-01-01"
store: tsdb
object_store: azure
schema: v13
index:
prefix: loki_index_
period: 24h
limits_config:
# Ingestion limits
ingestion_rate_mb: 50
ingestion_burst_size_mb: 100
max_line_size: 256KB
max_line_size_truncate: true
# Stream limits
max_streams_per_user: 100000
max_global_streams_per_user: 1000000
# Query limits
max_entries_limit_per_query: 5000
max_query_length: 721h
max_query_parallelism: 32
max_query_series: 500
# Retention
retention_period: 90d
# Chunks
max_chunks_per_query: 2000000
# Structured metadata (Loki 2.9+)
allow_structured_metadata: true
max_structured_metadata_size: 64KB
max_structured_metadata_entries_count: 128
# Volume API
volume_enabled: true
# OTLP Configuration (Loki 3.0+)
# IMPORTANT: k8s.pod.name and service.instance.id are NOT index labels (high cardinality)
otlp_config:
resource_attributes:
ignore_defaults: false
attributes_config:
- action: index_label
attributes:
- service.name
- service.namespace
- deployment.environment
- action: structured_metadata
attributes:
- k8s.pod.name
- service.instance.id
log_attributes:
- action: structured_metadata
attributes:
- trace_id
- span_id
# Time Sharding for out-of-order ingestion (Loki 3.4+)
shard_streams:
time_sharding_enabled: true
# Pattern Ingester (Loki 3.0+)
pattern_ingester:
enabled: true
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
delete_request_store: azure
ingester:
chunk_encoding: snappy
chunk_idle_period: 30m
chunk_retain_period: 15m
max_chunk_age: 2h
chunk_target_size: 1572864 # 1.5MB
querier:
max_concurrent: 4
query_timeout: 5m
query_frontend:
max_outstanding_per_tenant: 4096
compress_responses: true
encoding: protobuf
query_range:
parallelise_shardable_queries: true
cache_results: true
# Key Migration Notes from Legacy Storage:
# - use_thanos_objstore: true is MUTUALLY EXCLUSIVE with legacy storage config
# - Legacy config is silently ignored when Thanos is enabled
# - Managed identity is recommended for Azure-hosted workloads (AKS, VMs)
# - Storage prefix cannot contain dashes (-) - use underscores
# - Ruler storage MUST be configured separately under ruler_storage# Loki Configuration with Thanos Object Storage Client - GCS (Loki 3.4+)
# Simple Scalable deployment using the new Thanos-based storage clients
# The Thanos client provides consistent storage configuration across Grafana's databases
# Reference: https://grafana.com/docs/loki/latest/configure/examples/thanos-storage-configs/
auth_enabled: true
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
log_format: logfmt
graceful_shutdown_timeout: 30s
# Thanos Object Storage Client Configuration (Loki 3.4+)
# Note: use_thanos_objstore is mutually exclusive with legacy storage config
storage_config:
use_thanos_objstore: true
object_store:
# Storage prefix for all objects (optional)
# Note: Cannot contain dashes (-), use underscores instead
storage_prefix: "loki_prod"
gcs:
bucket_name: my-loki-bucket
# Authentication options (in order of preference):
# 1. Workload Identity (recommended for GKE) - automatic
# 2. GOOGLE_APPLICATION_CREDENTIALS environment variable
# 3. Inline service account JSON (not recommended for production):
# service_account: |
# {
# "type": "service_account",
# "project_id": "my-project",
# "private_key_id": "...",
# ...
# }
# GCS-specific settings
chunk_buffer_size: 10485760 # 10MB buffer for uploads
max_retries: 5
# Custom endpoint (optional, for GCS-compatible storage)
# endpoint: https://storage.googleapis.com
# Ruler storage must be configured separately when using Thanos
ruler_storage:
backend: gcs
gcs:
bucket_name: my-loki-ruler-bucket
common:
path_prefix: /loki
replication_factor: 3
ring:
kvstore:
store: memberlist
memberlist:
join_members:
- loki-memberlist
schema_config:
configs:
- from: "2025-01-01"
store: tsdb
object_store: gcs
schema: v13
index:
prefix: loki_index_
period: 24h
limits_config:
# Ingestion limits
ingestion_rate_mb: 50
ingestion_burst_size_mb: 100
max_line_size: 256KB
max_line_size_truncate: true
# Stream limits
max_streams_per_user: 100000
max_global_streams_per_user: 1000000
# Query limits
max_entries_limit_per_query: 5000
max_query_length: 721h
max_query_parallelism: 32
max_query_series: 500
# Retention
retention_period: 90d
# Chunks
max_chunks_per_query: 2000000
# Structured metadata (Loki 2.9+)
allow_structured_metadata: true
max_structured_metadata_size: 64KB
max_structured_metadata_entries_count: 128
# Volume API
volume_enabled: true
# OTLP Configuration (Loki 3.0+)
# IMPORTANT: k8s.pod.name and service.instance.id are NOT index labels (high cardinality)
otlp_config:
resource_attributes:
ignore_defaults: false
attributes_config:
- action: index_label
attributes:
- service.name
- service.namespace
- deployment.environment
- action: structured_metadata
attributes:
- k8s.pod.name
- service.instance.id
log_attributes:
- action: structured_metadata
attributes:
- trace_id
- span_id
# Time Sharding for out-of-order ingestion (Loki 3.4+)
# Enable if you need to ingest logs from the past (backfilling, delayed delivery)
shard_streams:
time_sharding_enabled: true
# Pattern Ingester (Loki 3.0+)
pattern_ingester:
enabled: true
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
# SQLite for delete requests (Loki 3.5+) - more efficient than BoltDB
delete_request_store: gcs # Use same backend as main storage
ingester:
chunk_encoding: snappy
chunk_idle_period: 30m
chunk_retain_period: 15m
max_chunk_age: 2h
chunk_target_size: 1572864 # 1.5MB
querier:
max_concurrent: 4
query_timeout: 5m
query_frontend:
max_outstanding_per_tenant: 4096
compress_responses: true
encoding: protobuf
query_range:
parallelise_shardable_queries: true
cache_results: true
# Key Migration Notes from Legacy Storage:
# - use_thanos_objstore: true is MUTUALLY EXCLUSIVE with legacy storage config
# - Legacy config is silently ignored when Thanos is enabled
# - service_account takes inline JSON (for dev) or use GOOGLE_APPLICATION_CREDENTIALS
# - Storage prefix cannot contain dashes (-) - use underscores
# - Ruler storage MUST be configured separately under ruler_storage# Loki Configuration with Thanos Object Storage Client (Loki 3.4+)
# Simple Scalable deployment using the new Thanos-based storage clients
# The Thanos client provides consistent storage configuration across Grafana's databases
# Reference: https://grafana.com/docs/loki/latest/configure/examples/thanos-storage-configs/
auth_enabled: true
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
log_format: logfmt
graceful_shutdown_timeout: 30s
# Thanos Object Storage Client Configuration (Loki 3.4+)
# Note: use_thanos_objstore is mutually exclusive with legacy storage config
storage_config:
use_thanos_objstore: true
object_store:
# Storage prefix for all objects (optional)
# Note: Cannot contain dashes (-), use underscores instead
storage_prefix: "loki_prod"
s3:
bucket_name: my-loki-bucket
endpoint: s3.us-west-2.amazonaws.com
region: us-west-2
# Authentication options:
# 1. IAM roles (recommended for EKS/EC2)
native_aws_auth_enabled: true
# 2. Or explicit credentials (not recommended for production):
# access_key_id: ${AWS_ACCESS_KEY_ID}
# secret_access_key: ${AWS_SECRET_ACCESS_KEY}
# S3-specific settings
dualstack_enabled: true # IPv4/IPv6 support
storage_class: STANDARD # STANDARD, REDUCED_REDUNDANCY, GLACIER, etc.
max_retries: 10
# HTTP client settings
http:
idle_conn_timeout: 1m30s
response_header_timeout: 2m
insecure_skip_verify: false
# Server-side encryption (optional)
# sse:
# type: SSE-KMS # SSE-KMS or SSE-S3
# kms_key_id: my-kms-key
# Ruler storage must be configured separately when using Thanos
ruler_storage:
backend: s3
s3:
bucket_name: my-loki-ruler-bucket
endpoint: s3.us-west-2.amazonaws.com
region: us-west-2
common:
path_prefix: /loki
replication_factor: 3
ring:
kvstore:
store: memberlist
memberlist:
join_members:
- loki-memberlist
schema_config:
configs:
- from: "2025-01-01"
store: tsdb
object_store: s3
schema: v13
index:
prefix: loki_index_
period: 24h
limits_config:
# Ingestion limits
ingestion_rate_mb: 50
ingestion_burst_size_mb: 100
max_line_size: 256KB
max_line_size_truncate: true
# Stream limits
max_streams_per_user: 100000
max_global_streams_per_user: 1000000
# Query limits
max_entries_limit_per_query: 5000
max_query_length: 721h
max_query_parallelism: 32
max_query_series: 500
# Retention
retention_period: 90d
# Chunks
max_chunks_per_query: 2000000
# Structured metadata (Loki 2.9+)
allow_structured_metadata: true
max_structured_metadata_size: 64KB
max_structured_metadata_entries_count: 128
# Volume API
volume_enabled: true
# OTLP Configuration (Loki 3.0+)
# IMPORTANT: k8s.pod.name and service.instance.id are NOT index labels (high cardinality)
otlp_config:
resource_attributes:
ignore_defaults: false
attributes_config:
- action: index_label
attributes:
- service.name
- service.namespace
- deployment.environment
- action: structured_metadata
attributes:
- k8s.pod.name
- service.instance.id
log_attributes:
- action: structured_metadata
attributes:
- trace_id
- span_id
# Time Sharding for out-of-order ingestion (Loki 3.4+)
# Enable if you need to ingest logs from the past (backfilling, delayed delivery)
shard_streams:
time_sharding_enabled: true
# Pattern Ingester (Loki 3.0+)
pattern_ingester:
enabled: true
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
ingester:
chunk_encoding: snappy
chunk_idle_period: 30m
chunk_retain_period: 15m
max_chunk_age: 2h
chunk_target_size: 1572864 # 1.5MB
querier:
max_concurrent: 4
query_timeout: 5m
query_frontend:
max_outstanding_per_tenant: 4096
compress_responses: true
encoding: protobuf
query_range:
parallelise_shardable_queries: true
cache_results: true
# Key Migration Notes from Legacy Storage:
# - use_thanos_objstore: true is MUTUALLY EXCLUSIVE with legacy storage config
# - Legacy config is silently ignored when Thanos is enabled
# - disable_dualstack → dualstack_enabled (inverted logic)
# - signature_version removed (always uses V4)
# - http_config → http (nested block)
# - Multiple bucket support removed (use single bucket_name)
# - Storage prefix cannot contain dashes (-) - use underscores
# - Ruler storage MUST be configured separately under ruler_storage# Loki Configuration with Ruler (Alerting & Recording Rules)
# Simple Scalable deployment with integrated ruler for LogQL-based alerting
# Reference: https://grafana.com/docs/loki/latest/alert/
auth_enabled: true
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
log_format: logfmt
graceful_shutdown_timeout: 30s
common:
path_prefix: /loki
storage:
s3:
s3: s3://us-east-1/my-loki-logs
s3forcepathstyle: false
replication_factor: 3
ring:
kvstore:
store: memberlist
memberlist:
join_members:
- loki-memberlist
schema_config:
configs:
- from: "2025-01-01"
store: tsdb
object_store: s3
schema: v13
index:
prefix: loki_index_
period: 24h
# Ruler Configuration - Alerting & Recording Rules
ruler:
# Storage for rule files
storage:
type: s3
s3:
bucket_name: loki-ruler-bucket
region: us-east-1
# Uses IAM role for authentication
# Temporary path for rule processing
rule_path: /loki/rules-temp
# Alertmanager integration
alertmanager_url: http://alertmanager:9093
enable_alertmanager_v2: true # Default since Loki 3.2.0
# Alertmanager client configuration (optional)
# alertmanager_client:
# tls_config:
# ca_path: /path/to/ca.crt
# basic_auth_username: admin
# basic_auth_password: ${ALERTMANAGER_PASSWORD}
# Enable API for rule management
enable_api: true
# Sharding for distributed ruler (recommended for production)
enable_sharding: true
ring:
kvstore:
store: memberlist
# Rule evaluation settings
evaluation_interval: 1m
poll_interval: 1m
# Alert timing
for_outage_tolerance: 1h
for_grace_period: 10m
resend_delay: 1m
# Optional: Remote write recording rule metrics to Prometheus
remote_write:
enabled: true
client:
url: http://prometheus:9090/api/v1/write
# Optional authentication:
# basic_auth:
# username: admin
# password: ${PROMETHEUS_WRITE_PASSWORD}
limits_config:
# Ingestion limits
ingestion_rate_mb: 50
ingestion_burst_size_mb: 100
max_line_size: 256KB
max_line_size_truncate: true
# Stream limits
max_streams_per_user: 100000
max_global_streams_per_user: 1000000
# Query limits
max_entries_limit_per_query: 5000
max_query_length: 721h
max_query_parallelism: 32
max_query_series: 500
# Retention
retention_period: 90d
# Chunks
max_chunks_per_query: 2000000
# Structured metadata (Loki 2.9+)
allow_structured_metadata: true
max_structured_metadata_size: 64KB
max_structured_metadata_entries_count: 128
# Volume API
volume_enabled: true
# Ruler-specific limits (per tenant)
ruler_max_rules_per_rule_group: 100
ruler_max_rule_groups_per_tenant: 50
# Pattern Ingester (Loki 3.0+)
pattern_ingester:
enabled: true
compactor:
working_directory: /loki/compactor
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
ingester:
chunk_encoding: snappy
chunk_idle_period: 30m
chunk_retain_period: 15m
max_chunk_age: 2h
chunk_target_size: 1572864 # 1.5MB
querier:
max_concurrent: 4
query_timeout: 5m
query_frontend:
max_outstanding_per_tenant: 4096
compress_responses: true
encoding: protobuf
query_range:
parallelise_shardable_queries: true
cache_results: true
---
# Example Rule File: /loki/rules/<tenant-id>/alerts.yaml
# Place this file in your ruler storage bucket under the tenant directory
# groups:
# - name: high_error_rate
# interval: 1m
# limit: 10
# rules:
# # Alerting rule - fires when error rate exceeds 5%
# - alert: HighErrorRate
# expr: |
# sum(rate({app="myapp"} |= "error" [5m])) by (job)
# /
# sum(rate({app="myapp"}[5m])) by (job)
# > 0.05
# for: 10m
# labels:
# severity: critical
# annotations:
# summary: "High error rate detected for {{ $labels.job }}"
# description: "Error rate is {{ $value | printf \"%.2f\" }}%"
# runbook_url: "https://runbooks.example.com/loki/high-error-rate"
#
# # Recording rule - pre-compute expensive queries
# - record: job:loki_requests:rate5m
# expr: |
# sum(rate({job=~".+"}[5m])) by (job)
# labels:
# source: loki
#
# - name: service_health
# interval: 1m
# rules:
# # Alert on service unavailability
# - alert: ServiceUnavailable
# expr: |
# absent_over_time({service="critical-service"}[5m])
# for: 5m
# labels:
# severity: page
# annotations:
# summary: "Service critical-service appears to be down"
#
# # Alert on high latency patterns in logs
# - alert: HighLatency
# expr: |
# count_over_time({app="api"} |~ "latency=[0-9]+" | latency > 1000 [5m]) > 100
# for: 5m
# labels:
# severity: warning
# annotations:
# summary: "High latency detected in API logs"
# Ruler API Endpoints:
# - GET /loki/api/v1/rules - List all rules
# - GET /loki/api/v1/rules/{ns} - List rules in namespace
# - POST /loki/api/v1/rules/{ns} - Create/update rule group
# - DELETE /loki/api/v1/rules/{ns}/{group} - Delete rule group
# - GET /loki/api/v1/alerts - List current alerts
# Note: enable_api: true is required for API-based rule managementLoki Configuration Best Practices
This document outlines best practices for configuring and deploying Grafana Loki in production environments.
Important Notice (Loki 3.4+): Promtail has been deprecated and its code merged into Grafana Alloy. For new log collection deployments, use Grafana Alloy instead of Promtail.
Schema Configuration
Use TSDB with v13 Schema (CRITICAL)
Always use the latest schema for new deployments:
schema_config:
configs:
- from: "2025-01-01" # Use deployment date
store: tsdb
object_store: s3
schema: v13
index:
prefix: loki_index_
period: 24hWhy:
- TSDB is the modern, performant index store
- v13 schema provides best performance and features
- Cannot be changed after deployment without migration
- Daily period (
24h) is recommended for most use cases
Important: Set from date to your deployment date, not a past date.
Deployment Modes
Choose the Right Deployment Mode
| Mode | Use Case | Ingestion | Complexity |
|---|---|---|---|
| Monolithic | Development, testing, small deployments | <100GB/day | Low |
| Simple Scalable | Production, moderate scale | 100GB-1TB/day | Medium |
| Microservices | Large scale, multi-tenancy | >1TB/day | High |
Monolithic:
- Single binary with all components
- Easy to operate
- Limited scalability
- Good for getting started
Simple Scalable:
- Separates read, write, and backend
- Horizontal scaling
- Production-ready
- Recommended for most use cases
Microservices:
- Full component separation
- Maximum scalability
- Independent scaling per component
- Requires more operational overhead
Storage Configuration
Storage Backend Selection
Filesystem:
- Development and testing only
- Requires persistent volumes
- Not recommended for production at scale
Object Storage (S3, GCS, Azure):
- Recommended for production
- Cost-effective at scale
- Durable and highly available
- Use IAM roles/service accounts for authentication
Best practices:
common:
storage:
s3:
s3: s3://region/bucket-name
s3forcepathstyle: false
# Use IAM roles instead of access keys
replication_factor: 3 # Always use 3 for productionReplication and High Availability
Always Use Replication Factor 3
common:
replication_factor: 3Why:
- Data durability: tolerates 2 node failures
- Query reliability: ensures data availability
- Industry standard for distributed systems
Enable Zone-Aware Replication
For multi-AZ deployments:
ingester:
lifecycler:
ring:
zone_awareness_enabled: trueWhy:
- Distributes replicas across availability zones
- Survives entire AZ failures
- Better fault tolerance
Native OTLP Ingestion (Loki 3.0+)
Configure OTLP Attributes
If using OpenTelemetry, configure how OTLP attributes are mapped:
limits_config:
allow_structured_metadata: true
otlp_config:
resource_attributes:
ignore_defaults: false # Set true to completely override defaults
attributes_config:
- action: index_label
attributes:
- service.name
- service.namespace
- deployment.environment
# NOTE: Do NOT include high-cardinality attributes as index labels!
- action: structured_metadata
attributes:
- k8s.pod.name # High cardinality - use structured_metadata
- service.instance.id # High cardinality - use structured_metadata
log_attributes:
- action: structured_metadata
attributes:
- trace_id
- span_id⚠️ CRITICAL: Label Cardinality Best Practices (Updated 2025)
>
DO NOT use these high-cardinality attributes as index labels:
- k8s.pod.name - Changes frequently, creates too many streams- service.instance.id - High cardinality>
Instead, store them as structured_metadata. This is now the recommended approach.See: https://grafana.com/docs/loki/latest/get-started/labels/remove-default-labels/
Recommended index labels (low-cardinality):
service.name,service.namespace,deployment.environmentcloud.region,cloud.availability_zonek8s.cluster.name,k8s.namespace.name,k8s.container.namek8s.deployment.name,k8s.statefulset.name,k8s.daemonset.name
Configuring Default Resource Attributes:
For more control over which OTLP resource attributes become labels:
distributor:
otlp_config:
default_resource_attributes_as_index_labels:
- service.name
- service.namespace
- deployment.environment
- k8s.cluster.name
- k8s.namespace.name
# EXCLUDES: k8s.pod.name, service.instance.idWhy:
- Native OTLP support eliminates the need for Loki Exporter (deprecated)
- Control which attributes become labels vs structured metadata
- Low-cardinality attributes should be
index_label - High-cardinality attributes should be
structured_metadata - Use
ignore_defaults: truefor complete control over attribute mapping
OTLP Endpoint: POST /otlp/v1/logs
OpenTelemetry Collector Configuration:
exporters:
otlphttp:
endpoint: http://loki:3100/otlp
# Note: lokiexporter is DEPRECATED - use otlphttp instead
service:
pipelines:
logs:
receivers: [otlp]
processors: [batch]
exporters: [otlphttp]Pattern Ingester (Loki 3.0+)
Enable Pattern Detection
pattern_ingester:
enabled: trueWhy:
- Automatic log pattern detection
- Powers Explore Logs / Grafana Drilldown features
- Identifies recurring patterns for anomaly detection
- Minimal resource overhead
Caching Configuration
Configure Memcached for Production
# Chunk cache
chunk_store_config:
chunk_cache_config:
memcached:
batch_size: 256
parallelism: 10
memcached_client:
host: memcached-chunks.loki.svc.cluster.local
service: memcached-client
timeout: 500ms
# Results cache
query_range:
cache_results: true
results_cache:
cache:
memcached_client:
host: memcached-results.loki.svc.cluster.local
timeout: 500msImportant Notes:
- TSDB does NOT need index cache - only chunks and results cache
- Use separate Memcached instances for chunks and results
- Size chunk cache based on query hot data volume
- Size results cache based on repeated query patterns
Helm Chart Caching:
memcached:
chunk_cache:
enabled: true
results_cache:
enabled: true
memcachedChunks:
enabled: true
replicas: 2
resources:
requests:
memory: 1Gi
limits:
memory: 2GiLimits Configuration
Set Appropriate Ingestion Limits
limits_config:
ingestion_rate_mb: 50 # Adjust based on expected load
ingestion_burst_size_mb: 100 # 2x rate for bursts
max_line_size: 256KB
max_line_size_truncate: trueWhy:
- Prevents resource exhaustion
- Protects against misconfigured clients
- Allows burst traffic while limiting sustained overload
Control Stream Cardinality
limits_config:
max_streams_per_user: 10000
max_global_streams_per_user: 100000Why:
- High cardinality kills performance
- Each label combination creates a stream
- Limit prevents accidental label explosion
Best practice: Use line filters for high-cardinality data (user IDs, trace IDs) instead of labels.
Configure Retention
compactor:
retention_enabled: true
retention_delete_delay: 2h
limits_config:
retention_period: 30d # Adjust based on requirementsWhy:
- Controls storage costs
- Meets compliance requirements
- Automatic cleanup of old data
Chunk Management
Optimize Chunk Settings
ingester:
chunk_encoding: snappy
chunk_target_size: 1572864 # 1.5MB
chunk_idle_period: 30m
max_chunk_age: 2hWhy:
snappy: Best balance of speed vs compression1.5MBtarget: Optimal chunk size (requires 5-10x raw data)30midle: Flushes inactive chunks to storage2hmax age: Prevents memory buildup
Important: More streams = more chunks in memory. Keep stream cardinality low.
Query Performance
Configure Query Concurrency
querier:
max_concurrent: 4 # Per querier instance
query_timeout: 5mRecommendations:
- Start with 4 concurrent queries
- Increase based on CPU/memory resources
- Monitor query latency and adjust
Enable Query Parallelization
query_range:
parallelise_shardable_queries: true
split_queries_by_interval: 15m # For large time rangesWhy:
- Distributes query load across queriers
- Faster results for large time ranges
- Better resource utilization
Security
Enable Multi-Tenancy
auth_enabled: trueProduction recommendation:
- Always use
auth_enabled: true - Deploy authenticating reverse proxy (nginx, Envoy)
- Enforce
X-Scope-OrgIDheader - Isolate tenant data
Use TLS for Inter-Component Communication
server:
http_tls_config:
cert_file: /path/to/cert.pem
key_file: /path/to/key.pem
grpc_tls_config:
cert_file: /path/to/cert.pem
key_file: /path/to/key.pemWhy:
- Encrypts data in transit
- Prevents eavesdropping
- Required for compliance (PCI, HIPAA, etc.)
Secure Credentials
Never hardcode credentials:
# BAD
common:
storage:
s3:
access_key_id: AKIAIOSFODNN7EXAMPLE
secret_access_key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# GOOD
common:
storage:
s3:
# Uses IAM role automaticallyBest practices:
- Use IAM roles for AWS
- Use service accounts for GCP
- Use managed identities for Azure
- Store secrets in Kubernetes Secrets or Vault
- Reference secrets via environment variables
Monitoring and Observability
Enable Metrics
Loki exports Prometheus metrics automatically. Scrape them:
# In Prometheus config
- job_name: 'loki'
static_configs:
- targets: ['loki:3100']Key metrics to monitor:
loki_ingester_chunks_flushed_total: Chunk flush rateloki_ingester_memory_streams: Active streams (watch for growth)loki_request_duration_seconds: Query latencyloki_distributor_ingester_append_failures_total: Ingestion failuresloki_boltdb_shipper_request_duration_seconds: Index query time
Set Up Alerts
Critical alerts:
# High ingestion failure rate
- alert: LokiIngestionFailureRate
expr: sum(rate(loki_distributor_ingester_append_failures_total[5m])) > 10
# Too many streams (cardinality explosion)
- alert: LokiHighStreamCardinality
expr: loki_ingester_memory_streams > 100000
# Compaction not running
- alert: LokiCompactionNotRunning
expr: time() - loki_boltdb_shipper_compact_tables_operation_last_successful_run_timestamp_seconds > 3600Resource Planning
Ingester Resources
Memory requirements:
- Base: ~1GB per ingester
- Add: 1-2KB per active stream
- Add: Chunk buffer (depends on throughput)
Example: 10,000 streams = ~1GB + 20MB = ~1.2GB minimum
Kubernetes recommendations:
resources:
requests:
memory: "4Gi"
cpu: "1"
limits:
memory: "8Gi"
cpu: "2"Querier Resources
Memory requirements:
- Base: ~500MB per querier
- Add: Depends on query complexity and concurrency
CPU requirements:
- Varies with query load
- More CPU = faster queries
Kubernetes recommendations:
resources:
requests:
memory: "2Gi"
cpu: "1"
limits:
memory: "4Gi"
cpu: "2"Storage Requirements
Estimate storage:
Daily storage = (ingestion rate MB/s) × 86400 seconds × compression ratioCompression ratios:
- Text logs: 5-10x (snappy)
- JSON logs: 3-7x (snappy)
- Structured logs: 2-5x (snappy)
Example: 10 MB/s ingestion with 5x compression:
10 MB/s × 86400 × 0.2 = ~170 GB/dayOperational Best Practices
Use Health Checks
Configure Kubernetes probes:
livenessProbe:
httpGet:
path: /ready
port: 3100
initialDelaySeconds: 45
readinessProbe:
httpGet:
path: /ready
port: 3100
initialDelaySeconds: 45Enable Graceful Shutdown
server:
graceful_shutdown_timeout: 30sWhy:
- Allows in-flight requests to complete
- Prevents data loss during restarts
- Smooth rolling updates
Use Configuration Management
Best practices:
- Store configs in Git
- Use configuration as code (Terraform, Helm)
- Validate configs before applying
- Test in staging before production
- Document all customizations
Regular Maintenance
Weekly:
- Review metrics and alerts
- Check for errors in logs
- Verify compaction is running
Monthly:
- Review and adjust limits based on actual usage
- Analyze storage growth trends
- Update Loki to latest stable version
Quarterly:
- Review architecture for scale
- Optimize queries and cardinality
- Conduct disaster recovery tests
Common Anti-Patterns
Don't Use High-Cardinality Labels
BAD:
# Don't use user_id, trace_id, request_id as labels
{app="api", user_id="12345"} # Creates too many streamsGOOD:
# Use structured metadata or line filters instead
{app="api"} | json | user_id="12345"Don't Ignore Limits
BAD:
limits_config:
max_streams_per_user: 0 # Unlimited - dangerous!GOOD:
limits_config:
max_streams_per_user: 10000 # Reasonable limitDon't Skip Replication
BAD:
common:
replication_factor: 1 # Single copy - data loss riskGOOD:
common:
replication_factor: 3 # Durability and availabilityDon't Use Filesystem Storage in Production
BAD:
common:
storage:
filesystem:
chunks_directory: /loki/chunks # Not scalableGOOD:
common:
storage:
s3:
s3: s3://region/bucket # Scalable and durableDon't Disable Authentication in Multi-Tenant Environments
BAD:
auth_enabled: false # No tenant isolationGOOD:
auth_enabled: true # Proper tenant isolationConfiguration Validation
Before Deployment
1. Validate syntax:
loki -config.file=loki.yaml -verify-config2. Review configuration:
loki -config.file=loki.yaml -print-config-stderr3. Test ingestion: Send test logs and verify they appear
4. Test queries: Run sample LogQL queries
After Deployment
1. Check health:
curl http://loki:3100/ready2. Monitor metrics: Review Prometheus metrics
3. Verify data ingestion: Check ingester and distributor logs
4. Test query performance: Run representative queries
Troubleshooting Guide
High Memory Usage
Symptoms:
- OOMKilled pods
- Slow queries
- High
loki_ingester_memory_streams
Solutions:
- Reduce
max_streams_per_user - Lower
chunk_idle_period - Check for cardinality explosion
- Add more ingester replicas
Slow Queries
Symptoms:
- Query timeouts
- High
loki_request_duration_seconds
Solutions:
- Increase
max_concurrentin querier - Enable query parallelization
- Add caching
- Optimize LogQL queries (use specific stream selectors)
- Add more querier replicas
Ingestion Failures
Symptoms:
- High
loki_distributor_ingester_append_failures_total - Missing logs
Solutions:
- Check ingestion rate limits
- Verify storage backend connectivity
- Check authentication headers
- Review distributor logs
- Increase ingester capacity
Storage Growing Rapidly
Symptoms:
- Storage costs increasing
- Running out of disk space
Solutions:
- Enable retention
- Review log volume and cardinality
- Implement sampling or filtering at source
- Check chunk compression settings
Thanos Object Storage Client (Loki 3.4+)
Loki 3.4 introduces new object storage clients based on the Thanos Object Storage Client. This is opt-in now but will become the default in future releases.
Enable Thanos Storage
storage_config:
use_thanos_objstore: true
object_store:
s3:
bucket_name: my-loki-bucket
endpoint: s3.us-west-2.amazonaws.com
region: us-west-2Key Migration Notes:
use_thanos_objstore: trueis mutually exclusive with legacy storage configdisable_dualstack→dualstack_enabled(inverted)signature_versionremoved (always uses V4)http_config→http(nested block)- Multiple bucket support removed (use single
bucket_name) - Storage prefix cannot contain dashes (
-) - use underscores
When using Thanos storage, ruler storage must be configured separately:
ruler_storage:
backend: s3
s3:
bucket_name: my-ruler-bucketTime Sharding for Out-of-Order Ingestion (Loki 3.4+)
For scenarios with delayed log delivery or historical imports:
limits_config:
shard_streams:
time_sharding_enabled: trueUse cases:
- Log backfilling
- Delayed log delivery (network issues, batch processing)
- Multi-region log aggregation with varying latencies
Bloom Filters (Experimental - Loki 3.0+)
Warning: Bloom filters are experimental and intended for deployments ingesting >75TB/month.
⚠️ BREAKING CHANGE (Loki 3.3+): Bloom filters now use structured metadata instead of free-text search. The block format (V3) is incompatible with previous versions. Delete existing bloom blocks before upgrading to 3.3+.
When to Use
Bloom filters accelerate "needle in haystack" queries on structured metadata:
bloom_build:
enabled: true
planner:
planning_interval: 6h
bloom_gateway:
enabled: true
worker_concurrency: 4
block_query_concurrency: 8
limits_config:
bloom_creation_enabled: true
bloom_gateway_enable_filtering: true
tsdb_sharding_strategy: boundedUse when:
- Large-scale deployments (>75TB/month)
- Frequent searches for specific values in structured metadata (trace IDs, UUIDs)
- Queries like:
{cluster="prod"} | traceID="3c0e3dcd33e7"
Don't use when:
- Small deployments (overhead > benefit)
- Queries mostly use label selectors
- Budget is a concern (requires additional storage)
- Need free-text search (blooms work on structured metadata only)
Best Practice for Bloom Queries:
# Good - filter structured metadata BEFORE parser
{cluster="prod"} | trace_id="abc123" | json | level="error"
# Bad - parser runs first, blooms can't help
{cluster="prod"} | json | trace_id="abc123" | level="error"Deprecated Storage and Configuration
⚠️ Deprecation Warnings
Deprecated Index Stores
boltdb/boltdb-shipper- Usetsdbinsteadbigtable- Migrate to TSDBdynamodb- Migrate to TSDBcassandra(for chunks) - Migrate to object storage
Deprecated Tools
- Promtail - Deprecated in Loki 3.4, commercial support ends February 28, 2026
- Use Grafana Alloy instead
- Migration:
alloy convert --source-format=promtail - Grafana Agent - Long-term support ended October 31, 2025
- Migrate to Grafana Alloy
- lokiexporter (OTel Collector) - Use
otlphttpinstead
Migration from BoltDB to TSDB
schema_config:
configs:
- from: 2020-01-01
store: boltdb-shipper # Keep for existing data
schema: v11
- from: 2025-01-01 # Add new period
store: tsdb # Use TSDB for new data
schema: v13Additional Resources
- Grafana Loki Best Practices
- Loki Configuration Reference
- Loki Operations Guide
- Loki Helm Charts
- OTLP Ingestion
- Grafana Alloy (Promtail replacement)
Related Skills
- logql-generator: For generating LogQL queries
- fluentbit-generator: For log collection pipelines to Loki
- promql-generator: For Prometheus (monitoring Loki)
Loki Configuration Reference
This document provides a comprehensive reference for Grafana Loki configuration parameters.
Current Stable Release: Loki 3.6.2 (November 2025)
Table of Contents
- Server Configuration
- Common Configuration
- Schema Configuration
- Storage Configuration
- Ingester Configuration
- Distributor Configuration
- Querier Configuration
- Query Frontend Configuration
- Query Range Configuration
- Compactor Configuration
- Limits Configuration
- Ruler Configuration
- Pattern Ingester Configuration
- Bloom Configuration
- Memberlist Configuration
- Caching Configuration
---
Server Configuration
The server block configures the HTTP and gRPC server settings.
server:
# HTTP server listen address
# CLI flag: -server.http-listen-address
[http_listen_address: <string> | default = ""]
# HTTP server listen port
# CLI flag: -server.http-listen-port
[http_listen_port: <int> | default = 3100]
# gRPC server listen address
# CLI flag: -server.grpc-listen-address
[grpc_listen_address: <string> | default = ""]
# gRPC server listen port
# CLI flag: -server.grpc-listen-port
[grpc_listen_port: <int> | default = 9095]
# Log level: debug, info, warn, error
# CLI flag: -log.level
[log_level: <string> | default = "info"]
# Log format: logfmt, json
# CLI flag: -log.format
[log_format: <string> | default = "logfmt"]
# Timeout for graceful shutdown
# CLI flag: -server.graceful-shutdown-timeout
[graceful_shutdown_timeout: <duration> | default = 30s]
# HTTP server read timeout
# CLI flag: -server.http-read-timeout
[http_server_read_timeout: <duration> | default = 30s]
# HTTP server write timeout
# CLI flag: -server.http-write-timeout
[http_server_write_timeout: <duration> | default = 30s]
# HTTP server idle timeout
# CLI flag: -server.http-idle-timeout
[http_server_idle_timeout: <duration> | default = 120s]
# Maximum number of simultaneous gRPC connections
# CLI flag: -server.grpc-max-concurrent-streams
[grpc_server_max_concurrent_streams: <int> | default = 100]
# TLS configuration for HTTP server
http_tls_config:
[cert_file: <string>]
[key_file: <string>]
[client_ca_file: <string>]
# TLS configuration for gRPC server
grpc_tls_config:
[cert_file: <string>]
[key_file: <string>]
[client_ca_file: <string>]---
Common Configuration
The common block configures shared settings across components.
common:
# Path prefix for data storage
[path_prefix: <string> | default = ""]
# Instance address for ring registration
[instance_addr: <string>]
# Replication factor for data durability
# CLI flag: -common.replication-factor
[replication_factor: <int> | default = 3]
# Storage configuration
storage:
# S3 storage configuration
s3:
[s3: <string>] # s3://region/bucket format
[s3forcepathstyle: <boolean> | default = false]
[access_key_id: <string>]
[secret_access_key: <string>]
[endpoint: <string>]
[region: <string>]
[insecure: <boolean> | default = false]
# GCS storage configuration
gcs:
[bucket_name: <string>]
[service_account: <string>]
[chunk_buffer_size: <int>]
# Azure storage configuration
azure:
[container_name: <string>]
[account_name: <string>]
[account_key: <string>]
[use_managed_identity: <boolean> | default = false]
[user_assigned_id: <string>]
# Filesystem storage configuration
filesystem:
[chunks_directory: <string>]
[rules_directory: <string>]
# Ring configuration for service discovery
ring:
kvstore:
# Store type: consul, etcd, memberlist, inmemory
[store: <string> | default = "memberlist"]
[prefix: <string> | default = "collectors/"]
# Consul configuration
consul:
[host: <string> | default = "localhost:8500"]
[acl_token: <string>]
# Etcd configuration
etcd:
[endpoints: <list of strings>]
[username: <string>]
[password: <string>]---
Schema Configuration
The schema_config block defines how Loki stores and indexes data. This is critical and cannot be changed after deployment without migration.
schema_config:
configs:
# Date when this schema takes effect (YYYY-MM-DD format)
- from: <daytime>
# Index store type: tsdb, boltdb-shipper (deprecated)
# TSDB is recommended for all new deployments
[store: <string> | default = "tsdb"]
# Object store type: s3, gcs, azure, filesystem
[object_store: <string>]
# Schema version: v13 is latest and recommended
[schema: <string> | default = "v13"]
# Index configuration
index:
# Table name prefix
[prefix: <string> | default = "index_"]
# Table period (24h recommended)
[period: <duration> | default = 24h]Best Practice: Always use store: tsdb and schema: v13 for new deployments.
---
Storage Configuration
Legacy Storage Configuration
storage_config:
# TSDB shipper configuration
tsdb_shipper:
[active_index_directory: <string>]
[cache_location: <string>]
[cache_ttl: <duration> | default = 24h]
index_gateway_client:
[server_address: <string>]
# AWS/S3 configuration
aws:
[s3: <string>]
[s3forcepathstyle: <boolean>]
[access_key_id: <string>]
[secret_access_key: <string>]
# GCS configuration
gcs:
[bucket_name: <string>]
# Azure configuration
azure:
[container_name: <string>]
[account_name: <string>]
[account_key: <string>]
# Filesystem configuration
filesystem:
[directory: <string>]Thanos Object Storage Client (Loki 3.4+)
The Thanos-based storage client provides consistent configuration across Grafana's databases.
storage_config:
# Enable Thanos object storage client
# MUTUALLY EXCLUSIVE with legacy storage config
use_thanos_objstore: true
object_store:
# Storage prefix for all objects (cannot contain dashes)
[storage_prefix: <string>]
# S3 configuration
s3:
[bucket_name: <string>]
[endpoint: <string>]
[region: <string>]
[access_key_id: <string>]
[secret_access_key: <string>]
[native_aws_auth_enabled: <boolean> | default = false]
[dualstack_enabled: <boolean> | default = false]
[storage_class: <string> | default = "STANDARD"]
[max_retries: <int> | default = 10]
# HTTP client settings
http:
[idle_conn_timeout: <duration> | default = 1m30s]
[response_header_timeout: <duration> | default = 2m]
[insecure_skip_verify: <boolean> | default = false]
# Server-side encryption
sse:
[type: <string>] # SSE-KMS or SSE-S3
[kms_key_id: <string>]
[kms_encryption_context: <string>]
# GCS configuration
gcs:
[bucket_name: <string>]
[service_account: <string>]
[chunk_buffer_size: <int>]
[max_retries: <int> | default = 5]
# Azure configuration
azure:
[account_name: <string>]
[account_key: <string>]
[container_name: <string>]
[use_managed_identity: <boolean> | default = false]
# Filesystem configuration
filesystem:
[dir: <string>] # Note: 'dir' not 'directory'Migration Notes:
use_thanos_objstore: trueis mutually exclusive with legacy storage configdisable_dualstack→dualstack_enabled(inverted logic)signature_versionremoved (always uses V4)http_config→http(nested block)- Storage prefix cannot contain dashes (
-) - use underscores
---
Ingester Configuration
The ingester block configures log ingestion and chunk management.
ingester:
# Chunk compression algorithm: snappy, gzip, lz4, none
# CLI flag: -ingester.chunk-encoding
[chunk_encoding: <string> | default = "snappy"]
# Flush inactive chunks after this period
# CLI flag: -ingester.chunk-idle-period
[chunk_idle_period: <duration> | default = 30m]
# Keep flushed chunks in memory for this duration
# CLI flag: -ingester.chunk-retain-period
[chunk_retain_period: <duration> | default = 15m]
# Maximum age of a chunk before flushing
# CLI flag: -ingester.max-chunk-age
[max_chunk_age: <duration> | default = 2h]
# Target compressed chunk size (bytes)
# CLI flag: -ingester.chunk-target-size
[chunk_target_size: <int> | default = 1572864] # 1.5MB
# Number of concurrent chunk flushes
# CLI flag: -ingester.concurrent-flushes
[concurrent_flushes: <int> | default = 16]
# Flush check interval
# CLI flag: -ingester.flush-check-period
[flush_check_period: <duration> | default = 30s]
# WAL (Write-Ahead Log) configuration
wal:
[enabled: <boolean> | default = true]
[dir: <string> | default = "wal"]
[flush_on_shutdown: <boolean> | default = true]
[replay_memory_ceiling: <int>]
# Lifecycler configuration for ring registration
lifecycler:
ring:
kvstore:
[store: <string>]
[replication_factor: <int> | default = 3]
[num_tokens: <int> | default = 128]
[heartbeat_period: <duration> | default = 5s]
[join_after: <duration> | default = 0s]
[observe_period: <duration> | default = 0s]
[interface_names: <list of strings>]
[final_sleep: <duration> | default = 30s]Best Practices:
- Use
chunk_encoding: snappyfor best speed/compression balance - Target 1.5MB chunks requires 5-10x raw log data
- Set
replication_factor: 3for production
---
Distributor Configuration
The distributor block configures log distribution to ingesters.
distributor:
ring:
kvstore:
[store: <string>]
[heartbeat_timeout: <duration> | default = 1m]
# OTLP configuration for default resource attributes
otlp_config:
# Override default list of resource attributes promoted to index labels
# Excludes high-cardinality attributes like k8s.pod.name, service.instance.id
default_resource_attributes_as_index_labels:
- service.name
- service.namespace
- deployment.environment
- cloud.region
- cloud.availability_zone
- k8s.cluster.name
- k8s.namespace.name
- k8s.container.name
- container.name
- k8s.deployment.name
- k8s.statefulset.name
- k8s.daemonset.name
- k8s.cronjob.name
- k8s.job.name
# Ingest limits (Loki 3.5+)
[ingest_limits_enabled: <boolean> | default = false]
[ingest_limits_dry_run_enabled: <boolean> | default = false]---
Querier Configuration
The querier block configures log query processing.
querier:
# Maximum concurrent queries per querier
# CLI flag: -querier.max-concurrent
[max_concurrent: <int> | default = 4]
# Query timeout
# CLI flag: -querier.query-timeout
[query_timeout: <duration> | default = 1m]
# Maximum duration for live tailing
# CLI flag: -querier.tail-max-duration
[tail_max_duration: <duration> | default = 1h]
# Extra delay before sending queries to storage
# CLI flag: -querier.extra-query-delay
[extra_query_delay: <duration> | default = 0s]
# Multi-tenant queries (requires auth_enabled: false)
[multi_tenant_queries_enabled: <boolean> | default = false]
# Engine configuration
engine:
[timeout: <duration> | default = 5m]
[max_look_back_period: <duration> | default = 30s]---
Query Frontend Configuration
The frontend block configures the query frontend.
frontend:
# Maximum outstanding requests per tenant
# CLI flag: -querier.max-outstanding-requests-per-tenant
[max_outstanding_per_tenant: <int> | default = 2048]
# Compress HTTP responses
# CLI flag: -querier.compress-http-responses
[compress_responses: <boolean> | default = true]
# Response encoding: protobuf (recommended) or json
[encoding: <string> | default = "protobuf"]
# Log queries longer than this duration
# CLI flag: -frontend.log-queries-longer-than
[log_queries_longer_than: <duration> | default = 0s]
# Downstream URL for query processing
[downstream_url: <string>]---
Query Range Configuration
The query_range block configures query splitting and caching.
query_range:
# Align queries with step intervals
# CLI flag: -querier.align-queries-with-step
[align_queries_with_step: <boolean> | default = false]
# Maximum retries for failed queries
# CLI flag: -querier.max-retries
[max_retries: <int> | default = 5]
# Enable parallel execution of shardable queries
# CLI flag: -querier.parallelise-shardable-queries
[parallelise_shardable_queries: <boolean> | default = true]
# Cache query results
[cache_results: <boolean> | default = false]
# Results cache configuration
results_cache:
cache:
# Embedded cache
embedded_cache:
[enabled: <boolean> | default = false]
[max_size_mb: <int> | default = 100]
[ttl: <duration> | default = 1h]
# Memcached client
memcached_client:
[host: <string>]
[service: <string>]
[timeout: <duration> | default = 500ms]
[max_idle_conns: <int> | default = 16]
[update_interval: <duration> | default = 1m]
[consistent_hash: <boolean> | default = true]
# Redis client
redis:
[endpoint: <string>]
[timeout: <duration>]
[expiration: <duration>]---
Compactor Configuration
The compactor block configures index compaction and retention.
compactor:
# Directory for compaction work
# CLI flag: -boltdb.shipper.compactor.working-directory
[working_directory: <string>]
# How often to run compaction
# CLI flag: -boltdb.shipper.compactor.compaction-interval
[compaction_interval: <duration> | default = 10m]
# Enable retention enforcement
# CLI flag: -compactor.retention-enabled
[retention_enabled: <boolean> | default = false]
# Delay before deleting expired data
# CLI flag: -compactor.retention-delete-delay
[retention_delete_delay: <duration> | default = 2h]
# Number of parallel deletion workers
# CLI flag: -compactor.retention-delete-worker-count
[retention_delete_worker_count: <int> | default = 150]
# Delete request store backend (Loki 3.5+)
# Options: boltdb, sqlite, s3, gcs, azure
# SQLite recommended over BoltDB for better query optimization
[delete_request_store: <string>]
# Horizontally Scalable Compactor (Loki 3.6+)
# Modes: disabled (default), main, worker
[horizontal_scaling_mode: <string> | default = "disabled"]
# Jobs configuration (for horizontal scaling)
jobs_config:
deletion:
[deletion_manifest_store_prefix: <string> | default = "__deletion_manifest__/"]
[timeout: <duration> | default = 15m]
[max_retries: <int> | default = 3]
[chunk_processing_concurrency: <int> | default = 3]
# Worker configuration (for horizontal scaling worker mode)
worker_config:
[num_sub_workers: <int> | default = 0] # 0 = use CPU core countHorizontal Compactor Modes (Loki 3.6+):
disabled: Traditional single compactor behaviormain: Distributes deletion work to workers; requires disk accessworker: Processes deletion jobs from main compactor via gRPC
---
Limits Configuration
The limits_config block sets rate limits and resource constraints.
limits_config:
# --- Ingestion Limits ---
# Maximum ingestion rate (MB/s) per tenant
# CLI flag: -distributor.ingestion-rate-limit-mb
[ingestion_rate_mb: <float> | default = 4]
# Maximum burst size (MB) per tenant
# CLI flag: -distributor.ingestion-burst-size-mb
[ingestion_burst_size_mb: <float> | default = 6]
# Maximum log line size
# CLI flag: -distributor.max-line-size
[max_line_size: <int> | default = 256KB]
# Truncate oversized lines instead of rejecting
# CLI flag: -distributor.max-line-size-truncate
[max_line_size_truncate: <boolean> | default = false]
# --- Stream Limits ---
# Maximum streams per tenant
# CLI flag: -ingester.max-streams-per-user
[max_streams_per_user: <int> | default = 10000]
# Maximum global streams per tenant (across all ingesters)
# CLI flag: -ingester.max-global-streams-per-user
[max_global_streams_per_user: <int> | default = 5000]
# Maximum label name length
# CLI flag: -validation.max-length-label-name
[max_label_name_length: <int> | default = 1024]
# Maximum label value length
# CLI flag: -validation.max-length-label-value
[max_label_value_length: <int> | default = 2048]
# Maximum labels per stream (reduced to 15 in Loki 3.0)
# CLI flag: -validation.max-label-names-per-series
[max_label_names_per_series: <int> | default = 15]
# --- Query Limits ---
# Maximum entries returned per query
# CLI flag: -querier.max-entries-limit-per-query
[max_entries_limit_per_query: <int> | default = 5000]
# Maximum query time range
# CLI flag: -querier.max-query-length
[max_query_length: <duration> | default = 721h]
# Maximum parallel sub-queries
# CLI flag: -querier.max-query-parallelism
[max_query_parallelism: <int> | default = 32]
# Maximum series per query
[max_query_series: <int> | default = 500]
# Maximum chunks per query
[max_chunks_per_query: <int> | default = 2000000]
# Query splitting interval (moved from query_range in 2.5.0)
# CLI flag: -querier.split-queries-by-interval
[split_queries_by_interval: <duration> | default = 30m]
# --- Retention ---
# Global retention period (requires compactor.retention_enabled)
# CLI flag: -limits.retention-period
[retention_period: <duration> | default = 0]
# Per-stream retention (optional)
retention_stream:
- selector: '{namespace="prod"}'
priority: 1
period: 720h # 30 days
# --- Structured Metadata (Loki 2.9+) ---
# Enable structured metadata
# CLI flag: -validation.allow-structured-metadata
[allow_structured_metadata: <boolean> | default = true]
# Maximum size per log line
# CLI flag: -limits.max-structured-metadata-size
[max_structured_metadata_size: <int> | default = 64KB]
# Maximum entries per log line
# CLI flag: -limits.max-structured-metadata-entries-count
[max_structured_metadata_entries_count: <int> | default = 128]
# --- Volume API ---
# Enable volume endpoints for Explore Logs / Grafana Drilldown
[volume_enabled: <boolean> | default = true]
# --- OTLP Configuration (Loki 3.0+) ---
otlp_config:
resource_attributes:
# Override default resource attributes list
[ignore_defaults: <boolean> | default = false]
# Attribute configuration
attributes_config:
- action: index_label # or structured_metadata, drop
attributes:
- service.name
- service.namespace
- action: structured_metadata
attributes:
- k8s.pod.name
- service.instance.id
- action: structured_metadata
regex: "cloud.*"
# Scope attributes configuration
scope_attributes:
- action: drop
attributes:
- otel.library.name
# Log attributes configuration
log_attributes:
- action: structured_metadata
attributes:
- trace_id
- span_id
- action: drop
regex: "internal.*"
# Store severity_text as index label (NOT recommended)
# CLI flag: -limits.otlp-config.severity-text-as-label
[severity_text_as_label: <boolean> | default = false]
# --- Time Sharding for Out-of-Order Ingestion (Loki 3.4+) ---
shard_streams:
[enabled: <boolean> | default = false]
[time_sharding_enabled: <boolean> | default = false]
# --- Enforced Labels (Experimental) ---
# Labels that must be present in every stream
# CLI flag: -validation.enforced-labels
[enforced_labels: <list of strings> | default = []]
# Policy-based enforced labels
# The '*' policy applies to all streams
policy_enforced_labels:
finance:
- cost_center
ops:
- team
'*':
- service.name
# Policy to stream selector mapping
policy_stream_mapping:
finance:
- selector: '{namespace="prod", container="billing"}'
priority: 2
ops:
- selector: '{namespace="prod", container="ops"}'
priority: 1
# --- Block Ingestion ---
# Block ingestion until date (RFC3339 format)
# CLI flag: -limits.block-ingestion-until
[block_ingestion_until: <time> | default = 0]
# Block ingestion per policy until date
[block_ingestion_policy_until: <map of string to Time>]
# HTTP status code when blocked (260 default, 200 for silent)
# CLI flag: -limits.block-ingestion-status-code
[block_ingestion_status_code: <int> | default = 260]
# --- Bloom Filters (Experimental, Loki 3.0+) ---
[bloom_creation_enabled: <boolean> | default = false]
[bloom_split_series_keyspace_by: <int> | default = 1024]
[bloom_gateway_enable_filtering: <boolean> | default = false]
[tsdb_sharding_strategy: <string>] # Use "bounded" for blooms
# --- Metric Aggregation ---
# Enable metric aggregation for faster histogram queries
# CLI flag: -limits.metric-aggregation-enabled
[metric_aggregation_enabled: <boolean> | default = false]
# --- Ruler Limits ---
[ruler_max_rules_per_rule_group: <int> | default = 100]
[ruler_max_rule_groups_per_tenant: <int> | default = 50]---
Ruler Configuration
The ruler block configures alerting and recording rules.
ruler:
# Rule evaluation interval
# CLI flag: -ruler.evaluation-interval
[evaluation_interval: <duration> | default = 1m]
# Rule polling interval
# CLI flag: -ruler.poll-interval
[poll_interval: <duration> | default = 1m]
# Storage configuration
storage:
# Storage type: local, s3, gcs, azure
[type: <string>]
local:
[directory: <string> | default = "/rules"]
s3:
[bucket_name: <string>]
[region: <string>]
gcs:
[bucket_name: <string>]
azure:
[container_name: <string>]
[account_name: <string>]
# Temporary rule file path
[rule_path: <string> | default = "/rules"]
# Alertmanager URL
# CLI flag: -ruler.alertmanager-url
[alertmanager_url: <string>]
# Use Alertmanager API v2 (default since Loki 3.2.0)
# CLI flag: -ruler.enable-alertmanager-v2
[enable_alertmanager_v2: <boolean> | default = true]
# Enable ruler API for rule management
# CLI flag: -ruler.enable-api
[enable_api: <boolean> | default = false]
# Enable rule sharding across instances
# CLI flag: -ruler.enable-sharding
[enable_sharding: <boolean> | default = false]
# Ring configuration for sharding
ring:
kvstore:
[store: <string>]
# Alert timing
[for_outage_tolerance: <duration> | default = 1h]
[for_grace_period: <duration> | default = 10m]
[resend_delay: <duration> | default = 1m]
# Remote write for recording rules
remote_write:
[enabled: <boolean> | default = false]
client:
[url: <string>]
[remote_timeout: <duration> | default = 30s]
# Alertmanager client configuration
alertmanager_client:
tls_config:
[ca_path: <string>]
[cert_path: <string>]
[key_path: <string>]
[basic_auth_username: <string>]
[basic_auth_password: <string>]Rule File Structure:
/rules/<tenant-id>/rules1.yaml
/rules2.yaml---
Pattern Ingester Configuration
The pattern_ingester block configures automatic log pattern detection (Loki 3.0+).
pattern_ingester:
# Enable pattern detection
[enabled: <boolean> | default = false]
# Metric aggregation configuration
metric_aggregation:
[enabled: <boolean> | default = false]
[loki_address: <string>]---
Bloom Configuration
Bloom filters accelerate "needle in haystack" queries on structured metadata (Loki 3.0+).
Warning: Experimental feature for deployments ingesting >75TB/month.
Breaking Change (Loki 3.3+): Bloom filters use structured metadata only (not free-text). Delete existing bloom blocks before upgrading.
# Bloom build configuration
bloom_build:
[enabled: <boolean> | default = false]
planner:
[planning_interval: <duration> | default = 6h]
[bloom_split_series_keyspace_by: <int> | default = 1024]
builder:
[planner_address: <string>]
# Bloom gateway configuration
bloom_gateway:
[enabled: <boolean> | default = false]
client:
[addresses: <string>]
[worker_concurrency: <int> | default = 4]
[block_query_concurrency: <int> | default = 8]
[max_query_page_size: <int> | default = 64MiB]
# Bloom shipper configuration
bloom_shipper:
[working_directory: <string>]---
Memberlist Configuration
The memberlist block configures gossip-based cluster coordination.
memberlist:
# Addresses of other nodes to join
join_members:
- loki-memberlist
# Port for gossip messages
# CLI flag: -memberlist.bind-port
[bind_port: <int> | default = 7946]
# Address to advertise to other nodes
[advertise_addr: <string>]
# Port to advertise
[advertise_port: <int>]
# Timeout for establishing a stream connection
[stream_timeout: <duration> | default = 2s]
# Interval between gossip messages
[gossip_interval: <duration> | default = 200ms]
# Number of random nodes to gossip to
[gossip_nodes: <int> | default = 3]---
Caching Configuration
Chunk Cache
chunk_store_config:
chunk_cache_config:
memcached:
[batch_size: <int> | default = 256]
[parallelism: <int> | default = 10]
memcached_client:
[host: <string>]
[service: <string>]
[timeout: <duration> | default = 500ms]
[max_idle_conns: <int> | default = 100]Results Cache
query_range:
cache_results: true
results_cache:
cache:
memcached_client:
[host: <string>]
[service: <string>]
[timeout: <duration> | default = 500ms]
[max_idle_conns: <int> | default = 100]
[consistent_hash: <boolean> | default = true]
[update_interval: <duration> | default = 1m]Note: TSDB does NOT need index cache - only chunks and results cache.
---
Additional Resources
Related skills
FAQ
What Loki settings does loki-config-generator produce?
The loki-config-generator skill outputs Grafana Loki YAML covering ingestion, retention, storage backends, rate limits, and compactor configuration. Developers use it when standing up centralized logging without manually drafting every operational section.
Who should use the loki-config-generator skill?
Platform and SRE engineers deploying Grafana Loki on Kubernetes or VMs benefit most from loki-config-generator. The skill fits new observability stacks and retention or storage tuning work, not teams committed to unrelated log platforms.