Loki ile Hafif Log Yönetimi: Grafana Entegrasyonu
Klasik ELK stack kurduysanız ve ardından sunucunun RAM’ini erittiğini gördüyseniz, Loki’nin neden bu kadar popüler hale geldiğini anlamak zor olmayacak. Grafana Labs tarafından geliştirilen Loki, “Prometheus ama loglar için” felsefesiyle tasarlanmış, hafif ve ölçeklenebilir bir log toplama sistemidir. Elasticsearch gibi logların içeriğini tam metin indekslemek yerine, sadece metadata etiketlerini indeksler. Bu yaklaşım disk alanı ve bellek kullanımını dramatik biçimde düşürür.
Bu yazıda bare metal bir Ubuntu sunucudan başlayarak Loki, Promtail ve Grafana’yı ayağa kaldıracağız, gerçek dünya senaryolarında nasıl sorgu yazılır göreceğiz ve production ortamında dikkat edilmesi gereken noktaları ele alacağız.
Loki’nin Mimarisi ve ELK’dan Farkı
Loki üç temel bileşenden oluşur:
- Loki: Log verilerini depolayan ve sorgulayan ana servis
- Promtail: Sunuculardan log toplayan agent (Prometheus’un node_exporter’ı gibi düşünebilirsiniz)
- Grafana: Görselleştirme ve sorgulama arayüzü
Elasticsearch log satırlarının her kelimesini indeksler, bu yüzden arama hızlıdır ama kaynak tüketimi yüksektir. Loki ise log satırlarını ham halde saklar ve sadece etiketleri (labels) indeksler. {app="nginx", env="production"} gibi etiketlerle log akışlarını filtreler, içerik araması yaparken ise grep benzeri bir yaklaşım kullanır. 10 GB log için Elasticsearch 2-3 GB RAM isterken Loki aynı veri için 200-300 MB ile idare edebilir.
Kurulum: Ubuntu 22.04 Üzerinde Loki
Önce gerekli dizinleri ve kullanıcıyı oluşturalım:
# Loki için sistem kullanıcısı oluştur
sudo useradd --system --no-create-home --shell /bin/false loki
# Çalışma dizinlerini oluştur
sudo mkdir -p /opt/loki /etc/loki /var/lib/loki /var/log/loki
# Loki binary'sini indir (en güncel sürüm için GitHub releases kontrol edin)
cd /tmp
wget https://github.com/grafana/loki/releases/download/v2.9.4/loki-linux-amd64.zip
unzip loki-linux-amd64.zip
sudo mv loki-linux-amd64 /usr/local/bin/loki
sudo chmod +x /usr/local/bin/loki
# Dizin izinlerini ayarla
sudo chown -R loki:loki /opt/loki /var/lib/loki /var/log/loki
Şimdi Loki konfigürasyon dosyasını oluşturalım. Bu konfigürasyon production için makul bir başlangıç noktasıdır:
sudo nano /etc/loki/loki-config.yaml
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: warn
common:
instance_addr: 127.0.0.1
path_prefix: /var/lib/loki
storage:
filesystem:
chunks_directory: /var/lib/loki/chunks
rules_directory: /var/lib/loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
query_range:
results_cache:
cache:
embedded_cache:
enabled: true
max_size_mb: 100
schema_config:
configs:
- from: 2024-01-01
store: tsdb
object_store: filesystem
schema: v12
index:
prefix: index_
period: 24h
ruler:
alertmanager_url: http://localhost:9093
limits_config:
reject_old_samples: true
reject_old_samples_max_age: 168h
ingestion_rate_mb: 16
ingestion_burst_size_mb: 32
compactor:
working_directory: /var/lib/loki/compactor
shared_store: filesystem
retention_enabled: true
retention_delete_delay: 2h
chunk_store_config:
max_look_back_period: 0s
table_manager:
retention_deletes_enabled: true
retention_period: 720h
Systemd servis dosyasını oluşturalım:
sudo nano /etc/systemd/system/loki.service
[Unit]
Description=Loki Log Aggregation System
After=network.target
[Service]
Type=simple
User=loki
Group=loki
ExecStart=/usr/local/bin/loki -config.file=/etc/loki/loki-config.yaml
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
SyslogIdentifier=loki
# Güvenlik önlemleri
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ProtectHome=yes
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable loki
sudo systemctl start loki
sudo systemctl status loki
# Loki'nin ayakta olduğunu doğrula
curl http://localhost:3100/ready
Promtail Kurulumu ve Konfigürasyonu
Promtail, log dosyalarını izleyip Loki’ye gönderen agent’tır. Her sunucuya kurulması gerekir:
# Promtail'i indir
cd /tmp
wget https://github.com/grafana/loki/releases/download/v2.9.4/promtail-linux-amd64.zip
unzip promtail-linux-amd64.zip
sudo mv promtail-linux-amd64 /usr/local/bin/promtail
sudo chmod +x /usr/local/bin/promtail
# Kullanıcı ve dizin
sudo useradd --system --no-create-home --shell /bin/false promtail
sudo mkdir -p /etc/promtail /var/lib/promtail
sudo usermod -a -G adm promtail # Sistem loglarını okuyabilmesi için
sudo chown -R promtail:promtail /var/lib/promtail
Promtail konfigürasyonu birçok sysadmin’in zaman harcadığı yer. Aşağıdaki konfigürasyon nginx, sistem logları ve uygulama loglarını kapsar:
sudo nano /etc/promtail/promtail-config.yaml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /var/lib/promtail/positions.yaml
clients:
- url: http://localhost:3100/loki/api/v1/push
tenant_id: default
backoff_config:
min_period: 500ms
max_period: 5m
max_retries: 10
timeout: 10s
scrape_configs:
# Sistem logları
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
host: prod-web-01
env: production
__path__: /var/log/{syslog,auth.log,kern.log}
# Nginx access logları
- job_name: nginx_access
static_configs:
- targets:
- localhost
labels:
job: nginx
host: prod-web-01
env: production
log_type: access
__path__: /var/log/nginx/access.log
pipeline_stages:
- regex:
expression: '^(?P<remote_addr>S+) S+ S+ [(?P<time_local>[^]]+)] "(?P<method>S+) (?P<path>S+) S+" (?P<status>d+) (?P<bytes_sent>d+)'
- labels:
method:
status:
- metrics:
http_requests_total:
type: Counter
description: "Toplam HTTP istek sayısı"
source: status
config:
action: inc
# Nginx error logları
- job_name: nginx_error
static_configs:
- targets:
- localhost
labels:
job: nginx
host: prod-web-01
env: production
log_type: error
__path__: /var/log/nginx/error.log
pipeline_stages:
- regex:
expression: '(?P<level>emerg|alert|crit|error|warn|notice|info|debug)'
- labels:
level:
# Uygulama logları (örnek: Python/Node.js uygulaması)
- job_name: app_logs
static_configs:
- targets:
- localhost
labels:
job: myapp
host: prod-web-01
env: production
__path__: /var/log/myapp/*.log
pipeline_stages:
- multiline:
firstline: '^d{4}-d{2}-d{2}'
max_wait_time: 3s
- regex:
expression: '^(?P<timestamp>d{4}-d{2}-d{2} d{2}:d{2}:d{2}) (?P<level>DEBUG|INFO|WARNING|ERROR|CRITICAL)'
- labels:
level:
- timestamp:
source: timestamp
format: '2006-01-02 15:04:05'
Multiline konfigürasyonu özellikle Java stack trace’leri veya Python traceback’leri için kritik. Bunlar olmadan her satır ayrı log eventi olarak görünür ve analiz imkansızlaşır.
# Promtail servisini oluştur ve başlat
sudo nano /etc/systemd/system/promtail.service
[Unit]
Description=Promtail Log Shipper
After=network.target loki.service
[Service]
Type=simple
User=promtail
Group=promtail
ExecStart=/usr/local/bin/promtail -config.file=/etc/promtail/promtail-config.yaml
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable promtail
sudo systemctl start promtail
# Promtail'in logları gönderip göndermediğini kontrol et
curl http://localhost:9080/metrics | grep promtail_sent_entries_total
Grafana Kurulumu ve Loki Entegrasyonu
# Grafana APT repository ekle
sudo apt-get install -y apt-transport-https software-properties-common
wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key
echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" |
sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install -y grafana
sudo systemctl daemon-reload
sudo systemctl enable grafana-server
sudo systemctl start grafana-server
Grafana web arayüzüne http://sunucu-ip:3000 adresinden erişin. Default kullanıcı admin, şifre admin. İlk girişte şifre değiştirmenizi isteyecek, bunu atlamayın.
Loki data source ekleme adımları:
- Sol menüden “Connections” > “Data sources” > “Add data source”
- “Loki” seçin
- URL kısmına
http://localhost:3100yazın - “Save & test” butonuna basın
- “Data source connected and labels found” mesajını görmelisiniz
LogQL ile Gerçek Dünya Sorguları
LogQL, Loki’nin sorgu dilidir. PromQL’e benzer bir sözdizimi vardır. Grafana’da “Explore” bölümünden bu sorguları deneyebilirsiniz.
Temel log akışı görüntüleme:
# Tüm nginx logları
{job="nginx"}
# Sadece production ortamındaki hata logları
{env="production", log_type="error"}
# Belirli host'un auth logları
{job="varlogs", host="prod-web-01"} |= "Failed password"
SSH brute force tespiti:
# Son 15 dakikada başarısız SSH girişimlerinin sayısı
count_over_time(
{job="varlogs"}
|= "Failed password"
| regexp `from (?P<ip>d+.d+.d+.d+)`
[15m]
)
# IP bazında gruplama ile
sum by (ip) (
count_over_time(
{job="varlogs"}
|= "Failed password"
| regexp `from (?P<ip>d+.d+.d+.d+)`
[5m]
)
)
Nginx 5xx error oranı:
# HTTP 500 hatalarının son 5 dakikadaki sayısı
sum(count_over_time({job="nginx", log_type="access"} |= "" 5" [5m]))
# 5xx oranı (yüzde olarak)
sum(count_over_time({job="nginx", log_type="access"} | status =~ "5.." [5m])) /
sum(count_over_time({job="nginx", log_type="access"} [5m])) * 100
Uygulama hata takibi:
# ERROR ve CRITICAL logları filtrele ve say
sum by (level) (
count_over_time(
{job="myapp"}
| label_format level=level
| level =~ "ERROR|CRITICAL"
[5m]
)
)
# Belirli bir hata mesajını içeren loglar
{job="myapp"}
|= "Database connection"
| json
| line_format "{{.timestamp}} [{{.level}}] {{.message}}"
Alerting: Kritik Durumlar İçin Uyarı Kuralları
Grafana’nın Alerting özelliğini kullanarak Loki sorgularına dayalı uyarılar oluşturabilirsiniz. Alerting > Alert rules > Create alert rule yolunu izleyin.
Disk dolmadan önce uyarı almak için alert rule konfigürasyon örneği:
# /etc/loki/rules/alerts.yaml
groups:
- name: log_alerts
rules:
- alert: HighErrorRate
expr: |
sum(rate({job="myapp"} |= "ERROR" [5m])) > 10
for: 2m
labels:
severity: warning
team: backend
annotations:
summary: "Uygulama hata oranı yüksek"
description: "Son 5 dakikada dakika başına 10'dan fazla ERROR logu var"
- alert: SSHBruteForce
expr: |
sum(count_over_time({job="varlogs"} |= "Failed password" [5m])) > 50
for: 1m
labels:
severity: critical
team: security
annotations:
summary: "Olası SSH brute force saldırısı"
description: "Son 5 dakikada 50'den fazla başarısız SSH girişimi tespit edildi"
- alert: NginxHighLatency
expr: |
count_over_time({job="nginx", log_type="error"} [5m]) > 100
for: 5m
labels:
severity: warning
annotations:
summary: "Nginx hata sayısı yüksek"
Loki konfigürasyonuna ruler bölümünü ekleyin:
# /etc/loki/loki-config.yaml dosyasına ekle
ruler:
storage:
type: local
local:
directory: /var/lib/loki/rules
rule_path: /var/lib/loki/rules_tmp
alertmanager_url: http://localhost:9093
ring:
kvstore:
store: inmemory
enable_api: true
enable_alertmanager_v2: true
Çok Sunuculu Ortamda Promtail Yapılandırması
10 sunucunuz varsa her birine Promtail kurmanız ve her birinin Loki’ye göndermesi gerekir. Ansible ile bunu otomatikleştirmek mantıklıdır:
# Ansible ile Promtail kurulumu için basit script
# promtail_setup.sh - her sunucuda çalıştır
#!/bin/bash
LOKI_SERVER="10.0.1.100" # Merkezi Loki sunucunuzun IP'si
HOST_NAME=$(hostname)
ENVIRONMENT=${1:-"production"} # Script argümanı olarak alın
cat > /etc/promtail/promtail-config.yaml << EOF
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /var/lib/promtail/positions.yaml
clients:
- url: http://${LOKI_SERVER}:3100/loki/api/v1/push
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
host: ${HOST_NAME}
env: ${ENVIRONMENT}
__path__: /var/log/{syslog,auth.log}
- job_name: nginx
static_configs:
- targets:
- localhost
labels:
job: nginx
host: ${HOST_NAME}
env: ${ENVIRONMENT}
__path__: /var/log/nginx/*.log
EOF
systemctl restart promtail
echo "Promtail yapılandırması tamamlandı: ${HOST_NAME} -> ${LOKI_SERVER}"
Performans Optimizasyonu ve Production Dikkat Noktaları
Label kardinalitesi: Loki’nin en sık düşülen tuzağı budur. Her benzersiz label kombinasyonu ayrı bir log akışı oluşturur. Kullanıcı ID’sini veya IP adresini label olarak eklerseniz, binlerce farklı akış oluşur ve performans çöker. Label olarak kullanılacak değerler az sayıda ve sabit olmalıdır.
Yanlış kullanım:
# BU YAPMAYIN - yüksek kardinalite
labels:
user_id: "12345"
client_ip: "192.168.1.100"
request_id: "abc-def-123"
Doğru kullanım:
# DOĞRU - düşük kardinalite
labels:
env: "production"
app: "api-server"
host: "web-01"
level: "error"
Disk yönetimi için retention politikası:
# Loki konfigürasyonunda retention ayarları
limits_config:
retention_period: 720h # 30 gün
compactor:
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
Bellek kullanımını izleme:
# Loki memory kullanımını kontrol et
curl -s http://localhost:3100/metrics | grep -E "^go_memstats_(heap_alloc|sys)_bytes"
# Aktif stream sayısını kontrol et
curl -s http://localhost:3100/metrics | grep loki_ingester_streams_created_total
Firewall kuralları – Loki dışarıya açılmamalı:
# Loki sadece local ve trusted network'ten erişilebilir olsun
sudo ufw allow from 10.0.0.0/8 to any port 3100
sudo ufw deny 3100
sudo ufw allow from 10.0.0.0/8 to any port 3101
# Grafana dışarıya açık olabilir ama Loki kesinlikle hayır
sudo ufw allow 3000/tcp
Grafana Dashboard Oluşturma
Grafana’da “Dashboards > New > New Dashboard” ile yeni dashboard oluşturun. Nginx monitoring için tipik panel sorguları:
# Panel 1: Toplam istek hacmi (son 1 saat)
sum(count_over_time({job="nginx", log_type="access"} [1h]))
# Panel 2: Hata dağılımı (pie chart için)
sum by (status) (
count_over_time(
{job="nginx", log_type="access"}
| regexp `" (?P<status>d+) `
[5m]
)
)
# Panel 3: En çok hata alan path'ler
topk(10,
sum by (path) (
count_over_time(
{job="nginx", log_type="access"}
| regexp `"(?:GET|POST|PUT|DELETE) (?P<path>S+).*" 5dd`
[1h]
)
)
)
Grafana’nın built-in “Logs” panel tipini kullanın, tablo yerine. Bu panel otomatik olarak log seviyelerini renklendirir ve filtreleme imkanı sunar.
Sorun Giderme
Promtail loglar göndermiyorsa kontrol listesi:
# Promtail'in log dosyalarını okuyabildiğini kontrol et
sudo -u promtail cat /var/log/nginx/access.log | head -5
# Positions dosyasını kontrol et
cat /var/lib/promtail/positions.yaml
# Promtail debug modunda çalıştır
sudo promtail -config.file=/etc/promtail/promtail-config.yaml -log.level=debug 2>&1 | head -50
# Loki'ye erişim kontrolü
curl -v http://loki-server:3100/ready
# Loki'deki mevcut label'ları listele
curl http://localhost:3100/loki/api/v1/labels
# Belirli bir label için values
curl "http://localhost:3100/loki/api/v1/label/job/values"
Sonuç
Loki, özellikle kaynak kısıtlı ortamlarda veya halihazırda Grafana kullanan ekiplerde son derece pratik bir çözüm. ELK stack’in tam metin indeksleme gücünü gerektirmiyorsanız ve log analizi ihtiyaçlarınız label bazlı filtreleme ile karşılanabiliyorsa, Loki hafif yapısıyla ciddi avantaj sağlar.
Kurulum sürecinde en çok dikkat edilmesi gereken nokta label tasarımı. Kardinaliteyi düşük tutmak performans açısından kritik. Buna ek olarak, production’da retention politikasını ve disk kullanımını düzenli izlemek gerekiyor. logcli komut satırı aracını da keşfetmenizi öneririm, SSH üzerinden hızlı log sorgulaması için çok pratik.
Bir sonraki adım olarak Loki’yi Prometheus ile birlikte kullanmak, yani metrikler ve logları aynı Grafana dashboard’unda ilişkilendirmek, incident response sürecini dramatik biçimde hızlandırıyor. Bir alert tetiklendiğinde hem metriği hem de ilgili log satırlarını aynı ekranda görmek, sorunun kaynağına çok daha hızlı ulaşmanızı sağlıyor.
