Teknoloji

Merkezi Loglama ve Gözlemlenebilirlik: VPS’te Loki + Promtail + Grafana ile Sakin Kalan Bir Zihin

Bir Gece Yarısı Log Peşinde: Neden Merkezi Loglama?

Hiç gece yarısı telefondaki bildirimle irkilip, “Sunucu bir anlığına nefesini tuttu” hissini yaşadın mı? Ben yaşadım. SSH ile sunucuya girdim, bir baktım her şey dağınık; Nginx başka yerde fısıldıyor, uygulama kendi köşesinde mırıldanıyor, systemd ise bambaşka bir defter tutmuş. Kimin ne dediğini tek tek dinlemek, uykulu bir kafayla pek şık bir çözüm olmuyor. İşte o an merkezî loglamanın kıymeti insanın içine işliyor. Tek pencereden her şeyi görmek, akışı geriye sarabilmek, “O sırada ne oldu?” sorusunu bir iki sorguda yanıtlayabilmek müthiş bir konfor.

Bu yazıda tam da bu rahatlığı kuracağız. Bir VPS üzerinde Loki, Promtail ve Grafana üçlüsüyle logları toplayacak, saklayacak, arşivleyecek ve uyarılarla kendimizi emniyete alacağız. Uygulamanın sesi, Nginx’in fısıltısı, sistem servislerinin iç çekişi… Hepsi tek yerde, okunaklı, aranabilir ve görselleştirilebilir olacak. Arada küçük tüyolar, hatalara düşmemek için deneyim kırıntıları ve günlük hayattan küçük hikayeler de var. Hadi başlayalım.

Parçaları Sakin Sakin Tanıyalım: Loki, Promtail, Grafana

Mesela şöyle düşün: Mahalleden bir sürü söylenti geliyor ve sen bunları tek bir masada toplayıp anlamlandırmak istiyorsun. Promtail dışarıdaki tüm sesleri kayıt altına alan muhabir. Loki bu kayıtları saklayan ve dönüp dönüp dinleyebildiğin arşiv. Grafana ise bunları renkli grafiklere, hızlı aramalara ve pratik uyarılara dönüştüren bir anlatıcı. Birlikte çalıştıklarında tam bir “olay defteri” kuruyorlar. Loki tarafını tanımak istersen, Loki’nin resmi sayfası iyi bir durak.

Güzel olan şu: Logları “metrik” gibi etiketlerle saklıyor, ama ham metinleri de kaybetmiyor. Yani istersen “son 1 saatte 500 hatayı aşmış mıyız?” diye sayı bakabiliyor, istersen o hataların metnini olduğu gibi okuyabiliyorsun. Bu, kopuk kopuk tutulan dosya loglarından çok daha rahat bir dünya. Üstelik tek bir VPS’te bile gayet keyifle çalışıyor.

Kurulum Stratejisi: Küçük Adımlar, Net Sonuçlar

Ben genelde böyle şeyleri iki yoldan kuruyorum: Ya sistem servisleriyle (systemd) tek tek ayağa kaldırıyorum ya da hepsini ufak bir Docker Compose dosyasında topluyorum. Tek VPS senaryosunda Compose kullanmak pratik oluyor; sürümleri güncellemek, config dosyalarını bir arada tutmak, arıza durumunda kaldırıp yeniden denemek daha rahat. Ama “Docker istemiyorum” diyorsan, aynı yapılandırmayı systemd ile de kurabilirsin. Önemli olan, ilk gün basit başlayıp, ihtiyaç büyüdükçe katman eklemek.

İlk iş, ufak bir çalışma dizini açmak. İçine üç dosya koyacağız: docker-compose.yml, loki-config.yaml ve promtail-config.yml. Böyle düzenli bir başlangıç, ileride neyin nerede olduğunu hatırlamayı kolaylaştırıyor. Sonra tek komutla ayaklanacaklar. Hazırsan, bir taslak görelim.

Docker Compose ile Hızlı Başlangıç

Aşağıdaki dosyayı çalışma dizinine docker-compose.yml adıyla kaydet. Portlar yerel ortam için açık, veriler kalıcı hacimlerde tutuluyor. Versiyon numaraları örnek; istersen güncel etiketleri kullan.

version: '3.9'
services:
  loki:
    image: grafana/loki:2.9.0
    command: -config.file=/etc/loki/local-config.yaml
    volumes:
      - ./loki-config.yaml:/etc/loki/local-config.yaml:ro
      - loki-data:/var/lib/loki
    ports:
      - "3100:3100"
    restart: unless-stopped

  promtail:
    image: grafana/promtail:2.9.0
    command: -config.file=/etc/promtail/config.yml
    volumes:
      - ./promtail-config.yml:/etc/promtail/config.yml:ro
      - /var/log:/var/log
      - /run/log/journal:/run/log/journal:ro
      - /var/lib/promtail:/var/lib/promtail
      - /etc/machine-id:/etc/machine-id:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
    depends_on:
      - loki
    restart: unless-stopped

  grafana:
    image: grafana/grafana:10.4.0
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
    environment:
      - GF_INSTALL_PLUGINS=grafana-piechart-panel
    restart: unless-stopped

volumes:
  loki-data:
  grafana-data:

Bu dosya hazırsa, tek bir komutla ayağa kaldırabilirsin. Klasöre gelip “docker compose up -d” demek yeterli. Sonrasında tarayıcıda 3000’e gidince Grafana seni karşılayacak. İlk şifreyle girip (admin/admin gibi bir şeyse değiştir), sonra Loki’yi veri kaynağı olarak ekleyeceğiz. Ama önce Loki’ye doğru bir dükkan düzeni verelim.

Loki’yi Ayarlamak: Saklama, Arşiv, Retention

Loki’yi küçük bir VPS’te çalıştırırken aşırı ayrıntıya boğmadan, tek kopya, dosya tabanlı bir arşivle başlamak rahat. “Sonraki aşamada S3’e taşıyabilir miyim?” diye soruyorsan, evet; aynı mantık S3 deposuyla da çalışıyor. Aşağıdaki örnek config, dosya sistemi üzerinde boltdb-shipper ile saklama yapıyor, derli toplu bir retention sağlıyor.

# loki-config.yaml
server:
  http_listen_port: 3100
  grpc_listen_port: 9095

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

schema_config:
  configs:
    - from: 2024-01-01
      store: boltdb-shipper
      object_store: filesystem
      schema: v13
      index:
        prefix: index_
        period: 24h

storage_config:
  boltdb_shipper:
    active_index_directory: /var/lib/loki/index
    cache_location: /var/lib/loki/boltdb-cache
    shared_store: filesystem
  filesystem:
    directory: /var/lib/loki/chunks

chunk_store_config:
  max_look_back_period: 168h  # 7 gün geriye bak

table_manager:
  retention_deletes_enabled: true
  retention_period: 168h

compactor:
  working_directory: /var/lib/loki/compactor
  compaction_interval: 5m
  retention_enabled: true

ruler:
  rule_path: /var/lib/loki/rules-temp
  storage:
    type: local
    local:
      directory: /var/lib/loki/rules
  alertmanager_url: http://localhost:9093
  enable_api: true

Burada retention basitçe 7 gün. İlk denemede kısa tutmak iyi; diski, sorgu hızını ve alışkanlıklarını gördükçe uzatabilirsin. Dosya sistemi yerine bir “object store” kullanmak istersen, filesystem kısmını S3 ile değiştirmen yeterli. Yedekleme tarafında işin kolaylaşsın istersen, benim sevdiğim yaklaşımı anlattığım S3 uyumlu uzak yedekleme rehberine göz atabilirsin.

Promtail: VPS’in İçindeki Sesleri Toplamak

Promtail, logların kapısındaki güvenilir muhabir. Neleri toplayacağını söyle, o da titizlikle taşısın. Systemd günlükleri, Nginx access/error logları, uygulama klasöründeki dosyalar, hatta Docker container logları… Hepsini toparlamak mümkün. Önemli olan, etiketleri (labels) sade tutmak. Her isteğin ID’sini etiket yapmak kulağa hoş gelir ama belleği yorar. Ben genelde job, environment, service name, host gibi sabit etiketlerle başlıyorum.

# promtail-config.yml
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /var/lib/promtail/positions.yaml

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

scrape_configs:
  - job_name: journal
    journal:
      max_age: 12h
      labels:
        job: systemd
        host: ${HOSTNAME}
    relabel_configs:
      - source_labels: ['__journal__systemd_unit']
        target_label: unit

  - job_name: nginx
    static_configs:
      - targets: [localhost]
        labels:
          job: nginx
          env: prod
          __path__: /var/log/nginx/*.log

  - job_name: app
    static_configs:
      - targets: [localhost]
        labels:
          job: app
          env: prod
          service: webshop
          __path__: /var/www/app/storage/logs/*.log
    pipeline_stages:
      - regex:
          expression: '^[(?P<level>w+)]s+(?P<msg>.*)$'
      - labels:
          level:
      - output:
          source: msg

Burada systemd günlüklerini ünite adına göre etiketliyoruz, Nginx loglarını tek etikette birleştiriyoruz, uygulama loglarını da seviyeyi (INFO, ERROR gibi) ayıklayarak zenginleştiriyoruz. Böyle olunca Grafana’dan “son 15 dakikadaki ERROR sayısı 50’yi geçti mi?” gibi alarm kurmak kolay. Promtail’in boru hattı aşamalarını merak edersen, Promtail aşamaları belgeleri hoş bir anlatımla özetliyor.

Grafana: Logları Gözle Okumaktan Gözlemlenebilirliğe

Grafana açıldığında, önce “Data Sources” menüsünden Loki’yi ekle. URL olarak http://loki:3100 yazman yeterli, Compose ağı içinde isimle erişilecek. Sonra “Explore” bölümüne girip ufak bir deneme yapalım. Mesela son 5 dakikada Nginx’te 500 hatası var mı diye soralım. LogQL dili tam bu iş için var; sade, niyetini belli eden bir dille konuşuyor.

{job="nginx"} |= " 500 "

Bu sorgu, Nginx loglarında 500 geçen satırları getirir. Saymak istersen bir adım daha atarsın, “rate” gibi metrik benzeri operatörleri devreye sokarsın. Örnek olsun:

sum by (job) (rate({job="nginx"} |= " 500 " [5m]))

Biraz daha tatlı bir örnek: Uygulama loglarında ERROR’ları seviyeye göre sayalım, panellerde ısınma varsa kırmızıya dönsün. Bunun için önce Explore’da oynar, sonra panelleri kaydedersin. LogQL’i tanımak istersen, LogQL ile sorgulama sayfası kısa örneklerle iyi bir eşlikçi.

Uyarılar: Hata Sesini Zamanında Duymak

Uyarı dediğin, bardak devrilmeden önce “Masada bir sallantı var” diyen iç ses. Grafana’nın yeni nesil alarm sistemiyle log tabanlı kurallar oluşturmak epey kolay. Örneğin, “Son 10 dakikada ERROR sayısı 100’ü aşarsa Slack’e haber ver” gibi bir kural yazabiliriz. Explore’da çalışan sorgunu bir panele koy, panelden Alert sekmesine geç, eşiği belirle, bir iletişim noktası (Slack, e‑posta) seç ve kaydet.

Bazen metin aramak yetmez; belirli bir servis adının hata hızını da izlemek istersin. O zaman etiketleri kullanarak seçici olursun. Diyelim ki “webshop” servisi için ERROR akışını sayalım:

sum by (service) (rate({job="app", service="webshop", level="ERROR"}[10m]))

Bu değer 0.2’yi aşarsa alarm ver, hızlıca bak. Paneldeki eşiği düşük tutup sonra kademeli yükseltmek pratik oluyor. Bir de sevdiğim küçük alışkanlık: Uyarı metnine, bakılacak sorgunun ve ilgili dashboard’un bağlantısını eklemek. Gece uykusu bölündüğünde, “Ben nereye bakıyordum?” derdini azaltıyor.

Arşiv ve Saklama: Ne Kadar, Nerede, Nasıl?

Logun ömrü biraz da ihtiyacınla alakalı. Geliştirme aşamasında 7 gün yetebilir, üretimde belki 30 güne uzatırsın. Loki’nin retention ayarı burada anahtar. Disk daralıyorsa önce gereksiz etiketleri azalt, sonra saklama süresini toparla. S3 gibi bir object store’a geçmek istersen de configte “object_store” kısmını S3’e çevirip erişim bilgilerini eklemen kafi. Günün birinde “Ben bu arşivi dışarı da alayım” dersen, log klasörlerinin yedeğini planlı bir boru hattına koymak iyi fikir. Ben bunun için zamanında anlattığım S3 uyumlu uzak yedekleme pratiğini seviyorum; şifreleme, sürümleme ve saklama politikası bir arada yürüyor.

Arşiv demişken, küçük ama etkili bir alışkanlık: Rotasyonlarını ve retention’ı çakıştırma. Uygulama kendi içinde çok hızlı rotasyon yapıyorsa Promtail’in pozisyon dosyası şaşırabilir. Rotasyon aralıklarını biraz rahat bırakmak, Promtail’in acele etmeden kuyruğu taşımasına fırsat verir.

Güvenlik ve Erişim: Sadece İhtiyacı Olan Görsün

Grafana’yı 3000’den, Loki’yi 3100’den açtık, güzel. Ama bu portları herkese açık bırakmak istemeyebilirsin. Ben çoğu zaman Nginx’in arkasına alıp basit bir kimlik doğrulama ekliyorum. İstersen mTLS, istersen IP kısıtlaması, istersen temel kimlik doğrulama… Küçük bir örnek, Grafana için:

server {
  listen 443 ssl;
  server_name logs.example.com;

  ssl_certificate /etc/ssl/certs/fullchain.pem;
  ssl_certificate_key /etc/ssl/private/privkey.pem;

  auth_basic "Logs";
  auth_basic_user_file /etc/nginx/.htpasswd;

  location / {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://127.0.0.1:3000;
  }
}

Bu örnekle temel bir koruma sağlarsın. Eğer websiteni zaten Nginx ve modern şifreleme ile güçlendiriyorsan, oradaki prensipleri burada da uygula. Geliştirici ortamlarında ise şifreyi bir ekip kasasında saklamak, erişimi gerektiğinde açıp kapatmak işleri düzenli tutuyor. Uygulama loglarına gereğinden fazla detay basmamak da güvenlikte ilk adım; kimlik bilgileri veya kişisel veriler loga düşmesin.

Sahadan Notlar: Etiket Disiplini, Bellek ve Sorgu Hızı

Uzun vadede en çok fayda sağlayan alışkanlık, etiket disiplini. Her isteğe özel, sürekli değişen değerleri etiket yapmamak gerekiyor. Request ID, kullanıcı ID, token gibi değerler metin içinde kalsın; filtrelerken “|= “.user_id=123″” gibi metin aramasına güven. Etiketlerde; job, service, env, host, level gibi sakin değerleri tercih et. Böylece Loki’nin kartopu gibi büyümesini engellersin, sorgular da seri akar.

İkincisi, sorgu pencerelerini akıllı seçmek. Çok geniş bir zaman aralığında “her şeyi” istemek zorlar. Önce yakın bir aralığı tarayıp ipucunu bul, sonra geriye genişle. Bir de unutma: Çok gürültülü loglar varsa, uygulama tarafında seviyeyi ayarlamak ve gereksiz satırları azaltmak çift taraflı bir kazanım.

Uygulamadan Örnekler: Nginx, Node.js, systemd

Nginx’te access ve error dosyaları klasik. Access loglarında “request_time” ve “upstream_status” gibi alanlar varsa, metin aramalarıyla performans kokusu alan sorgular yazabilirsin. Uygulamada Node.js kullanıyorsan, anlamlı ve tek satırlık log formatı işleri çok kolaylaştırır. Nasıl canlıya alırken panik yapmadan derli toplu bir ortam kuracağını anlattığım Node.js’i canlıya alırken PM2/systemd ve Nginx notları, log düzeni için de ilham verebilir.

Systemd tarafında ise servis isimlerine göre ayırmak, özellikle “neden yeniden başladı?” soru işaretini çözer. Journal’dan ünite adına etiketleme yapınca, hangi servis ne zaman inlemiş görürsün. Promtail burada hayati; positions dosyasını korur, koptuğu yerden devam eder, panik yok.

Gözlemlenebilirlik Haritasını Genişletmek: Metrikler ve Uptime

Loglar tek başına yetmez, doğru. Ama iyi bir başlangıç. Üzerine metrikleri ve uptime kontrollerini koyduğunda tablo tamamlanıyor. Ben genelde Loki ile logları oturttuktan sonra, aynı Grafana içinde Prometheus ve küçük bir uptime izleyici ekliyorum. Bu konuda “ilk taşları nasıl dizerim?” dersen, VPS izleme ve alarm kurulumuna dair rehber hoş bir yoldaş olur. Loglardaki ERROR artarken CPU, bellek ve yanıt süresi ne yapıyor, birlikte bakınca hikaye tamamlanıyor.

Değişiklikleri Güvenle Yaymak: Konfigürasyon, Sürümleme, Geri Alma

Günün sonuna doğru ufak bir Promtail kuralı ekledin diyelim. Canlıda denemek istiyorsun ama “ya bir şeyi bozarsam” çekincesi hep var. O noktada küçük bir CI/CD hattı kurtarıcı. Konfigürasyon dosyalarını versiyon kontrolüne al, bir “staging” VPS’te dene, sonra üretime güvenle at. Benzer bir yaklaşımı adım adım anlattığım VPS’e sıfır kesinti CI/CD yazısı burada harika çalışıyor. Bir de küçük öneri: Loki ve Promtail’in sürümlerini birlikte güncelle, büyük atlamalarda önce test et.

Sorun Giderme: Bağlantılar, Roll-up’lar, Gürültü

Olur ya, Promtail gönderiyor ama Loki’de görünmüyor. İlk kontrol adresi Promtail arayüzü; 9080 portundan “targets” sayfasına bak, durum “ready” mi? Sonra firewall veya reverse proxy araya giriyor mu diye bakarsın. Görünüyor ama yavaşsa, sorgu penceresini daralt, gereksiz etiket var mı diye incele. Loglar çok gürültülü ise, uygulamada seviyeyi INFO yerine WARN’a çekmek bazen en kestirme çözüm. Bir de kompaktörün çalıştığından emin ol; arşivi toparlarken o görevli.

Grafana’da panel boş dönüyorsa, zaman aralığı ayarı ve sorgu ifadesine yeniden göz at. LogQL basit ama küçük tırnak ve eşittir oyunları önemli. Emin olamadığında Explore ekranında adım adım ilerlemek en temiz yol.

Kapanış: Derli Toplu Log, Sakin Operasyon

Merkezî loglama, ilk bakışta bir “nice to have” gibi duruyor. Oysa gece yarısı bir hata patlayınca, sabah trafiği artınca ya da ekip büyüyüp el değişmeye başlayınca, değerini çok net görüyorsun. Loki + Promtail + Grafana üçlüsü, tek VPS’te bile hafif adımlarla kurulup günlük hayata uyumlanan bir sistem. Üstelik büyümek istediğinde, aynı alışkanlıkları daha geniş bir oyuncağa taşıyorsun.

Başlangıç için küçük önerilerimi toparlayayım. Etiketleri sade tut; job, env, service, host sana yeter. Retention’ı kademeli artır, diski ve sorgu süresini izleyerek karar ver. Uyarıları erken kur, eşikleri zamanla finetune et. Değişiklikleri sürüm kontrolünde sakla, küçük adımlarla yayımla, bir şey olursa geri alması kolay olsun. Ve unutmadan, uygulamayı canlıya alırken log formatını basit ve tek satırlı tutmak, ileride sana dakikalar kazandırır; nitekim bu konuda paylaştığım canlıya alma notları log düzenini sadeleştirmeye de göz kırpıyor.

Umarım bu yolculuk sana iyi gelmiştir. Bir sonraki küçük krizde elinin altındaki bu düzenle nefes alacağını bilmek güzel. Sorun, deneyim paylaş, kendi mutfağında işe yarayan minik teknikleri anlat; hep birlikte daha sakin bir operasyon kültürü kuruyoruz. Görüşmek üzere.

Sıkça Sorulan Sorular

Evet, gayet rahat. Kaynakları çok kısıtlı değilse tek VPS’te başlamak iyi bir seçim. Etiketleri sade tut, retention’ı makul ayarla, gerekiyorsa sonra S3 gibi bir depoya taşı.

Uygulamada gerçekten ihtiyacın olanları INFO/ERROR gibi net seviyelere indir. Gereksiz debug satırlarını kapat, kritik olayları kısa ve tek satır yaz. Böylece hem sorgular hızlanır hem disk şişmez.

Önce küçükten başla; e‑posta veya Slack yeter. Tek bir panodaki önemli paneller için eşik belirle, geceyi bölecek kuralları dikkatli ayarla. Zamanla seviyeleri ve kanalları kademeli genişlet.