Skip to main content

Loki - Promtail & Grafana for System Logs.

Shenzhen, China

Loki is a horizontally-scalable, highly-available, multi-tenant log aggregation system inspired by Prometheus. It is designed to be very cost effective and easy to operate. It does not index the contents of the logs, but rather a set of labels for each log stream.

Installation with Docker

You can install Loki and Promtail with Docker or Docker Compose if you are evaluating, testing, or developing Loki.

Dry-run with Docker Compose

Run the following commands in your command line. They work for Windows or Linux systems.

wget https://raw.githubusercontent.com/grafana/loki/v2.3.0/production/docker-compose.yaml -O docker-compose.yaml

docker-compose -f docker-compose.yml up

nano /opt/loki/docker-compose.yml

version: "3"

networks:
  loki:

services:
  loki:
    image: grafana/loki:2.3.0
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml
    networks:
      - loki

  promtail:
    image: grafana/promtail:2.3.0
    volumes:
      - /var/log:/var/log
    command: -config.file=/etc/promtail/config.yml
    networks:
      - loki

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    networks:
      - loki

Navigate to http://localhost:3100/metrics to view the metrics and http://localhost:3100/ready readiness of the Loki database.

The Docker-Compose file looks like:

Now visit the server IP on Port 3000. Login with admin/admin, e.g.:

http://192.168.2.111:3000/login

Loki - Grafana and Prometheus

Ok - this worked - shut everything down with docker-compose down and going to the next step:

Configuring the Services

Promtail

Promtail - similar to Elastic Logstash - ingests log files for us and forwards them to our database Loki. We need to configure it to keep an eye on a specific log or a log directory. The official config example is:

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://localhost:3100/loki/api/v1/push

scrape_configs:
- job_name: system
  static_configs:
  - targets:
      - localhost
    labels:
      job: varlogs
      __path__: /var/log/*log

Which would keep an eye on our Linux system log directory. Since we are running the service inside a Docker container, we have to point Promtail to an internal directory and modify our docker-compose file to mount in the log file from our host system. The resulting configuration file looks like:

nano /opt/loki/config/promtail-config.yml

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
- job_name: nginx_log
  static_configs:
  - targets:
      - loki
    labels:
      job: varlogs
      __path__: /opt/nginx_access.log

The NGINX logfile is located in /opt/loki/logs/nginx_access.log on my host and will be mounted to /opt/nginx_access.log inside the Promtail container by the Docker-Compose file below.

All the demo files I found online usually use the localhost:3100 URL - make sure to change this to loki:3100. We are running our setup in an virtual environment where docker provides a DNS service that allows us to resolve container names to their IP addresses inside the docker network.

Loki

For Loki I am going to use the default config you can download from Github:

In the downloaded version there was a path /tmp/loki/rules-temp that I had to replace with /loki/rules-temp for this config to work.

nano /opt/loki/config/loki-config.yml

auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 9096

ingester:
  wal:
    enabled: true
    dir: /tmp/wal
  lifecycler:
    address: 127.0.0.1
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
    final_sleep: 0s
  chunk_idle_period: 1h       # Any chunk not receiving new logs in this time will be flushed
  max_chunk_age: 1h           # All chunks will be flushed when they hit this age, default is 1h
  chunk_target_size: 1048576  # Loki will attempt to build chunks up to 1.5MB, flushing first if chunk_idle_period or max_chunk_age is reached first
  chunk_retain_period: 30s    # Must be greater than index read cache TTL if using an index cache (Default index read cache TTL is 5m)
  max_transfer_retries: 0     # Chunk transfers disabled

schema_config:
  configs:
    - from: 2020-10-24
      store: boltdb-shipper
      object_store: filesystem
      schema: v11
      index:
        prefix: index_
        period: 24h

storage_config:
  boltdb_shipper:
    active_index_directory: /tmp/loki/boltdb-shipper-active
    cache_location: /tmp/loki/boltdb-shipper-cache
    cache_ttl: 24h         # Can be increased for faster performance over longer query periods, uses more disk space
    shared_store: filesystem
  filesystem:
    directory: /tmp/loki/chunks

compactor:
  working_directory: /tmp/loki/boltdb-shipper-compactor
  shared_store: filesystem

limits_config:
  reject_old_samples: true
  reject_old_samples_max_age: 168h

chunk_store_config:
  max_look_back_period: 0s

table_manager:
  retention_deletes_enabled: false
  retention_period: 0s

ruler:
  storage:
    type: local
    local:
      directory: /tmp/loki/rules
  rule_path: /loki/rules-temp
  alertmanager_url: http://localhost:9093
  ring:
    kvstore:
      store: inmemory
  enable_api: true

Docker Compose

Now we need to make sure that those configuration files and logs are mounted into the correct containers:

version: "3"

networks:
  loki:

services:
  loki:
    image: grafana/loki:2.3.0
    volumes:
      - /opt/loki/config/loki-config.yml:/etc/loki/loki-config.yml
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/loki-config.yml
    networks:
      - loki

  promtail:
    image: grafana/promtail:2.3.0
    volumes:
      - /opt/loki/config/promtail-config.yml:/etc/promtail/promtail-config.yml
      - /opt/loki/logs/nginx_access.log:/opt/nginx_access.log
    command: -config.file=/etc/promtail/promtail-config.yml
    networks:
      - loki

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    networks:
      - loki

Starting the Loki Environment

Configure Data Source

Head over to Configuration/Data sources and select to add a new Loki Data Source:

Loki - Grafana and Prometheus

The online documentation I found usually used localhost:3100. But since I am accessing from a different system, I have to use the server IP address instead. 192.168.2.111:3000

Now switch to the Explore tab and follow the help to come up with some queries - e.g. {job="varlogs"} - varlogs is the label we assigned to our job in promtail-config.yml:

Loki - Grafana and Prometheus

Running the query will show the NGINX log data that I had Promtail load into Loki:

Loki - Grafana and Prometheus