Docker & DevOps

    Loki ile Merkezi Log Toplama

    Sunucu ve konteyner loglarını tek yerde toplayıp Grafana'dan sorgulamanın yolu.

    11 dk okuma Güncellendi: 25 Ağustos 2026

    Üç sunucun varken ssh ile bağlanıp tail -f çekmek işini görür. Yedincide artık hangi makinede olduğunu unutursun, onuncuda bir konteyner silindiğinde logları da onunla gider ve hata anını bir daha asla göremezsin. Loki ile merkezi log toplama tam olarak bu noktada devreye girer: tüm sunucuların ve konteynerlerin log satırlarını tek bir yerde toplar, Grafana üzerinden sorgulanabilir hale getirir ve metriklerinle aynı zaman ekseninde gösterir.

    Loki'yi ilgi çekici yapan şey, klasik log yığınlarından farklı bir tasarım tercihi yapmış olmasıdır: log içeriğini indekslemez, yalnızca etiketleri indeksler. Bu tek karar, disk ve bellek ihtiyacını Elasticsearch tabanlı kurulumlara kıyasla ciddi biçimde düşürür ama etiket tasarımını da kritik hale getirir. Bu rehberde Loki'nin nasıl çalıştığını, Promtail ile log toplamayı, etiketleri doğru seçmeyi, LogQL ile sorgu yazmayı, Grafana'da logları metriklerle hizalamayı ve saklama süresini planlamayı anlatacağım.

    Loki Neden Farklı Çalışır#

    Geleneksel log sistemleri her satırın içindeki her kelimeyi ters indekse yazar. Bu, "şu kelimeyi içeren tüm satırları bul" sorgusunu çok hızlı yapar ama karşılığında ciddi bir bedel ister: indeks çoğu zaman ham logdan büyük olur, bellek tüketimi yüksektir ve kümeyi ayakta tutmak başlı başına bir iştir. Loki bunun tersini yapar. Yalnızca etiketleri (job, host, container, level gibi) indeksler; log satırının kendisi sıkıştırılıp nesne olarak saklanır ve sorgu anında taranır.

    Bu tasarımın pratik sonucu şudur: Loki'de sorgu yaparken önce daraltmak zorundasın. {host="web-01", job="nginx"} gibi bir etiket seçicisiyle veri kümesini küçültür, sonra metin filtresi uygularsın. Doğrudan "tüm loglarda şu kelimeyi ara" demek, Loki'yi terabaytlarca sıkıştırılmış veriyi açmaya zorlar ve sorgu ya çok yavaş çalışır ya da zaman aşımına uğrar. Alışması bir gün sürer, ama bir kez oturduğunda kaynak tüketimi farkı çarpıcıdır.

    Yığın üç parçadan oluşur:

    BileşenGöreviNerede çalışır
    PromtailLog dosyalarını okur, etiketler, Loki'ye iterHer sunucuda (ajan)
    LokiLog parçalarını saklar, LogQL sorgularını çalıştırırMerkezi tek yerde
    GrafanaSorgu arayüzü ve görselleştirmeMerkezi tek yerde

    Promtail'in Prometheus'a çok benzeyen bir yapılandırma dili vardır — hizmet keşfi, relabel_configs, aynı etiket mantığı. Prometheus tarafına aşinaysan Promtail'i öğrenmen yarım saat sürer; değilsen önce Prometheus kurulumu yazısındaki etiket bölümüne göz atmanı öneririm.

    Loki ve Promtail Kurulumu#

    Tek sunuculuk bir başlangıç için Loki'nin dosya sistemi tabanlı depolama modu fazlasıyla yeterlidir; nesne depolamaya ancak veri hacmi büyüdüğünde geçersin.

    # docker-compose.yml
    services:
      loki:
        image: grafana/loki:latest
        container_name: loki
        restart: unless-stopped
        ports:
          - "127.0.0.1:3100:3100"
        volumes:
          - ./loki-config.yml:/etc/loki/local-config.yaml:ro
          - loki-data:/loki
        command: -config.file=/etc/loki/local-config.yaml
    
      promtail:
        image: grafana/promtail:latest
        container_name: promtail
        restart: unless-stopped
        volumes:
          - ./promtail-config.yml:/etc/promtail/config.yml:ro
          - /var/log:/var/log:ro                      # sistem logları
          - /var/lib/docker/containers:/var/lib/docker/containers:ro  # konteyner logları
          - promtail-positions:/tmp                   # okuma konumu kalıcı olmalı
        command: -config.file=/etc/promtail/config.yml
    
    volumes:
      loki-data:
      promtail-positions:
    

    promtail-positions birimini atlamak, ilk bakışta zararsız görünen ama pahalıya patlayan bir hatadır: Promtail her dosyayı nereye kadar okuduğunu bu dizindeki positions.yaml dosyasında tutar. Kalıcı değilse konteyner her yeniden başladığında tüm log dosyalarını baştan okur ve Loki'ye günlerce eski satırları tekrar iter. Loki bunları too far behind diye reddeder, sen de neden log gelmediğini ararsın.

    Loki'nin asgari yapılandırması şöyle görünür:

    # loki-config.yml
    auth_enabled: false
    
    server:
      http_listen_port: 3100
    
    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
    
    schema_config:
      configs:
        - from: 2024-01-01
          store: tsdb
          object_store: filesystem
          schema: v13
          index:
            prefix: index_
            period: 24h
    
    limits_config:
      # 30 günden eski logları sil
      retention_period: 720h
      # Tek kiracıda saatlik alım tavanı (MB/s)
      ingestion_rate_mb: 8
      ingestion_burst_size_mb: 16
    
    compactor:
      working_directory: /loki/compactor
      retention_enabled: true
      delete_request_store: filesystem
    

    auth_enabled: false ayarı Loki'yi kimlik doğrulamasız açar; bu yüzden portu 127.0.0.1 ile sınırladık. Loki'yi farklı sunuculardan gelen Promtail'lere açacaksan mutlaka ters vekil arkasına alıp temel kimlik doğrulaması ekle.

    Promtail Yapılandırması ve Etiket Tasarımı#

    Promtail'in işi üç adımdan ibarettir: hangi dosyaları okuyacağını bul, her satıra etiket ekle, Loki'ye gönder. Ama ikinci adımı yanlış yaparsan Loki'yi dizlerinin üstüne çökertirsin, o yüzden buraya dikkat.

    # promtail-config.yml
    server:
      http_listen_port: 9080
    
    positions:
      filename: /tmp/positions.yaml
    
    clients:
      - url: http://loki:3100/loki/api/v1/push
    
    scrape_configs:
      # 1) Klasik sistem logları
      - job_name: sistem
        static_configs:
          - targets: ['localhost']
            labels:
              job: syslog
              host: web-01
              __path__: /var/log/*.log
    
      # 2) Nginx erişim logları — seviye çıkarımı ile
      - job_name: nginx
        static_configs:
          - targets: ['localhost']
            labels:
              job: nginx
              host: web-01
              __path__: /var/log/nginx/*.log
        pipeline_stages:
          # HTTP durum kodunu yakala ve seviyeye çevir
          - regex:
              expression: '\s(?P<durum>[45]\d{2})\s'
          - labels:
              durum:
    
      # 3) Docker konteyner logları — otomatik keşif
      - 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_log_stream']
            target_label: 'stream'
    

    Etiket tasarımının altın kuralı şudur: etiket değerleri sınırlı sayıda olmalı. Her benzersiz etiket kombinasyonu Loki'de ayrı bir "stream" yaratır ve akış sayısı patladığında hem alım hem sorgu çöker. Buna kardinalite patlaması denir ve Loki'de yaşanan sorunların büyük çoğunluğunun kaynağıdır.

    Etiket olarak uygunEtiket olarak felaket
    job, host, containerrequest_id, trace_id
    env, namespaceuser_id, session_id
    level, streamip, url (parametreli)
    durum (5xx/4xx grubu)tam yanıt süresi değeri

    Kural pratikte şöyle işler: bir alanın alabileceği değer sayısı yüzlerle ifade ediliyorsa etiket yapma, log satırının içinde bırak ve sorgu anında filtrele. Kullanıcı kimliği etiket yapılırsa on bin kullanıcıda on bin akış oluşur; aynı bilgi satır içinde kalırsa |= "user_id=1234" filtresiyle yine bulursun ve hiçbir maliyeti olmaz.

    LogQL ile Sorgulama#

    LogQL, PromQL'e kasıtlı olarak benzeyen bir sorgu dilidir ve iki bölümden oluşur: etiket seçici (zorunlu) ve satır filtreleri (isteğe bağlı). Zincirleme mantığı soldan sağa çalışır; her adım veri kümesini daha da daraltır.

    # Tek işin tüm logları
    {job="nginx", host="web-01"}
    
    # İçinde "error" geçen satırlar (büyük/küçük harf duyarlı)
    {job="nginx"} |= "error"
    
    # "error" içeren ama "favicon" içermeyenler
    {job="nginx"} |= "error" != "favicon"
    
    # Regex ile: 5xx durum kodları
    {job="nginx"} |~ " 5\\d{2} "
    
    # JSON logdan alan çıkar ve filtrele
    {job="uygulama"} | json | seviye="error" | line_format "{{.mesaj}}"
    
    # Metrik sorgusu: dakikadaki hata sayısı
    sum(rate({job="nginx"} |= "error" [1m])) by (host)
    
    # En çok log üreten konteyner
    topk(5, sum(count_over_time({job="docker"}[5m])) by (container))
    

    Son iki örnek Loki'nin en güçlü tarafını gösteriyor: log satırlarını metrik haline getirebilirsin. rate() ve count_over_time() ile hata sayısını zaman serisine çevirip Grafana'da metriklerinin yanına koyabilir, hatta bu ifadeler üzerine uyarı kurabilirsin. Böylece "5xx oranı yüzde birin üstüne çıkarsa haber ver" gibi bir kuralı, uygulamaya tek satır kod eklemeden yazabilirsin.

    Sık kullanılan operatörler kısa bir tabloya sığar:

    OperatörAnlamı
    |=Satır bu metni içeriyor
    !=Satır bu metni içermiyor
    |~Regex eşleşiyor
    !~Regex eşleşmiyor
    | jsonSatırı JSON olarak ayrıştır
    | logfmtlogfmt biçimini ayrıştır
    | line_formatÇıktı satırını yeniden biçimlendir

    Grafana'da Logları Metriklerle Hizalamak#

    Loki'nin asıl değeri, logları metriklerle aynı ekranda ve aynı zaman aralığında görebilmektir. Grafana'da Connections → Data sources → Loki ile veri kaynağını ekle (URL: http://loki:3100), sonra mevcut sunucu panonun altına bir Logs paneli koy.

    Kritik ayrıntı şudur: log panelinin sorgusunda, üstteki metrik panelleriyle aynı değişkeni kullan. Örneğin $instance değişkeninden sunucu seçiyorsan log sorgusu da {host=~"$instance"} olmalı. Böylece açılır menüden bir sunucu seçtiğinde hem grafikler hem loglar birlikte değişir. CPU'nun tavan yaptığı yere tıkladığında o dakikanın logları hemen altında durur — "neden" sorusunun cevabı ekran değiştirmeden gelir. Pano tarafındaki değişken kurulumunu Grafana dashboard oluşturma yazısındaki bölümden aynen uygulayabilirsin.

    Bir de Explore ekranını unutma. Pano yapmadan hızlı arama yapmak istediğinde Grafana'nın Explore modu, Loki için tasarlanmış canlı bir tail gibi çalışır; sorguyu yazıp "Live" düğmesine bastığında satırlar akmaya başlar. Konteyner loglarına doğrudan sunucudan bakma alışkanlığın varsa Docker konteyner loglarını okuma yazısındaki komutların merkezi karşılığı budur.

    Saklama, Sıkıştırma ve Disk Planlaması#

    Log saklama, izleme yığınında diski en hızlı dolduran kalemdir. Kabaca bir hesap yapmak istersen: orta yoğunlukta bir web sunucusu günde 200-500 MB ham log üretir, Loki bunu yaklaşık onda birine sıkıştırır. On sunucu ve 30 gün saklama için 15-25 GB civarı bir alan planlamak makul bir başlangıçtır. Trafiğin arttığında bu sayı doğrusal büyür.

    Saklama süresini limits_config.retention_period ile ayarlarsın, ama tek başına yeterli değildir — silme işini yapan bileşen compactor'dır ve retention_enabled: true verilmezse eski veriler diskte kalmaya devam eder. Bu, "retention ayarladım ama disk doluyor" şikâyetinin bir numaralı sebebidir.

    İhtiyaç duyarsan iş (job) bazında farklı süreler de tanımlayabilirsin:

    limits_config:
      retention_period: 720h        # varsayılan 30 gün
    
    overrides:
      # Denetim logları daha uzun saklansın
      "fake":
        retention_stream:
          - selector: '{job="audit"}'
            priority: 1
            period: 2160h           # 90 gün
          - selector: '{job="debug"}'
            priority: 2
            period: 168h            # 7 gün
    

    Disk kullanımını düzenli izlemek istersen Loki'nin kendi metrik uç noktası (/metrics) Prometheus tarafından kazınabilir; loki_ingester_chunks_flushed_total ve alım hızı metrikleri kapasite planlaması için yeterli sinyali verir. Sunucu diski beklenmedik biçimde doluyorsa suçlunun her zaman Loki olmadığını da hatırla — Docker diski doldurdu, nasıl temizlenir yazısındaki kontrol listesi genellikle daha büyük bir suçlu bulur.

    Sık Yapılan Hatalar ve Tuzaklar#

    Yüksek kardinaliteli etiket kullanmak. İstek kimliği, kullanıcı kimliği ya da tam URL'yi etiket yapmak Loki'yi öldürmenin en hızlı yoludur. Akış sayısı patlar, alım yavaşlar, bellek şişer. Bu bilgiler satır içinde kalsın, sorgu anında filtrelenirler.

    Etiket seçicisi olmadan sorgu yazmak. {job=~".+"} |= "error" gibi bir ifade tüm veriyi tarar. Her sorguya en az bir dar etiket seçicisi koy ve zaman aralığını mümkün olduğunca kısa tut.

    Pozisyon dosyasını kalıcı yapmamak. Promtail yeniden başladığında logları baştan okur, Loki eski zaman damgalarını reddeder ve loglar sessizce kaybolur. positions.yaml mutlaka kalıcı bir birimde durmalı.

    Zaman damgası ve saat kayması. Sunucuların saati kaymışsa Loki gelecekten ya da çok geçmişten gelen satırları reddeder. chronyd ya da systemd-timesyncd her sunucuda çalışıyor olmalı; log toplama, saat senkronizasyonunu görünür kılan ilk sistemdir.

    Retention ayarlayıp compactor'ı açmamak. retention_period yazmak yeterli değildir; compactor bloğunda retention_enabled: true olmadan hiçbir şey silinmez.

    Loki'yi kimlik doğrulamasız internete açmak. auth_enabled: false varsayılandır ve Loki'nin kendi kimlik doğrulaması yoktur. Portu ya yerelde tut ya da ters vekil arkasına alıp temel kimlik doğrulaması ekle; aksi halde tüm log geçmişin herkese açıktır.

    Sıkça Sorulan Sorular#

    Loki mi ELK mi kullanmalıyım#

    Karar büyük ölçüde ihtiyacın olan arama derinliğine bağlıdır. Loki, etiketlerle daraltıp sonra metin filtresi uyguladığın senaryolarda çok daha az kaynakla çalışır ve Grafana kullanıyorsan kurulumu birkaç saat sürer. Elasticsearch tabanlı yığın ise tam metin arama, karmaşık toplama (aggregation) ve uzun süreli analitik gerektiğinde öne geçer, ama karşılığında ciddi bellek ve bakım maliyeti ister. Ayrıntılı karşılaştırma için ELK Stack kurulumu yazısına bakabilirsin.

    Loki ne kadar disk alanı harcar#

    Ham log hacminin kabaca onda biri kadar; sıkıştırma oranı log biçimine göre değişir ve tekrar eden yapıdaki satırlarda daha da iyileşir. Günde 300 MB log üreten on sunucu ve 30 günlük saklama için 10-20 GB aralığında bir alan beklemek gerçekçidir. Asıl büyüme etiket sayısından değil satır hacminden gelir; debug seviyesini üretimde açık bırakmak bu sayıyı birkaç katına çıkarır.

    Promtail yerine ne kullanabilirim#

    Promtail en doğal seçenektir ama tek seçenek değildir. Grafana Alloy (eski adıyla Grafana Agent) hem metrik hem log toplayabilen birleşik bir ajandır ve yeni kurulumlarda giderek daha çok tercih ediliyor. Docker kullanıyorsan konteynerlerin loglarını doğrudan Loki'ye yollayan bir günlükleme sürücüsü (logging driver) da vardır, ancak ajan tabanlı yaklaşım daha esnektir çünkü satırları göndermeden önce işleyebilir.

    Loki logları ne kadar hızlı sorgular#

    Etiket seçicin ne kadar darsa o kadar hızlı. Tek bir konteynerin son bir saatlik logunda arama yapmak anlık döner; tüm sunucuların bir haftalık logunda metin araması yapmak dakikalar sürebilir ve zaman aşımına uğrayabilir. Loki'yi hızlı kullanmanın yolu, sorguyu her zaman etiketle daraltıp zaman aralığını olabildiğince kısa tutmaktır.

    Loglar geliyor ama Grafana'da görünmüyor, neden#

    Önce Grafana'nın Explore ekranında {job="..."} gibi çok basit bir sorgu çalıştır; sonuç geliyorsa sorun panonun sorgusundadır. Sonuç gelmiyorsa Promtail loglarına bak: positions.yaml yazma izni yoksa ya da __path__ deseni hiçbir dosyayla eşleşmiyorsa hiç satır gönderilmiyordur. Üçüncü olasılık zaman damgasıdır — sunucu saati kaymışsa Loki satırları sessizce reddeder.

    Loki üzerinden uyarı kurabilir miyim#

    Evet. Loki'nin kendi kural motoru (ruler) LogQL metrik ifadeleri üzerinde çalışır ve ürettiği uyarıları Alertmanager'a iletir; yani Prometheus kurallarıyla aynı boru hattını paylaşır. Örneğin sum(rate({job="nginx"} |= "error" [5m])) > 10 gibi bir ifade, hata oranı arttığında bildirim üretir. Alternatif olarak Grafana'nın kendi uyarı motoru da Loki sorgularını doğrudan destekler.

    Kapanış#

    Loki, log toplamayı ağır bir altyapı projesi olmaktan çıkarıp bir akşamda kurulabilir bir işe indirger — ama bunu etiket disiplinine bağlı olarak yapar. Aklında kalması gereken dört alışkanlık şunlar: etiketleri az ve düşük kardinaliteli tut, her sorguya dar bir etiket seçicisi koy, Promtail'in pozisyon dosyasını kalıcı bir birime al, ve saklama süresini ayarlarken compactor'ı açmayı unutma. Bunları oturttuğunda bir hata anını dakikalar içinde bulmak sıradan bir işe dönüşür.

    Merkezi log yığını sürekli açık bir sunucu ve rahat bir disk ister. Kendi Loki kurulumun için VDS ya da esnek büyüyebilen bulut sunucu paketlerimiz uygun bir zemin sunar; log verisini düzenli yedeklemek istiyorsan yedekleme hizmetimize göz atabilirsin. Kurulumu ve bakımı bize bırakmak isterseniz sunucu yönetimi hizmetimiz izleme ve log yığınının kurulumunu da kapsıyor.

    LokiLog YönetimiGrafana

    Uygulamaya geçmeye hazır mısınız?

    NVMe SSD, ücretsiz SSL ve %99.9 uptime garantisiyle Clou.TR hosting ve sunucu çözümleriyle projenizi hayata geçirin.