Neler yeni

Yazılım Forum

Tüm özelliklerimize erişmek için şimdi bize katılın. Kayıt olduktan ve giriş yaptıktan sonra konu oluşturabilecek, mevcut konulara yanıt gönderebilecek, itibar kazanabilecek, özel mesajlaşmaya erişebilecek ve çok daha fazlasını yapabileceksiniz! Bu hizmetlerimiz ise tamamen ücretsiz ve kurallara uyulduğu sürece sınırsızdır, o zaman ne bekliyorsunuz? Hadi, sizde aramıza katılın!

Log Dosyalarını Etkin Bir Şekilde Ayrıştırma: Kapsamlı Betik Yazımı Rehberi

Giriş: Log Dosyaları ve Pars Etmenin Önemi

Modern bilgi işlem sistemleri, sunucular, ağ cihazları ve uygulamalar sürekli olarak olay günlükleri (log dosyaları) üretir. Bu loglar, sistemlerin ve uygulamaların çalışma durumları, oluşan hatalar, güvenlik ihlalleri, kullanıcı etkinlikleri ve performans verileri hakkında paha biçilmez bilgiler içerir. Ancak, bu dosyalar genellikle ham ve okunması zor formatlarda bulunur. Milyonlarca satırdan oluşabilen bu devasa veri yığınlarından anlamlı bilgiler çıkarmak için "log pars etme" (log parsing) adı verilen bir sürece ihtiyaç duyarız. Log pars etme, ham log verilerini yapılandırılmış, okunabilir ve analiz edilebilir bir formata dönüştürme işlemidir. Bu süreç, problem tespiti, güvenlik denetimi, performans optimizasyonu ve iş zekası analizi gibi birçok alanda kritik bir rol oynar. Bir betik (script) yazarak bu süreci otomatikleştirmek, zaman kazandırır ve insan hatasını minimize eder.

Log Dosyası Türleri ve Ortak Formatlar

Farklı sistemler ve uygulamalar farklı log formatları kullanır. İşte bazı yaygın log türleri ve onların formatları:

  • Web Sunucusu Logları:
  • Apache Erişim Logları: Genellikle "Common Log Format (CLF)" veya "Combined Log Format" kullanır. IP adresi, tarih/saat, HTTP metodu, URL, durum kodu, yanıt boyutu gibi bilgileri içerir.
  • Nginx Erişim Logları: Apache'ye benzer ancak daha esnek yapılandırma seçenekleri sunar.
  • Hata Logları: Sunucu veya uygulamanın karşılaştığı sorunları, uyarıları ve hataları kaydeder.
  • Sistem Logları:
  • Syslog: Linux/Unix tabanlı sistemlerde yaygın olarak kullanılır. Farklı servislerin ve çekirdeğin olaylarını merkezi bir yerde toplar.
  • Auth.log: Kimlik doğrulama ile ilgili olayları (başarılı/başarısız girişler, sudo kullanımları) kaydeder.
  • Uygulama Logları: Geliştiricilerin belirli bir uygulamanın davranışını izlemek için oluşturduğu özel formatlardır. Bunlar JSON, XML veya basit metin formatında olabilir.

Bu çeşitlilik, log pars betiği yazarken esnek bir yaklaşım benimsememizi gerektirir.

Log Pars Etme Yaklaşımları ve Kullanılabilecek Araçlar/Diller

Logları ayrıştırmak için çeşitli yöntemler ve araçlar mevcuttur:

  • Düzenli İfadeler (Regex): Metin içerisindeki belirli desenleri eşleştirmek ve yakalamak için güçlü bir yöntemdir. Özellikle yapılandırılmamış veya yarı yapılandırılmış loglar için idealdir.
  • Programlama Dilleri:
  • Python: Metin işleme yetenekleri, zengin kütüphane ekosistemi (re, json, pandas) ve okunabilirliği sayesinde log pars etme için en popüler dillerden biridir.
  • Perl: Metin işleme ve regex konusunda güçlü tarihsel bir geçmişi vardır, ancak son zamanlarda Python'ın popülaritesinin gerisinde kalmıştır.
  • Bash/Shell Scripting: grep, awk, sed gibi komutlarla hızlı ve basit pars işlemleri için etkilidir. Özellikle küçük ve orta ölçekli görevler için idealdir.
  • Go/Java/C#: Büyük ölçekli, yüksek performans gerektiren log işleme sistemleri için tercih edilebilirler.
  • Özel Log Yönetim Araçları: Logstash, Splunk, Graylog, ELK Stack (Elasticsearch, Logstash, Kibana) gibi ticari veya açık kaynaklı çözümler, log toplama, ayrıştırma, indeksleme, depolama ve görselleştirme yeteneklerini bir arada sunar.

Bu rehberde, özellikle Python ve Bash kullanarak log pars betikleri yazmaya odaklanacağız, çünkü bunlar çoğu senaryo için yeterli esnekliği ve gücü sunar.

Detaylı Log Pars Betiği Yazım Adımları

Bir log pars betiği geliştirirken izlenmesi gereken temel adımlar şunlardır:

  • Adım 1: Log Dosyasını Okuma
    Log pars etmenin ilk adımı, işlenecek log dosyasına erişmek ve içeriğini okumaktır. Basit bir metin dosyası ise satır satır okunabilir. Ancak, çok büyük log dosyaları (gigabaytlarca) ile çalışırken belleği verimli kullanmak önemlidir. Bu tür durumlarda, dosyanın tamamını belleğe yüklemek yerine, bir iteratör (döngü) kullanarak satır satır okumak en iyi yaklaşımdır.

    Kod:
        # Python ile dosya okuma örneği
        def read_log_file(filepath):
            try:
                with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
                    for line in f:
                        yield line.strip() # Her satırı temizleyip döndür
            except FileNotFoundError:
                print(f"Hata: Dosya bulunamadı: {filepath}")
            except Exception as e:
                print(f"Dosya okunurken bir hata oluştu: {e}")
    
        # Kullanım örneği:
        # for log_entry in read_log_file("sunucu.log"):
        #     print(log_entry)

    "Veri girişi her zaman tahmin edilenden daha kirli olacaktır. Bu nedenle, dosya okuma ve ilk temizleme adımları kritik öneme sahiptir." - Bilinmeyen Kaynak
  • Adım 2: Veri Ayrıştırma (Parsing)
    Okunan her log satırını, yapılandırılmış verilere dönüştürme işlemidir. Bu, log formatına bağlı olarak farklı yöntemlerle yapılabilir.
    • Regex (Düzenli İfadeler) Kullanımı: En yaygın ve güçlü yöntemlerden biridir. Karmaşık desenleri tanımak ve log satırlarından belirli alanları (IP adresi, tarih, URL, durum kodu vb.) çıkarmak için kullanılır.

      Kod:
              import re
      
              # Apache Combined Log Format örneği
              # 127.0.0.1 - - [10/Oct/2023:10:00:01 +0300] "GET /index.html HTTP/1.1" 200 1234 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
              APACHE_LOG_PATTERN = re.compile(
                  r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - - \[(.*?)\] "(.*?)" (\d{3}) (\d+) "(.*?)" "(.*?)"'
              )
      
              def parse_apache_log(log_line):
                  match = APACHE_LOG_PATTERN.match(log_line)
                  if match:
                      ip_address, timestamp, request, status_code, bytes_sent, referrer, user_agent = match.groups()
                      return {
                          "ip_address": ip_address,
                          "timestamp": timestamp,
                          "request": request,
                          "status_code": int(status_code),
                          "bytes_sent": int(bytes_sent),
                          "referrer": referrer,
                          "user_agent": user_agent
                      }
                  return None
      
              # Kullanım örneği:
              # log_line = '192.168.1.1 - - [20/Nov/2023:14:30:05 +0200] "GET /api/data HTTP/1.1" 200 567 "-" "PostmanRuntime/7.29.0"'
              # parsed_data = parse_apache_log(log_line)
              # if parsed_data:
              #     print(parsed_data)

      Regex öğrenmek ve test etmek için harika bir kaynak: https://regex101.com/
    • Delimiter (Ayraç) Kullanımı: Log satırlarının virgül, sekme veya başka bir karakterle ayrıldığı durumlarda string.split() gibi yöntemler kullanılabilir. CSV dosyaları bu kategoriye girer.

      Kod:
              # Virgülle ayrılmış log örneği: time,level,message,source
              def parse_csv_log(log_line):
                  parts = log_line.strip().split(',')
                  if len(parts) == 4:
                      return {
                          "time": parts[0],
                          "level": parts[1],
                          "message": parts[2],
                          "source": parts[3]
                      }
                  return None
    • JSON/XML Pars Etme: Eğer loglar doğrudan JSON veya XML formatında yazılmışsa, ilgili kütüphaneler (Python'da `json` modülü veya `xml.etree.ElementTree`) kullanılarak doğrudan nesnelere dönüştürülebilir. Bu, en kolay ayrıştırma yöntemidir çünkü veriler zaten yapılandırılmıştır.

      Kod:
              import json
      
              # JSON log örneği: {"timestamp": "2023-11-20T14:30:05Z", "level": "INFO", "message": "User logged in", "user_id": 123}
              def parse_json_log(log_line):
                  try:
                      return json.loads(log_line)
                  except json.JSONDecodeError:
                      return None
      
              # Kullanım örneği:
              # json_log = '{"timestamp": "2023-11-20T14:30:05Z", "level": "INFO", "message": "User logged in", "user_id": 123}'
              # parsed_json = parse_json_log(json_log)
              # if parsed_json:
              #     print(parsed_json)
  • Adım 3: Veri Filtreleme ve Dönüştürme
    Ayrıştırılan veriler üzerinde belirli kriterlere göre filtreleme yapabilir veya daha ileri analizler için formatlarını dönüştürebiliriz. Örneğin, sadece hata loglarını almak, belirli bir IP'den gelen istekleri saymak veya tarih/saat damgalarını daha kullanışlı bir formata dönüştürmek isteyebiliriz.

    Kod:
        from datetime import datetime
    
        def filter_and_transform_apache_log(parsed_data):
            if parsed_data and parsed_data["status_code"] >= 400: # Sadece hata kodları (4xx veya 5xx)
                # Zaman damgasını datetime nesnesine dönüştürme
                # Örnek: "10/Oct/2023:10:00:01 +0300"
                try:
                    # Regex ile yakalanan zaman damgası biraz karmaşık, önce formatını basitleştirelim.
                    # Daha iyi bir yaklaşım, regex'i bu kısmı daha kesin yakalamak için ayarlamaktır.
                    # Şimdilik, sadece tarih ve saati alalım.
                    dt_str = parsed_data["timestamp"].split(' ')[0] # "10/Oct/2023:10:00:01"
                    dt_obj = datetime.strptime(dt_str, "%d/%b/%Y:%H:%M:%S")
                    parsed_data["timestamp_dt"] = dt_obj
                    return parsed_data
                except ValueError as e:
                    print(f"Tarih dönüştürme hatası: {e} için {parsed_data['timestamp']}")
                    return None
            return None
    
        # Kullanım örneği:
        # parsed_log = parse_apache_log('192.168.1.5 - - [20/Nov/2023:15:00:10 +0200] "GET /nonexistent HTTP/1.1" 404 345 "-" "curl/7.64.1"')
        # error_log = filter_and_transform_apache_log(parsed_log)
        # if error_log:
        #     print(error_log)
  • Adım 4: Veriyi Depolama veya Analiz Etme
    İşlenen verilerle ne yapacağımız, betiğin amacına bağlıdır. Yaygın seçenekler şunlardır:
    • Yeni bir dosyaya yazma: İşlenmiş verileri (örneğin CSV veya JSON formatında) başka bir dosyaya kaydetmek.
    • Veritabanına kaydetme: PostgreSQL, MySQL gibi ilişkisel veritabanlarına veya MongoDB, Elasticsearch gibi NoSQL veritabanlarına kaydetmek.
    • Doğrudan analiz veya uyarı sistemi: Verileri anında işleyip bir gösterge panosuna göndermek, belirli bir olay durumunda uyarı tetiklemek veya gerçek zamanlı analiz yapmak.

    Kod:
        import csv
    
        def save_to_csv(data_list, filename="parsed_logs.csv"):
            if not data_list:
                return
    
            keys = data_list[0].keys()
            with open(filename, 'w', newline='', encoding='utf-8') as output_file:
                dict_writer = csv.DictWriter(output_file, fieldnames=keys)
                dict_writer.writeheader()
                dict_writer.writerows(data_list)
            print(f"{len(data_list)} kayıt {filename} dosyasına yazıldı.")
    
        # Toplu işleme örneği:
        # all_parsed_errors = []
        # for line in read_log_file("sunucu.log"):
        #     parsed = parse_apache_log(line)
        #     filtered = filter_and_transform_apache_log(parsed)
        #     if filtered:
        #         all_parsed_errors.append(filtered)
        # save_to_csv(all_parsed_errors)

Kapsamlı Python Log Pars Betiği Örneği

Aşağıda, belirtilen adımları birleştiren daha kapsamlı bir Python betiği örneği bulunmaktadır. Bu betik, bir Apache erişim log dosyasını okur, hata durum kodlarına sahip girişleri ayrıştırır ve bunları bir CSV dosyasına kaydeder.

Kod:
import re
import csv
from datetime import datetime

# Regex deseni (Apache Combined Log Format için)
APACHE_LOG_PATTERN = re.compile(
    r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - - \[(.*?)\s[+\-]\d{4}\] "(.*?)" (\d{3}) (\d+) "(.*?)" "(.*?)"'
)

def read_log_file_generator(filepath):
    """
    Belirtilen log dosyasını satır satır okuyan bir jeneratör.
    Büyük dosyalar için bellek verimliliği sağlar.
    """
    try:
        with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
            for line in f:
                yield line.strip()
    except FileNotFoundError:
        print(f"[HATA] Dosya bulunamadı: {filepath}")
        return
    except Exception as e:
        print(f"[HATA] Dosya okunurken bir sorun oluştu: {e}")
        return

def parse_apache_log_entry(log_line):
    """
    Bir Apache log satırını ayrıştırır ve bir sözlük döndürür.
    Eşleşme bulunamazsa None döner.
    """
    match = APACHE_LOG_PATTERN.match(log_line)
    if match:
        try:
            ip_address, timestamp_str, request, status_code_str, bytes_sent_str, referrer, user_agent = match.groups()

            # Tarih ve saat bilgisini datetime objesine dönüştür
            # Örnek: "10/Oct/2023:10:00:01"
            dt_obj = datetime.strptime(timestamp_str.split(' ')[0], "%d/%b/%Y:%H:%M:%S")

            return {
                "ip_address": ip_address,
                "timestamp": dt_obj.isoformat(), # ISO formatına dönüştürüyoruz
                "request_method": request.split(' ')[0] if request else "",
                "request_path": request.split(' ')[1] if len(request.split(' ')) > 1 else "",
                "http_version": request.split(' ')[2] if len(request.split(' ')) > 2 else "",
                "status_code": int(status_code_str),
                "bytes_sent": int(bytes_sent_str),
                "referrer": referrer,
                "user_agent": user_agent,
                "raw_log_line": log_line # Orijinal log satırını da tutmak faydalı olabilir
            }
        except (ValueError, IndexError) as e:
            print(f"[UYARI] Ayrıştırma veya dönüşüm hatası: {e} - Satır: {log_line}")
            return None
    return None

def main_parser(log_filepath, output_csv_filepath, filter_status_code_gte=None):
    """
    Log dosyasını okur, ayrıştırır, filtreler ve CSV'ye kaydeder.
    """
    parsed_entries = []
    processed_count = 0
    error_count = 0

    print(f"'{log_filepath}' dosyası işleniyor...")

    for line in read_log_file_generator(log_filepath):
        processed_count += 1
        parsed_data = parse_apache_log_entry(line)

        if parsed_data:
            if filter_status_code_gte is None or parsed_data["status_code"] >= filter_status_code_gte:
                parsed_entries.append(parsed_data)
        else:
            error_count += 1

    if parsed_entries:
        # CSV başlıkları için ilk öğenin anahtarlarını kullan
        fieldnames = list(parsed_entries[0].keys())

        try:
            with open(output_csv_filepath, 'w', newline='', encoding='utf-8') as csvfile:
                writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
                writer.writeheader()
                writer.writerows(parsed_entries)
            print(f"Başarıyla ayrıştırılan {len(parsed_entries)} kayıt '{output_csv_filepath}' adresine kaydedildi.")
        except IOError as e:
            print(f"[HATA] CSV dosyasına yazarken hata oluştu: {e}")
    else:
        print("Filtreleme kriterlerine uyan veya ayrıştırılabilecek kayıt bulunamadı.")

    print(f"Toplam işlenen satır: {processed_count}, Hata veren satır: {error_count}")
    print("Log ayrıştırma işlemi tamamlandı.")

# Betiği çalıştırma örneği (bu kısmı gerçek kullanımda yorumdan çıkarılmalıdır)
# if __name__ == "__main__":
#     # Örnek bir log dosyası oluşturun veya mevcut bir dosyayı kullanın
#     # test_log_content = """
#     # 127.0.0.1 - - [20/Nov/2023:10:00:01 +0300] "GET /index.html HTTP/1.1" 200 1234 "-" "Mozilla/5.0"
#     # 192.168.1.5 - - [20/Nov/2023:10:00:02 +0300] "POST /api/users HTTP/1.1" 201 56 "-" "Postman"
#     # 10.0.0.10 - - [20/Nov/2023:10:00:03 +0300] "GET /nonexistent HTTP/1.1" 404 345 "-" "curl/7.64.1"
#     # 172.16.0.1 - - [20/Nov/2023:10:00:04 +0300] "GET /admin HTTP/1.1" 401 223 "-" "Chrome"
#     # invalid log entry here
#     # 192.168.1.10 - - [20/Nov/2023:10:00:05 +0300] "GET /error.php HTTP/1.1" 500 1200 "-" "Firefox"
#     # """
#     # with open("sample_apache.log", "w") as f:
#     #     f.write(test_log_content.strip())
#
#     # main_parser("sample_apache.log", "parsed_errors.csv", filter_status_code_gte=400)
#     # main_parser("sample_apache.log", "all_access.csv") # Tüm logları kaydet

Basit Bash Log Pars Betiği Örneği

Daha küçük ve hızlı görevler için Bash betikleri son derece kullanışlıdır. `grep`, `awk`, `sed` gibi komutlar ile logları filtreleyebilir ve işleyebilirsiniz.

Kod:
#!/bin/bash

LOG_FILE="syslog.log"
OUTPUT_FILE="filtered_errors.log"

echo "Hata logları filtreleniyor ve '$OUTPUT_FILE' dosyasına yazılıyor..."

# syslog dosyasındaki "error" veya "fail" kelimesini içeren satırları bul
# ve tarih, işlem ve mesajı ayıkla
grep -E "error|fail" "$LOG_FILE" | awk '{print $1, $2, $3, $5, $6, $7, $8, $9, $10, $11}' > "$OUTPUT_FILE"

echo "İşlem tamamlandı."
echo "Örnek kullanım (Bash):"
echo '  # son 100 satırda "Failed password" içeren logları göster'
echo '  tail -n 100 /var/log/auth.log | grep "Failed password"'
echo ''
echo '  # Belirli bir IP adresinden gelen Apache isteklerini say'
echo '  awk "$1 == \"192.168.1.1\" {count++} END {print count}" /var/log/apache2/access.log'

En İyi Uygulamalar ve Performans İpuçları

Bir log pars betiği geliştirirken aşağıdaki en iyi uygulamaları göz önünde bulundurmak önemlidir:

  • Hata Yönetimi: Log dosyaları genellikle bozuk veya beklenmeyen formatta satırlar içerebilir. Betiğinizin bu tür satırları atlaması veya hata kaydetmesi, ancak çalışmaya devam etmesi için uygun `try-except` blokları veya koşullu kontroller kullanın.
  • Bellek ve CPU Optimizasyonu: Büyük log dosyalarıyla çalışırken, dosyanın tamamını belleğe yüklemek yerine satır satır işleyen jeneratörler veya akış tabanlı okuma yöntemleri kullanın. Regex desenlerinizi mümkün olduğunca verimli yazmaya çalışın.
  • Otomasyon: Log pars betiklerini `cron` (Linux) veya Görev Zamanlayıcı (Windows) gibi araçlarla düzenli olarak çalışacak şekilde planlayın. Bu, sürekli bir izleme ve analiz sağlar.
  • Modüler Tasarım: Betiğinizi dosya okuma, ayrıştırma, filtreleme ve depolama gibi ayrı işlevlere bölmek, kodun okunabilirliğini, test edilebilirliğini ve bakımını kolaylaştırır.
  • Kayıt Formatı Standardizasyonu: Mümkünse, log üreten sistemlerinizde JSON gibi yapılandırılmış bir log formatı kullanmayı teşvik edin. Bu, ayrıştırma sürecini büyük ölçüde basitleştirir.
  • Log Rotasyonu: İşletim sistemleri veya log yönetim araçları tarafından yapılan log rotasyonunu (eski log dosyalarını sıkıştırma veya silme) dikkate alın. Betiğinizin sıkıştırılmış logları (örn. .gz) okuyabilmesi veya rotasyon sonrası yeni log dosyalarını bulabilmesi gerekebilir.

Faydalı Kaynaklar


Sonuç

Log pars betikleri yazmak, sistemlerinizin ve uygulamalarınızın derinlemesine anlaşılması için vazgeçilmez bir beceridir. Bu rehberde ele alınan Python ve Bash örnekleri, çeşitli log formatlarını etkili bir şekilde ayrıştırmak ve değerli bilgileri çıkarmak için size sağlam bir temel sunmaktadır. Doğru araçlar ve yaklaşımlarla, devasa log yığınlarını anlamlı verilere dönüştürebilir, operasyonel verimliliği artırabilir ve güvenlik duruşunuzu güçlendirebilirsiniz. Unutmayın, iyi yazılmış bir log pars betiği, pasif log dosyalarını aktif bir bilgi kaynağına dönüştüren bir köprüdür. Bu alandaki sürekli gelişim ve yeni log formatları göz önüne alındığında, öğrenmeye ve betiklerinizi güncel tutmaya devam etmek önemlidir.
 
shape1
shape2
shape3
shape4
shape5
shape6
Üst

Bu web sitenin performansı Hazal Host tarafından sağlanmaktadır.

YazilimForum.com.tr internet sitesi, 5651 sayılı Kanun’un 2. maddesinin 1. fıkrasının (m) bendi ve aynı Kanun’un 5. maddesi kapsamında Yer Sağlayıcı konumundadır. Sitede yer alan içerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır.

YazilimForum.com.tr, kullanıcılar tarafından paylaşılan içeriklerin doğruluğunu, güncelliğini veya hukuka uygunluğunu garanti etmez ve içeriklerin kontrolü veya araştırılması ile yükümlü değildir. Kullanıcılar, paylaştıkları içeriklerden tamamen kendileri sorumludur.

Hukuka aykırı içerikleri fark ettiğinizde lütfen bize bildirin: lydexcoding@gmail.com

Sitemiz, kullanıcıların paylaştığı içerik ve bilgileri 6698 sayılı KVKK kapsamında işlemektedir. Kullanıcılar, kişisel verileriyle ilgili haklarını KVKK Politikası sayfasından inceleyebilir.

Sitede yer alan reklamlar veya üçüncü taraf bağlantılar için YazilimForum.com.tr herhangi bir sorumluluk kabul etmez.

Sitemizi kullanarak Forum Kuralları’nı kabul etmiş sayılırsınız.

DMCA.com Protection Status Copyrighted.com Registered & Protected