What is Loki
Loki is a horizontally scalable, highly available, multi-tenant log aggregation system inspired by Prometheus. Created by Grafana Labs, it is designed to be cost-effective and easy to operate by indexing only the metadata (labels) of log streams rather than the full text of log lines. This fundamental design choice makes Loki dramatically cheaper to run compared to traditional log management systems like Elasticsearch, while still providing powerful query capabilities through its custom query language called LogQL.
At its core, Loki treats logs as streams of time-series data, similar to how Prometheus handles metrics. Each log stream is identified by a set of key-value pairs called labels. The actual log content is stored as compressed, unstructured chunks in object storage like Amazon S3, Google Cloud Storage, or a local filesystem. This separation of metadata indexing from log content storage is what allows Loki to achieve such impressive cost efficiency and performance at scale.
Why Loki Matters
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →Traditional log aggregation solutions like the Elastic Stack (Elasticsearch, Logstash, Kibana) require full-text indexing of every log line. While this provides extremely fast full-text search capabilities, it comes with enormous operational costs: massive storage requirements, high memory consumption, complex cluster management, and expensive licensing. Loki takes a fundamentally different approach that aligns perfectly with modern cloud-native architectures.
Cost Efficiency
By storing only labels in the index and keeping log content in cheap object storage, Loki can reduce operational costs by up to 80% compared to Elasticsearch-based solutions. Object storage like S3 is typically 5-10x cheaper than the SSD-backed block storage required for full-text search indices. This makes Loki an ideal choice for organizations that need to retain logs for long periods for compliance or forensic purposes but don't want to pay premium prices for storage they rarely query.
Native Kubernetes Integration
Loki was built from the ground up with Kubernetes in mind. It automatically discovers pods and services, inherits metadata labels from Kubernetes objects, and integrates seamlessly with Prometheus monitoring. If you're already running Prometheus and Grafana, adding Loki completes the observability trifecta: metrics, logs, and traces all within the same ecosystem.
Simplified Operations
Unlike Elasticsearch clusters that require careful tuning of shard allocations, index lifecycle management, and heap sizes, Loki is relatively straightforward to operate. It runs as a single binary with a simple configuration file. Scaling is achieved by adding more instances behind a load balancer, and object storage handles durability and replication automatically.
Correlation with Metrics
One of Loki's most powerful features is the ability to correlate logs with metrics directly in Grafana. You can jump from a spike in your Prometheus metrics dashboard to the relevant logs with a single click, dramatically reducing mean time to resolution during incidents.
Architecture Overview
Understanding Loki's architecture is essential for successful implementation. The system consists of several interconnected components that work together to ingest, store, and query log data efficiently.
Core Components
- Ingester - Receives log entries from distributors, compresses them into chunks, and stores them in the configured storage backend. The ingester holds newly written chunks in memory temporarily before flushing them to long-term storage, providing a write buffer that improves performance.
- Distributor - Acts as the entry point for log ingestion. It validates incoming log streams, ensures label ordering consistency, and distributes log streams to the appropriate ingesters based on consistent hashing. This enables horizontal scaling of ingestion capacity.
- Querier - Handles LogQL queries by fetching relevant chunks from storage, decompressing them, and evaluating the query logic. In microservice mode, queriers also communicate with ingesters to access recently ingested logs that haven't been flushed to object storage yet.
- Query Frontend - Optional but recommended component that provides a queue for queries, splits large queries into smaller parallel operations, and caches query results. This significantly improves query performance under load.
- Compactor - Processes flushed chunks to create optimized, indexed chunks that improve query efficiency. It deduplicates logs, merges chunks, and builds index files for faster access patterns.
- Ruler - Evaluates alerting and recording rules against log streams, enabling you to create alerts based on log patterns and derive metrics from log data.
Deployment Modes
Loki supports three distinct deployment modes that cater to different scale requirements:
- Monolithic Mode - All components run in a single process. Ideal for development, testing, and small-scale production environments processing up to a few gigabytes of logs per day. This mode is the simplest to deploy and requires minimal infrastructure.
- Simple Scalable Mode - Splits Loki into two processes: read (querier, query frontend) and write (distributor, ingester). This mode is suitable for medium-scale deployments where you want to scale read and write independently without the full complexity of microservices.
- Microservices Mode - Each component runs as a separate service, allowing independent scaling of every function. This is the recommended mode for large-scale production deployments handling terabytes of logs daily. It requires a more complex infrastructure setup but provides maximum flexibility and resilience.
Setting Up Loki: Complete Implementation
Let's walk through a complete implementation of Loki in a production-ready configuration. We'll start with a simple monolithic setup for learning purposes, then progress to a scalable deployment suitable for production environments.
Step 1: Installing Loki in Monolithic Mode
The simplest way to get started is running Loki as a single binary. First, download the latest release:
# Download Loki binary for your architecture (Linux amd64 example)
curl -O https://github.com/grafana/loki/releases/download/v3.0.0/loki-linux-amd64.zip
unzip loki-linux-amd64.zip
chmod +x loki-linux-amd64
sudo mv loki-linux-amd64 /usr/local/bin/loki
Create a configuration file for the monolithic setup:
# /etc/loki/config.yaml
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
common:
instance_addr: 127.0.0.1
path_prefix: /var/loki
storage:
filesystem:
chunks_directory: /var/loki/chunks
rules_directory: /var/loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
ingester:
chunk_idle_period: 5m
chunk_block_size: 262144
chunk_retain_period: 1m
max_transfer_retries: 0
wal:
enabled: true
dir: /var/loki/wal
schema_config:
configs:
- from: 2024-01-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
storage_config:
tsdb_shipper:
active_index_directory: /var/loki/tsdb-index
cache_location: /var/loki/tsdb-cache
shared_store: filesystem
limits_config:
allow_structured_metadata: true
volume_enabled: true
reject_old_samples: true
reject_old_samples_max_age: 168h
compactor:
working_directory: /var/loki/compactor
compaction_interval: 10m
Create the required directories and start Loki:
# Create storage directories
sudo mkdir -p /var/loki/{chunks,rules,wal,tsdb-index,tsdb-cache,compactor}
sudo chown -R $USER:$USER /var/loki
# Start Loki
loki -config.file=/etc/loki/config.yaml
Step 2: Setting Up Promtail for Log Collection
Promtail is the official agent for collecting logs and sending them to Loki. It automatically discovers targets, scrapes log files, and enriches them with labels before pushing them to Loki. Install Promtail:
# Download Promtail
curl -O https://github.com/grafana/loki/releases/download/v3.0.0/promtail-linux-amd64.zip
unzip promtail-linux-amd64.zip
chmod +x promtail-linux-amd64
sudo mv promtail-linux-amd64 /usr/local/bin/promtail
Create the Promtail configuration:
# /etc/promtail/config.yaml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /var/promtail/positions.yaml
clients:
- url: http://localhost:3100/loki/api/v1/push
batchwait: 1s
batchsize: 1048576
timeout: 10s
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
host: ${HOSTNAME}
__path__: /var/log/*.log
- job_name: containers
static_configs:
- targets:
- localhost
labels:
job: container-logs
__path__: /var/log/containers/*.log
- job_name: journald
journal:
max_age: 12h
labels:
job: journald
Start Promtail:
# Create positions directory
sudo mkdir -p /var/promtail
sudo chown -R $USER:$USER /var/promtail
# Start Promtail
promtail -config.file=/etc/promtail/config.yaml
Step 3: Docker Container Log Collection
For collecting Docker container logs, Promtail can integrate with the Docker socket directly:
# Add this scrape_config to /etc/promtail/config.yaml
scrape_configs:
- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 15s
relabel_configs:
- source_labels: ['__meta_docker_container_name']
regex: '/(.*)'
target_label: 'container'
- source_labels: ['__meta_docker_container_image']
target_label: 'image'
- source_labels: ['__meta_docker_container_id']
target_label: 'container_id'
- source_labels: ['__meta_docker_network_name']
target_label: 'network'
Step 4: Kubernetes Log Collection with Promtail DaemonSet
In Kubernetes environments, Promtail is typically deployed as a DaemonSet to collect logs from every node. Here's the complete Kubernetes deployment manifest:
# promtail-daemonset.yaml
apiVersion: v1
kind: Namespace
metadata:
name: loki
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: promtail
namespace: loki
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: promtail
rules:
- apiGroups: [""]
resources: ["nodes", "nodes/proxy", "services", "endpoints", "pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: promtail
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: promtail
subjects:
- kind: ServiceAccount
name: promtail
namespace: loki
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: promtail
namespace: loki
labels:
app: promtail
spec:
selector:
matchLabels:
app: promtail
template:
metadata:
labels:
app: promtail
spec:
serviceAccountName: promtail
containers:
- name: promtail
image: grafana/promtail:3.0.0
args:
- -config.file=/etc/promtail/promtail-config.yaml
env:
- name: HOSTNAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumeMounts:
- name: config
mountPath: /etc/promtail
- name: positions
mountPath: /var/promtail
- name: varlog
mountPath: /var/log
- name: pod-logs
mountPath: /var/log/pods
readOnly: true
- name: docker-logs
mountPath: /var/lib/docker/containers
readOnly: true
securityContext:
privileged: true
volumes:
- name: config
configMap:
name: promtail-config
- name: positions
hostPath:
path: /var/promtail
- name: varlog
hostPath:
path: /var/log
- name: pod-logs
hostPath:
path: /var/log/pods
- name: docker-logs
hostPath:
path: /var/lib/docker/containers
---
apiVersion: v1
kind: ConfigMap
metadata:
name: promtail-config
namespace: loki
data:
promtail-config.yaml: |
server:
log_level: info
clients:
- url: http://loki-gateway.loki.svc.cluster.local/loki/api/v1/push
batchwait: 1s
batchsize: 1048576
timeout: 10s
external_labels:
cluster: production
positions:
filename: /var/promtail/positions.yaml
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels:
- __meta_kubernetes_pod_controller_name
regex: (.+)
target_label: controller
- source_labels:
- __meta_kubernetes_pod_controller_kind
regex: (.+)
target_label: controller_kind
- source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- source_labels:
- __meta_kubernetes_pod_name
target_label: pod
- source_labels:
- __meta_kubernetes_pod_container_name
target_label: container
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- action: replace
source_labels:
- __meta_kubernetes_pod_node_name
target_label: node_name
pipeline_stages:
- docker: {}
Apply the DaemonSet to your cluster:
kubectl apply -f promtail-daemonset.yaml
Querying Logs with LogQL
LogQL is Loki's query language, inspired by PromQL. It enables powerful log analysis, filtering, and aggregation. Understanding LogQL thoroughly is key to extracting maximum value from Loki.
Basic Log Queries
A basic LogQL query consists of a log stream selector followed by an optional log pipeline. The stream selector identifies which log streams to query based on labels:
# Select all logs from the production namespace
{namespace="production"}
# Select logs from a specific job with error level
{job="varlogs", level="error"}
# Select logs from multiple namespaces using regex
{namespace=~"production|staging"}
# Exclude logs matching a pattern
{job="varlogs"} != "DEBUG"
Filter Expressions
Filter expressions allow you to search within log lines. They are evaluated after stream selection:
# Find logs containing specific text
{namespace="production"} |= "error"
# Find logs that do NOT contain specific text
{namespace="production"} != "DEBUG"
# Case-insensitive filtering
{namespace="production"} |~ "(?i)error|fail"
# Multiple chained filters
{namespace="production"} |= "error" != "timeout" |= "database"
Label and Line Format Expressions
Transform log content and labels during query time:
# Extract labels from log content using regex
{job="varlogs"} | regexp "(?P\\d+\\.\\d+\\.\\d+\\.\\d+)"
| line_format "IP address {{.ip}} was accessed"
# Parse JSON logs and extract fields
{job="app-logs"} | json | line_format "{{.level}}: {{.message}}"
# Parse logfmt-style logs
{job="app-logs"} | logfmt | line_format "{{.method}} {{.path}} {{.status}}"
Range Aggregation Queries
Range aggregations transform log streams into time-series metrics:
# Count log lines per minute
count_over_time({job="varlogs"}[5m])
# Rate of log lines per second
rate({job="app-logs"}[5m])
# Count specific log patterns over time
sum by (level) (count_over_time({job="varlogs"}
| logfmt | level=~"error|warn"[5m]))
# Calculate error rate percentage
sum(rate({job="app-logs"} | logfmt | level="error"[5m]))
/ sum(rate({job="app-logs"}[5m])) * 100
Advanced LogQL Examples
Here are practical examples that demonstrate LogQL's power in real-world scenarios:
# Find HTTP 500 errors and extract request duration
{job="nginx"} | json | status >= 500
| line_format "Status {{.status}} for {{.request}} took {{.duration}}s"
# Count unique IPs accessing a service
count(count_over_time({job="nginx"}
| json | unwrap ip [1h])) by (ip)
# Find slow database queries
{job="postgres-logs"}
| pattern "<_> duration: ms <_>"
| duration > 1000
# Calculate 99th percentile of response times
quantile_over_time(0.99,
{job="api-logs"} | json | unwrap response_time_ms [5m]
) by (endpoint)
# Detect spike in error rate compared to average
rate({job="api-logs"} | logfmt | level="error"[5m])
> 2 * rate({job="api-logs"} | logfmt | level="error"[1h])
Visualizing Logs in Grafana
Grafana provides native support for Loki as a data source, enabling seamless log exploration and dashboard creation. The integration allows you to view logs alongside metrics and create unified dashboards.
Adding Loki as a Data Source
In Grafana, navigate to Configuration → Data Sources → Add data source, select Loki, and configure the connection:
# Grafana data source configuration
Name: Loki Production
URL: http://loki-gateway:3100
Max lines: 1000
Derived fields:
- Name: traceID
Regex: traceID=(.*?)(?:\\s|$)
URL: http://jaeger-query:16686/trace/${__value.raw}
Creating Log Dashboards
Build comprehensive dashboards combining logs and metrics. Here's an example dashboard panel configuration for visualizing error rates alongside log volumes:
# Grafana dashboard JSON for a logs overview panel
{
"dashboard": {
"title": "Application Logs Overview",
"panels": [
{
"title": "Log Volume by Level",
"type": "timeseries",
"targets": [
{
"expr": "sum by (level) (count_over_time(
{job=\"app-logs\"} | logfmt [5m]))",
"legendFormat": "{{level}}"
}
]
},
{
"title": "Error Rate",
"type": "stat",
"targets": [
{
"expr": "sum(rate(
{job=\"app-logs\"} | logfmt | level=\"error\" [5m]
)) / sum(rate({job=\"app-logs\"}[5m])) * 100",
"legendFormat": "Error %"
}
],
"fieldConfig": {
"defaults": {
"unit": "percent"
}
}
},
{
"title": "Recent Error Logs",
"type": "logs",
"targets": [
{
"expr": "{job=\"app-logs\"} | logfmt | level=\"error\"",
"maxLines": 100
}
]
}
]
}
}
Loki Explore Mode
Grafana's Explore mode is purpose-built for log investigation. You can:
- View live streaming logs in real-time
- Search across massive time ranges with instant results
- Correlate log patterns with metric anomalies
- Export log query results for sharing or further analysis
- Create alerts directly from log queries
Production Deployment Considerations
Moving Loki to production requires careful planning around storage, scaling, and reliability. Here's what you need to know for a successful production deployment.
Storage Backend Configuration
For production, object storage is strongly recommended over filesystem storage. Here's how to configure different storage backends:
# S3-compatible storage configuration
storage_config:
aws:
s3:
endpoint: s3.amazonaws.com
region: us-east-1
bucket: loki-logs-production
access_key_id: ${AWS_ACCESS_KEY_ID}
secret_access_key: ${AWS_SECRET_ACCESS_KEY}
s3force_immediate_uploads: true
tsdb_shipper:
active_index_directory: /var/loki/tsdb-index
cache_location: /var/loki/tsdb-cache
shared_store: s3
# Google Cloud Storage configuration
storage_config:
gcs:
bucket_name: loki-logs-production
service_account_key: /etc/loki/gcs-key.json
tsdb_shipper:
active_index_directory: /var/loki/tsdb-index
cache_location: /var/loki/tsdb-cache
shared_store: gcs
# Azure Blob Storage configuration
storage_config:
azure:
account_name: lokistorage
account_key: ${AZURE_ACCOUNT_KEY}
container_name: loki-logs
tsdb_shipper:
active_index_directory: /var/loki/tsdb-index
cache_location: /var/loki/tsdb-cache
shared_store: azure
High Availability Configuration
For production HA setup, configure memberlist for cluster coordination and deploy multiple instances:
# HA configuration snippet
common:
ring:
kvstore:
store: memberlist
replication_factor: 3
storage:
filesystem: null # Disable local filesystem in HA mode
memberlist:
bind_port: 7946
join_members:
- loki-ingester-1.loki.svc.cluster.local:7946
- loki-ingester-2.loki.svc.cluster.local:7946
- loki-ingester-3.loki.svc.cluster.local:7946
max_join_retries: 10
rejoin_interval: 10s
Resource Sizing Guidelines
Proper resource allocation is critical for production stability. Here are recommended starting points based on log volume:
# Resource recommendations by log volume
# Small (50GB/day):
# CPU: 4 cores, Memory: 8GB, Storage: 500GB S3
# Medium (500GB/day):
# CPU: 8 cores per component, Memory: 16GB per component
# Separate read/write paths, Storage: 5TB S3
# Large (5TB+/day):
# Full microservices deployment
# Distributor: 4x instances (4 CPU, 8GB RAM each)
# Ingester: 12x instances (8 CPU, 32GB RAM each)
# Querier: 8x instances (8 CPU, 24GB RAM each)
# Query Frontend: 2x instances (2 CPU, 4GB RAM each)
# Storage: S3 with intelligent tiering
Authentication and Multi-Tenancy
Enable authentication for multi-tenant environments where different teams share the same Loki infrastructure:
# Authentication configuration
auth_enabled: true
auth:
type: basic # or 'bearer_token' for production
# Multi-tenancy configuration
limits_config:
allow_structured_metadata: true
max_streams_per_user: 10000
max_global_streams_per_user: 5000
ingestion_rate_mb: 10
ingestion_burst_size_mb: 20
max_query_series: 500
query_timeout: 5m
# Per-tenant overrides (runtime configuration file)
overrides:
tenant-a:
ingestion_rate_mb: 50
max_streams_per_user: 50000
tenant-b:
ingestion_rate_mb: 5
max_streams_per_user: 1000
Alerting and Recording Rules
Loki's ruler component enables you to create alerts based on log patterns and derive metrics from log data. This transforms logs from a passive forensic tool into an active monitoring signal.
Configuring Alert Rules
# /etc/loki/rules/app-alerts.yaml
groups:
- name: application-critical
interval: 1m
rules:
- alert: HighErrorRate
expr: |
sum(rate({job="api-logs"} | logfmt | level="error"[5m]))
/ sum(rate({job="api-logs"}[5m])) > 0.05
for: 5m
labels:
severity: critical
team: backend
annotations:
summary: High error rate detected
description: "Error rate is {{ $value | humanizePercentage }} in the last 5 minutes"
runbook_url: https://runbooks.example.com/high-error-rate
- alert: DatabaseConnectionFailures
expr: |
increase({job="postgres-logs"}
|= "connection refused"[5m]) > 5
for: 2m
labels:
severity: warning
annotations:
summary: Database connection failures detected
- alert: SlowRequestSpike
expr: |
quantile_over_time(0.95,
{job="api-logs"} | json | unwrap duration_ms [5m]
) > 500
for: 5m
labels:
severity: warning
annotations:
summary: 95th percentile latency exceeds 500ms
Recording Rules for Derived Metrics
# Recording rules to derive metrics from logs
groups:
- name: app-metrics
interval: 1m
rules:
- record: job:error_rate:5m
expr: |
sum(rate({job="api-logs"} | logfmt | level="error"[5m]))
/ sum(rate({job="api-logs"}[5m]))
- record: endpoint:latency_p95:5m
expr: |
quantile_over_time(0.95,
{job="api-logs"} | json | unwrap latency [5m]
) by (endpoint)
- record: job:request_count:5m
expr: |
sum(count_over_time({job="api-logs"}[5m])) by (job)
Best Practices
Following these best practices will help you get the most out of Loki while avoiding common pitfalls that can lead to performance problems or operational difficulties.
Label Management
Labels are the single most important factor in Loki's performance. Unlike Prometheus where high cardinality labels are manageable, Loki's index is label-based, meaning every unique label combination creates a separate stream. Keep labels bounded and predictable:
- Use static labels for broad categorization — job, environment, namespace, cluster are excellent candidates
- Never put dynamic values in labels — user IDs, request IDs, timestamps, IP addresses must never become labels
- Use structured metadata for high-cardinality data — Loki supports structured metadata that doesn't get indexed but can be filtered
- Limit total label combinations per tenant — aim for fewer than 50,000 unique stream combinations
Structured Logging
Logs are most useful when they follow a consistent, parseable format. Structured logging dramatically improves LogQL query efficiency:
# Good: Structured JSON logging
{
"timestamp": "2024-01-15T10:30:45.123Z",
"level": "error",
"service": "payment-service",
"endpoint": "/api/v1/checkout",
"duration_ms": 2345,
"status": 500,
"error": "database timeout",
"trace_id": "abc123def456"
}
# Better approach: Configure your application to emit JSON logs
# Example Python logging configuration
import logging
import json
from datetime import datetime
class JSONFormatter(logging.Formatter):
def format(self, record):
log_entry = {
"timestamp": datetime.utcnow().isoformat(),
"level": record.levelname,
"logger": record.name,
"message": record.getMessage(),
"pathname": record.pathname,
"lineno": record.lineno,
"service": "payment-service"
}
if hasattr(record, 'trace_id'):
log_entry['trace_id'] = record.trace_id
return json.dumps(log_entry)
logger = logging.getLogger()
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)
Performance Optimization
- Keep chunk sizes optimal — configure chunk_block_size between 256KB and 1MB. Larger chunks reduce storage operations but increase query latency for small time ranges
- Configure appropriate flush intervals — chunk_idle_period of 5-15 minutes balances memory usage against query freshness
- Use the query frontend for production — it provides query splitting, caching, and result merging that dramatically improves performance for dashboards
- Set reasonable query limits — max_query_series, query_timeout, and max_query_length protect the system from expensive queries
- Implement query result caching — the query frontend cache can serve repeated dashboard queries from cache, reducing load on queriers
Retention and Storage Management
Define retention policies that align with your compliance requirements and budget:
# Retention configuration example
limits_config:
retention_period: 30d # Global retention
# Per-stream retention for different log types
compactor:
retention_enabled: true
retention_period: 30d
delete_request_store: s3
# Configure lifecycle policies on your object storage bucket
# AWS S3 lifecycle policy example:
{
"Rules": [
{
"id": "log-retention-90d",
"filter": {
"prefix": "index_"
},
"status": "Enabled",
"transitions": [
{
"days": 30,
"storageClass": "INTELLIGENT_TIERING"
}
],
"expiration": {
"days": 90
}
}
]
}
Monitoring Loki Itself
Monitor Loki's own health to ensure your logging pipeline remains reliable:
# Key metrics to monitor
# Loki exposes Prometheus metrics at /metrics
# Ingestion health
loki_distributor_bytes_received_total
loki_distributor_lines_received_total
loki_ingester_chunk_age_seconds
# Query performance
loki_query_frontend_queue_length
loki_querier_request_duration_seconds
# Storage operations
loki_ingester_chunks_flushed_total
loki_compactor_compaction_duration_seconds
# Create alert rules for Loki itself
groups:
- name: loki-health
rules:
- alert: LokiIngestionLatency
expr: |
loki_ingester_chunk_age_seconds > 300
annotations:
summary: "Ingester chunks are aging, possible ingestion backlog"
- alert: LokiQueryQueueBacklog
expr: |
loki_query_frontend_queue_length > 50
for: 5m
annotations:
summary: "Query queue is backing up, slow queries may be occurring"
Security Considerations
- Enable TLS for all components — use mutual TLS between Loki components in microservices mode
- Implement network policies — restrict access to Loki's HTTP and gRPC ports in Kubernetes
- Use authentication even in internal deployments — prevent accidental access to sensitive log data
- Redact sensitive data at ingestion time — use Promtail pipeline stages to mask PII before logs reach Loki
- Implement audit logging — track who queries which log streams for compliance
Pipeline Processing in Promtail
Promtail's pipeline stages allow you to transform, filter, and enrich logs before they reach Loki