DEV Community

SHARON SHAJI
SHARON SHAJI

Posted on

Modern Logging with Grafana Alloy + Loki

A guide to collect Docker and host logs using Grafana Alloy + Loki, and why Alloy is replacing Promtail. Includes diagrams, permissions, docker-compose, and config files.

Containers made deployments fast, portable, and efficient.

But collecting logs from hosts + containers + services quickly becomes chaotic.

That’s why the modern stack uses Grafana Alloy + Loki instead of the older Promtail-based approach.

🧠 Why Grafana Loki Uses Alloy Instead of Promtail

Promtail served its purpose well β€” but infrastructure evolved.

Grafana introduced Alloy as its unified, modern, extensible telemetry collector.

πŸ”₯ Promtail vs Alloy (Honest Breakdown)

Feature Promtail Alloy
Log Collection βœ”οΈ Yes βœ”οΈ Yes
Metrics Collection ❌ No βœ”οΈ Yes
Traces Collection ❌ No βœ”οΈ Yes
Unified pipeline ❌ βœ”οΈ Logs + Metrics + Traces
Docker auto-discovery Limited βœ”οΈ Excellent
Processing pipeline Basic βœ”οΈ Powerful
Extensibility Low βœ”οΈ High
Future support πŸŸ₯ Legacy 🟩 Actively developed

πŸ“Œ The real reason Alloy replaces Promtail

Promtail = log-only agent

Alloy = one collector for logs, metrics, and traces

Promtail is now maintenance-only.

Alloy is the future.


🧩 Architecture Overview

The logging pipeline includes:

  • Alloy β†’ collector
  • Loki β†’ log store
  • Grafana β†’ visualization

πŸ”₯ High-level workflow

Host Logs β†’
Alloy β†’ Loki β†’ Grafana
Docker Logs β†’


🧱 Architecture Diagram (Text View)

                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                  β”‚        Grafana            β”‚
                  β”‚  (Dashboards + Logs)      β”‚
                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚       Loki          β”‚
                    β”‚    (Log Store)      β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚              Alloy                    β”‚
            β”‚   (Unified Telemetry Collector).      β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚           β”‚
                 Host Logs      Docker Logs
             (/var/log/*)   (via Docker Engine)

Enter fullscreen mode Exit fullscreen mode

πŸ“ Folder Structure

/opt/alloy/
β”œβ”€β”€ alloy/
β”‚ └── config.alloy
β”œβ”€β”€ grafana-data/
β”œβ”€β”€ loki/
β”‚ └── loki-config.yaml
β”œβ”€β”€ loki-data/
└── docker-compose.yml

πŸ” Required Permissions (Critical)

Loki & Grafana will fail without correct folder ownership.

Loki storage (UID/GID 10001)

sudo mkdir -p /opt/alloy/loki-data
sudo chown -R 10001:10001 /opt/alloy/loki-data
Enter fullscreen mode Exit fullscreen mode
sudo mkdir -p /opt/alloy/grafana-data
sudo chown -R 472:472 /opt/alloy/grafana-data
Enter fullscreen mode Exit fullscreen mode

🐳 docker-compose.yaml (Production Ready)

services:
  loki:
    image: grafana/loki:3.1.0
    container_name: loki
    command: -config.file=/etc/loki/local-config.yaml
    volumes:
      - ./loki/loki-config.yaml:/etc/loki/loki-config.yaml:ro
      - ./loki-data:/loki
    ports:
      - "3100:3100"

  alloy:
    image: grafana/alloy:latest
    container_name: alloy
    privileged: true
    volumes:
      - ./alloy/config.alloy:/etc/alloy/config.alloy:ro
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/log:/var/log:ro
    ports:
      - "12345:12345"

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    volumes:
      - ./grafana-data:/var/lib/grafana    
  ports:
      - "3000:3000"

Enter fullscreen mode Exit fullscreen mode

βš™οΈ config.alloy


### Send Alloy’s internal logs to Loki
logging {
  level  = "info"
  format = "logfmt"
  write_to = [loki.relabel.alloy_logs.receiver]
}

### Auto-discover Docker containers
discovery.docker "local_docker" {
  host = "unix:///var/run/docker.sock"
}

### Match host logs (/var/log/*log)
local.file_match "host_logs" {
  path_targets = [
    { __path__ = "/var/log/*log" },
  ]
}

### Tail host logs
loki.source.file "host_tail" {
  targets    = local.file_match.host_logs.targets
  forward_to = [loki.process.host_pipeline.receiver]
}

### Add static labels to host logs
loki.process "host_pipeline" {
  forward_to = [loki.write.local.receiver]

  stage.static_labels {
    values = {
      job     = "varlogs",
      source  = "host",
      env     = "dev",
    }
  }
}

### Collect logs from Docker containers (stdout/stderr)
loki.source.docker "docker_engine" {
  host = "unix:///var/run/docker.sock"

  targets = discovery.docker.local_docker.targets

  labels = {
    job     = "docker_logs",
    env     = "dev",
    cluster = "local",
  }

  forward_to = [loki.write.local.receiver]
}

### Loki ingest endpoint
loki.write "local" {
  endpoint {
    url = "http://loki:3100/loki/api/v1/push"
  }
}

### Add label to internal Alloy logs
loki.relabel "alloy_logs" {
  forward_to = [loki.write.local.receiver]

  rule {
    target_label = "service"
    replacement  = "alloy"
  }
}
Enter fullscreen mode Exit fullscreen mode

loki-config.yaml

auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 9096

common:
  instance_addr: 127.0.0.1
  path_prefix: /loki
  storage:
    filesystem:
      chunks_directory: /loki/chunks
      rules_directory: /loki/rules
  replication_factor: 1
  ring:
    kvstore:
      store: inmemory

query_range:
  results_cache:
    cache:
      embedded_cache:
        enabled: true
        max_size_mb: 100

limits_config:
  ingestion_rate_mb: 10
  ingestion_burst_size_mb: 20
  max_concurrent_tail_requests: 20
  max_cache_freshness_per_query: 10m
  max_streams_per_user: 50
  allow_structured_metadata: false

schema_config:
  configs:
    - from: 2024-01-01
      store: tsdb
      object_store: filesystem
      schema: v13
      index:
        prefix: index_
        period: 24h
Enter fullscreen mode Exit fullscreen mode

πŸš€ Restart and Run

docker compose up -d
Enter fullscreen mode Exit fullscreen mode
  • βœ” All Docker logs collected
  • βœ” All host logs collected
  • βœ” Alloy logs included with label service=alloy
  • βœ” Grafana fully functional
  • βœ” No permission errors
  • βœ” Production-grade observability pipeline

Alloy replaces Promtail and simplifies the entire telemetry ecosystem β€” logs, metrics, traces β€” in one place.

Top comments (0)