Tüm yazılar
Araçlar 6 dk okuma

Regex Intelligence Guide: Log Analizi ve Veri Madenciliği

Regex log analizi için pratik desenler: e-posta, URL ve IP yakalama, log satırı ayrıştırma, veri madenciliği ve catastrophic backtracking tuzakları.

#regex #log-analysis #data-mining #pattern-matching #debugging

Sunucu tarafında otomasyon kuran herkesin er ya da geç log dosyalarıyla baş başa kaldığı bir gece olur. Benimki bir web sunucusunun erişim log'unda kaybolmaya çalıştığım, yüz binlerce satırın içinden tek bir hatalı isteği aradığım bir geceydi. O gece öğrendiğim şey şuydu: regex log analizi için vazgeçilmez bir araçtır, ama ancak doğru kullanıldığında. Yanlış kurulan tek bir desen, size saatlerce yanlış sonuç ürettirebilir; hatta bazı desenler işlemciyi kilitleyip analizi tamamen durdurabilir.

Bu yazıda yıllar içinde elimde birikmiş pratik desenleri paylaşacağım: e-posta, URL ve IP doğrulama, log satırı ayrıştırma, veri madenciliğinde desen çıkarma ve en önemlisi beni gerçekten yakan tuzaklar. Örneklerin tamamı Python'un re modülüyle yazıldı ve çalışır durumda; kopyalayıp kendi log'larınızda deneyebilirsiniz.

Baştan bir uyarı: regex her sorunun cevabı değildir. Yapılandırılmış bir JSON log'u regex ile ayrıştırmaya çalışmak, tornavida yerine çekiç kullanmaya benzer. Ama düz metin log'lar, yarı yapılandırılmış ihracat dosyaları ve elle tutulmuş kayıtlar söz konusu olduğunda regex hâlâ en hızlı yoldur.

E-posta, URL ve IP Doğrulama Desenleri

Doğrulama desenlerinde en sık gördüğüm hata, mükemmeliyetçiliktir. RFC 5322'ye birebir uyan bir e-posta regex'i sayfalarca sürer ve pratikte kimsenin işine yaramaz. Log analizi bağlamında amaç doğrulama değil yakalamadır: metnin içinden e-postaya benzeyen şeyleri çekip çıkarmak istersiniz. Bu ayrımı kafanızda netleştirmek, desen tasarımını çok sadeleştirir.

Günlük işlerimde kullandığım pragmatik desenler şunlar:

  • E-posta (yakalama amaçlı): [\w.+-]+@[\w-]+\.[\w.-]+ — kusursuz değil ama log içindeki adreslerin neredeyse tamamını yakalar.
  • IPv4: \b(?:\d{1,3}\.){3}\d{1,3}\b — dikkat, bu desen 999.999.999.999 gibi geçersiz değerleri de eşler. Gerçek doğrulama gerekiyorsa eşleşmeyi Python tarafında ipaddress.ip_address() ile kontrol ederim; regex'i şişirmekten her zaman daha temizdir.
  • URL: https?://[^\s"'<>]+ — boşluk, tırnak ve açılı parantezde durur. Log satırlarında URL'nin sonuna yapışan noktalama işaretini ayrıca temizlemek gerekir.

Buradaki ders şu: regex'i kaba filtre olarak kullan, hassas doğrulamayı programlama diline bırak. İkisini tek desende birleştirmeye çalışan herkes gibi ben de okunmaz canavarlar üretmiştim; artık üretmiyorum.

Log Satırı Ayrıştırma: Named Group ve re.VERBOSE

Bir web sunucusu erişim log'unu ayrıştırırken iki özellik hayat kurtarır: isimli gruplar ((?P...)) ve deseni yorum satırlarıyla yazmaya izin veren re.VERBOSE bayrağı. İsimli gruplar sayesinde eşleşme sonucu kendi kendini belgeleyen bir sözlüğe dönüşür; altı ay sonra koda döndüğünüzde grup(3)'ün ne olduğunu hatırlamaya çalışmazsınız.

import re

LOG_DESENI = re.compile(r"""
    ^(?P<ip>\d{1,3}(?:\.\d{1,3}){3})     # istemci IP adresi
    \s+\S+\s+\S+\s+
    \[(?P<zaman>[^\]]+)\]                 # zaman damgasi
    \s+"(?P<metot>[A-Z]+)\s+(?P<yol>\S+)\s+HTTP/[\d.]+"
    \s+(?P<durum>\d{3})                   # HTTP durum kodu
    \s+(?P<boyut>\d+|-)                   # yanit boyutu
""", re.VERBOSE)

satir = '203.0.113.42 - - [01/Sep/2026:09:15:22 +0300] "GET /blog/feed HTTP/1.1" 200 5123'
es = LOG_DESENI.match(satir)
if es:
    kayit = es.groupdict()
    print(kayit["ip"], kayit["durum"], kayit["yol"])

Bu yapının en güzel yanı, deseni büyütmenin acısız olmasıdır. Yeni bir alan eklemek gerektiğinde ilgili satırın yanına yorumuyla birlikte eklersiniz; desen bozulmaz, okunurluğu düşmez. Aynı yaklaşımı Windows tarafında da uyguluyorum — PowerShell ile sistem izleme scripti yazısında anlattığım izleme hattında, olay günlüğü satırlarını benzer isimli-grup desenleriyle ayrıştırıp raporluyorum.

Bir de küçük ama kritik bir ayrıntı: re.match satırın başından eşleşir, re.search herhangi bir yerinden. Log ayrıştırmada neredeyse her zaman match (veya çapa olarak ^) istersiniz; aksi hâlde desen, satırın ortasındaki alakasız bir parçaya tutunup sessizce yanlış veri üretebilir.

Veri Madenciliğinde Desen Çıkarma

Ayrıştırmanın bir adım ötesi, log yığınından anlamlı örüntüler çıkarmaktır: hangi IP kaç kez hata aldı, hangi kullanıcı hangi saatlerde reddedildi, hangi uç nokta en çok zaman aşımına uğradı. Burada findall ve Counter ikilisi benim ekmek kapım. Eskiden bu tür soruları log'u Excel'e yapıştırıp elle süzerek cevaplamaya çalışırdım; bir gecelik ayıklama işi bu yaklaşımla dakikalara indi.

import re
from collections import Counter

IPV4 = re.compile(r"\b(?:\d{1,3}\.){3}\d{1,3}\b")
HATA = re.compile(r"\bERROR\b")

satirlar = [
    "2026-09-01 09:15:22 ERROR kullanici=ali ip=203.0.113.42 oturum reddedildi",
    "2026-09-01 09:16:03 ERROR kullanici=veli ip=203.0.113.42 parola hatali",
    "2026-09-01 09:18:47 WARN  ip=198.51.100.7 istek zaman asimi",
    "2026-09-01 09:21:10 ERROR kullanici=ali ip=198.51.100.7 oturum reddedildi",
]

sayac = Counter()
for satir in satirlar:
    if HATA.search(satir):
        for ip in IPV4.findall(satir):
            sayac[ip] += 1

for ip, adet in sayac.most_common(5):
    print(f"{ip}: {adet} hata kaydi")

Bu iskelet basit görünür ama gerçek işlerin çoğunu taşır: desenle çek, sayaçla topla, sırala, raporla. Desen çıkarmanın regex'in yetmediği yüzü de var elbette — "Ahmet Yılmaz Ltd." ile "AHMET YILMAZ LİMİTED ŞİRKETİ"nin aynı firma olduğunu hiçbir regex söyleyemez. O sınıra geldiğinizde firma eşleştirme ve fuzzy matching rehberinde anlattığım bulanık eşleştirme tekniklerine geçmek gerekir; regex kaba ayıklamayı yapar, bulanık eşleştirme inceltir.

Yaygın Tuzaklar: Backtracking, Greedy/Lazy ve Unicode

Regex'te en sık zaman kaybettiren üç tuzak, iç içe niceleyicilerin yol açtığı felaket geri izleme (catastrophic backtracking), açgözlü ve tembel eşleşmenin karıştırılması ve Unicode ile Türkçe karakter farklarıdır.

  • Catastrophic backtracking: (a+)+$ gibi iç içe tekrarlı desenler, eşleşmeyen bir girdide üstel sayıda geri dönüş dener ve işlemciyi kilitler. Masum görünen bir desen, tek bir bozuk log satırında bütün analizi dondurabilir. Çözüm: iç içe niceleyicilerden kaçının, alternatifleri ayrık tutun ve mümkünse desenin sonunu $ yerine belirgin bir sınırlayıcıyla bitirin. Python 3.11 ve sonrasında re modülünün atomik grup (?>...) desteği de bu tür desenleri güvenli hâle getirmek için iyi bir araç.
  • Greedy / lazy karmaşası: ".*" deseni, satırdaki ilk tırnaktan son tırnağa kadar her şeyi yutar; iki ayrı alanı tek alan sanırsınız. Tembel hâli ".*?" ilk kapanışta durur. Ben çoğu zaman ikisini de kullanmam: "[^"]*" gibi olumsuz karakter sınıfı hem daha hızlıdır hem de niyeti daha net anlatır.
  • Unicode ve Türkçe: Python 3'te \w varsayılan olarak Unicode'dur, yani "ğüşiöç" harflerini eşler — bu iyi haber. Kötü haber, başka araçlardan (grep, eski sistemler) gelen alışkanlıkla [a-zA-Z] yazmaktır; bu sınıf Türkçe karakterlerde sessizce delik açar. Bir de büyük/küçük harf tuzağı var: re.IGNORECASE, Türkçe'nin noktalı/noktasız i ayrımını (İ/i, I/ı) her zaman beklediğiniz gibi katlamaz. Kritik eşleştirmelerde metni önce casefold() ile normalize edip desende küçük harf kullanmak daha öngörülebilir sonuç verir.

Bu üç başlığın ortak dersi: bir deseni yalnızca eşleşmesi gereken örneklerle değil, eşleşmemesi gereken ve kötü biçimli örneklerle de test edin. Benim alışkanlığım, her kalıcı desenin yanına üç-beş satırlık bir test bloğu koymak; desen değiştiğinde testin kırılması, sessiz veri bozulmasından her zaman iyidir.

Log'larda Kişisel Veri ve KVKK

Log analizi konuşup işin hukuki yüzünü atlamak olmaz. IP adresi, e-posta ve kullanıcı adı KVKK kapsamında kişisel veridir; bir erişim log'u bu üçünü birden içerir. Yani "sadece log dosyası" dediğiniz şey, aslında bir kişisel veri deposudur ve buna göre davranmak gerekir.

Benim uygulamada izlediğim ilkeler şunlar:

  • Analiz çıktılarında kişisel veriyi mümkün olduğunca maskeleyin — raporda IP'nin son okteti yerine x yazmak çoğu analiz için yeterlidir, regex ile bu dönüşüm tek satırdır.
  • Ham log'ları süresiz saklamayın; saklama süresini baştan belirleyip otomatik temizlik kurun.
  • Log içeren dosyaları üçüncü taraf servislere (bulut tabanlı analiz araçları dâhil) göndermeden önce iki kez düşünün — bu, yurt dışına veri aktarımı anlamına gelebilir.
  • Ekiple log paylaşırken tam dosya yerine, maskelenmiş ve süzülmüş özet paylaşın.

Regex burada da işinize yarar: kişisel veriyi bulan desenler, aynı zamanda onu maskeleyen desenlerdir. re.sub ile e-postaları ve IP'leri anonimleştirmek, yukarıdaki yakalama desenlerinin en hayırlı kullanım alanlarından biri.

Sonuç

Regex, log analizi ve veri madenciliğinde hâlâ en keskin bıçaklardan biri — yeter ki sapından tutun. Özetle: yakalama ile doğrulamayı ayırın, isimli grup ve re.VERBOSE ile okunur desenler yazın, iç içe niceleyicilerden uzak durun, Türkçe metinlerde Unicode davranışını bilerek çalışın ve log'daki kişisel veriyi baştan hesaba katın. Bu ilkeler sayesinde ben log yığınlarını elle ayıklamaktan kurtuldum; aynı yolun size de zaman kazandıracağına eminim.

Veri ve otomasyon tarafında neler yaptığımı merak ediyorsanız ana sayfadaki çalışmalarıma göz atabilirsiniz. Elinizde ayrıştırılmayı bekleyen log yığınları, temizlenecek veri setleri veya otomatikleştirilecek raporlar varsa iletişim bölümünden bana yazın; birlikte çözelim.