Ana içeriğe geç

Kibana ile Log Analizi ve Görselleştirme

Kibana, Elasticsearch üzerindeki log verilerini görselleştirir ve analiz eder; yanlış yapılandırma log’ların bulunamamasına ve verimsiz analize yol açar.


1. Yapılandırılmamış Log Göndermek

Yanlış Kullanım: Düz metin logları Elasticsearch’e göndermek.

_logger.LogInformation($"Sipariş oluşturuldu: {order.Id}, Müşteri: {order.CustomerId}, Tutar: {order.Total}");
// Düz metin, Kibana'da alan bazlı filtreleme yapılamaz

İdeal Kullanım: Structured logging ile alan bazlı arama yapın.

builder.Host.UseSerilog((context, config) => config
    .WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://elasticsearch:9200"))
    {
        IndexFormat = "app-logs-{0:yyyy.MM.dd}",
        AutoRegisterTemplate = true,
        AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv8,
        NumberOfShards = 2,
        NumberOfReplicas = 1
    }));

// Structured log
_logger.LogInformation("Sipariş oluşturuldu: {OrderId}, Müşteri: {CustomerId}, Tutar: {Total}",
    order.Id, order.CustomerId, order.Total);
// Kibana'da OrderId, CustomerId, Total alanları ile filtreleme yapılabilir

2. Index Pattern Yönetimi Yapmamak

Yanlış Kullanım: Tek bir index’e tüm logları yazmak.

new ElasticsearchSinkOptions(new Uri("http://elasticsearch:9200"))
{
    IndexFormat = "application-logs",
    // Tek index sürekli büyür, performans düşer
};

İdeal Kullanım: Tarih bazlı index rotation uygulayın.

new ElasticsearchSinkOptions(new Uri("http://elasticsearch:9200"))
{
    IndexFormat = "app-{0:yyyy.MM.dd}",  // Günlük index
    AutoRegisterTemplate = true,
    TemplateName = "app-template",
    BatchPostingLimit = 50,
    Period = TimeSpan.FromSeconds(5)
};
// ILM (Index Lifecycle Management) Policy
// PUT _ilm/policy/log-retention
{
  "policy": {
    "phases": {
      "hot": { "actions": { "rollover": { "max_size": "5gb", "max_age": "1d" } } },
      "warm": { "min_age": "7d", "actions": { "shrink": { "number_of_shards": 1 } } },
      "delete": { "min_age": "30d", "actions": { "delete": {} } }
    }
  }
}

3. Dashboard Oluşturmamak

Yanlış Kullanım: Kibana’yı sadece log arama için kullanmak.

// Kibana Discover sekmesinde her seferinde manuel sorgu yazmak
// Tekrarlayan aramalarda zaman kaybı

İdeal Kullanım: Önceden tanımlı dashboard’lar oluşturun.

// Kibana saved search örneği - API hataları
{
  "query": {
    "bool": {
      "must": [
        { "range": { "@timestamp": { "gte": "now-1h" } } },
        { "range": { "fields.StatusCode": { "gte": 500 } } }
      ]
    }
  }
}
// Dashboard için anlamlı log alanları ekleyin
_logger.LogError("API hatası: {StatusCode} {Endpoint} {Method} {Duration}ms {ErrorMessage}",
    context.Response.StatusCode,
    context.Request.Path,
    context.Request.Method,
    stopwatch.ElapsedMilliseconds,
    exception.Message);

4. Log Seviyelerini Yanlış Kullanmak

Yanlış Kullanım: Her şeyi Information seviyesinde loglamak.

_logger.LogInformation("DB bağlantısı başarısız: {Error}", ex.Message);  // Error olmalı
_logger.LogInformation("Cache miss: {Key}", key);                          // Debug olmalı
_logger.LogInformation("Kullanıcı giriş yaptı: {UserId}", userId);       // Doğru
_logger.LogInformation("Döngü iterasyonu: {i}", i);                       // Trace olmalı

İdeal Kullanım: Doğru log seviyelerini kullanın.

_logger.LogTrace("Döngü iterasyonu: {Index}", i);
_logger.LogDebug("Cache miss, DB'den çekiliyor: {Key}", key);
_logger.LogInformation("Kullanıcı giriş yaptı: {UserId}", userId);
_logger.LogWarning("Rate limit yaklaşıyor: {CurrentRate}/{MaxRate}", current, max);
_logger.LogError(ex, "Sipariş oluşturulamadı: {OrderId}", orderId);
_logger.LogCritical(ex, "Veritabanı bağlantısı tamamen kesildi");

// Ortam bazlı minimum seviye
// appsettings.Production.json
// { "Logging": { "LogLevel": { "Default": "Warning", "MyApp": "Information" } } }

5. Hassas Verileri Loglamak

Yanlış Kullanım: PII ve hassas bilgileri loglara yazmak.

_logger.LogInformation("Kullanıcı girişi: {Email} {Password}", email, password);
_logger.LogInformation("Ödeme: Kart={CardNumber}", cardNumber);
// KVKK/GDPR ihlali, güvenlik riski

İdeal Kullanım: Hassas verileri maskeleyin veya hariç tutun.

public class SensitiveDataDestructuringPolicy : IDestructuringPolicy
{
    private static readonly HashSet<string> SensitiveFields = new(StringComparer.OrdinalIgnoreCase)
    {
        "password", "token", "secret", "cardnumber", "cvv", "ssn"
    };

    public bool TryDestructure(object value, ILogEventPropertyValueFactory factory,
        out LogEventPropertyValue? result)
    {
        // Hassas alanları maskele
        result = null;
        return false;
    }
}

// Veya Serilog.Expressions ile
builder.Host.UseSerilog((context, config) => config
    .Destructure.ByTransforming<PaymentRequest>(r => new
    {
        r.OrderId,
        CardNumber = "****" + r.CardNumber[^4..],
        CVV = "***"
    }));