.NET ile AI Destekli Log Analiz Servisi — Faz 4: Incident Intelligence, Multi-Candidate Extraction…
Önceki fazlarda logları topladık ve AI ile analiz ettik. Ancak sistem olgunlaştıkça büyük bir engelle karşılaştım: Aggregation Bias…
.NET ile AI Destekli Log Analiz Servisi — Faz 4: Incident Intelligence, Multi-Candidate Extraction ve Jira Orchestration
Önceki fazlarda logları topladık ve AI ile analiz ettik. Ancak sistem olgunlaştıkça büyük bir engelle karşılaştım: Aggregation Bias (Toplulaştırma Yanılgısı). AI, bir batch içindeki tüm farklı hataları tek bir “hikayeye” dönüştürüyordu. Bu bölümde, sistemin nasıl log özetleyen bir yapıdan çıkıp, operasyonel problemleri birbirinden ayıran ve yöneten bir Incident Intelligence Pipeline’a dönüştüğünü inceleyeceğiz.

Jira API İşlemleri
İçeriğe geçmeden önce Jira ile ilgili birkaç detay vereyim, bilgi sahibi olanlar Giriş bölümüne geçebilirler. Önceden freelance işlerim ve günlük takiplerim için Trello kullanıyordum, Atlassian Trelloyu satın aldıktan sonra Jira ile tanıştım ve kullanmaya başladım. Hem daha profesyönel hem de kurumsal şirketler yoğun şekilde kullanıyor. Her şekilde iş hayatınıza artı karacağına inanıyorum.
Geliştirmeye başlamadan önce Jira hesabımda bir Log Analiz workspace oluşturdum. Hemen bir iş akışı belirledim.

Sonra projem için özel bir api key ürettim. Ardından bir sprint oluşturup, ilk taskı elle oluşturdum.

Api ile taskları nasıl çekebileceğimi denedim.

Görüldüğü gibi Jira api ile iletişimi kurduktan sonra, mimariyi değiştirmeye ve projeye çağ atlatmaya geçebilirim.
Github Repo
Kod okumayı makale okumaktan daha keyifli bulanlar için repoyu paylaşayım: https://github.com/melihtuna/LogAnalyzer
1. Giriş: AI Log Analiz Ediyor Ama Problem Çözülüyor mu?
AI’dan bir özet almak, operasyon ekipleri için her zaman “aksiyon alınabilir” (actionable) sonuçlar üretmez. Bir batch içinde hem ödeme hatası hem de veritabanı yavaşlığı varsa, bunları tek bir Jira task’ında birleştirmek operasyonel körlüğe yol açar. Faz 4'ün temel amacı, AI’yı bir “Summarizer” olmaktan çıkarıp bir “Incident Extractor” haline getirmekti.
2. Incident-Centric Mimariye Geçiş: Log Analizi Değil, Olay Yönetimi
Faz 3 sonunda sistem teknik olarak çalışıyordu. Graylog üzerinden gelen loglar OpenAI ile analiz ediliyor ve özet bilgiler üretiliyordu. İlk etapta bu yapı yeterli görünse de gerçek trafik altında önemli bir problem ortaya çıkmaya başladı. Aynı batch içinde oluşan timeout, payment failure, TLS warning veya database kilitlenmesi gibi birbirinden farklı problemler tek bir AI özeti altında birleşebiliyordu.
Bir süre bunun yalnızca AI tarafındaki yorumlama kalitesiyle ilgili olduğunu düşündüm. Ancak sistemi izledikçe asıl problemin mimaride olduğunu fark ettim. Çünkü sistemin merkezinde hâlâ log satırları vardı. Oysa operasyon ekipleri log değil, olay yönetir.
Bu yüzden yapının merkezini loglardan çıkarıp “Incident” kavramı üzerine taşımaya karar verdim. Böylece sistem yalnızca bir hata mesajını yorumlayan değil, olayın yaşam döngüsünü takip eden bir yapıya dönüşmeye başladı. Aynı problemin tekrar oluştuğu durumlarda yeni kayıt açmak yerine mevcut incident güncelleniyor, occurrence sayısı artırılıyor ve Jira tarafında duplicate task oluşumu engelleniyordu.
Bu değişiklikten sonra sistemin davranışı da tamamen değişti. Artık amaç yalnızca “logları analiz etmek” değil, operasyonel olarak anlamlı olayları ayırmak, takip etmek ve yönetmek haline geldi.
OLD:
Logs → AI Summary → Jira
NEW:
Logs → Incident Extraction → Incident Lifecycle → Jira
3. Structured AI Contracts ve Güvenli Parsing
LLM entegrasyonunun ilk versiyonlarında en büyük problemlerden biri, model çıktısının her zaman aynı yapıda dönmemesiydi. Bazı cevaplar eksik alan içeriyor, bazıları geçersiz JSON üretiyor, bazıları ise tamamen serbest metne dönüşüyordu. Demo seviyesinde bu durum tolere edilebilir olsa da, incident pipeline’ının merkezine AI koyduğum noktada çıktının deterministik olması gerekiyordu.
Bu yüzden AI cevabını doğrudan kullanmak yerine version’lanmış structured contract yaklaşımına geçtim. Modelden artık serbest açıklama değil, belirli alanlara sahip JSON response üretmesini istiyordum. Süreç ilerledikçe ilk contract yapısı yeterli olmamaya başladı ve multi-candidate extraction desteği için V2 yapısına geçildi.
Ancak yalnızca contract tanımlamak yeterli olmadı. Gerçek trafik altında model zaman zaman bozuk JSON üretiyor, alan isimlerini değiştiriyor veya contract dışına çıkabiliyordu. Bu yüzden AI cevabını doğrudan sisteme almak yerine strict parser, repair ve fallback katmanlarından oluşan ayrı bir güvenlik hattı oluşturdum.
Pipeline önce gelen cevabı strict schema validator üzerinden geçiriyor. Eğer response contract ile tam uyumluysa veri doğrudan işleniyor. Uyuşmayan durumlarda sistem hemen hata moduna geçmek yerine repair mekanizmasını devreye alıyor. Basit format problemleri düzeltilmeye çalışılıyor, başarısız olursa pipeline tamamen kırılmak yerine minimal güvenli fallback payload üretiliyor.
Bu yaklaşımın önemli taraflarından biri de telemetry oldu. Malformed response, repair attempt veya fallback senaryolarını telemetry etiketleri üzerinden işaretleyerek hangi modellerin veya prompt değişikliklerinin daha fazla hata ürettiğini izleyebilir hale geldim.
Buradaki amaç AI çıktısını tamamen kusursuz hale getirmek değil, güvenilmez davranışları kontrollü şekilde yönetebilmekti. Çünkü production ortamında asıl problem modelin hata yapması değil, bu hataların sistemin geri kalanını bozması oluyor.
[AI Response (Raw JSON)]
↓
[Strict Schema Validator] → (Hata varsa) → [Repair Mechanism]
↓ ↓
↓ <--- (Tamir edilemezse) --- [Fallback Payload]
↓ ↓
[Validated & Structured Incident] ←----------- (Etiketle: "malformed_fixed")
4. AI Destekli Incident Classification: Özetin Ötesinde
Structured parsing katmanı oturduktan sonra sıradaki problem, AI çıktısını operasyonel olarak kullanılabilir hale getirmek oldu. Çünkü yalnızca summary üretmek incident yönetimi için yeterli değildi. Sistemin aynı zamanda olayın önem seviyesini belirlemesi, hangi operasyonel kategoriye ait olduğunu anlaması ve mümkünse olası kök nedeni yorumlayabilmesi gerekiyordu.
Bu noktada pipeline yalnızca metin üretmek yerine incident enrichment odaklı çalışmaya başladı. AI cevabı artık severity, category, possible root cause ve recommended action alanlarıyla birlikte structured incident modeline dönüştürülüyordu.
Severity bilgisi yalnızca görsel bir etiket olarak kullanılmadı. Incident önceliği, Jira task oluşturma davranışı, retry stratejileri ve ileride planlanan escalation kuralları bu alan üzerinden şekillenmeye başladı. Benzer şekilde category alanı da frontend, backend, infrastructure veya external_service gibi operasyonel ayrımları yapabilmek için pipeline’ın merkezine taşındı.
Possible root cause alanı başlangıçta yalnızca açıklayıcı metadata gibi görünüyordu. Ancak süreç ilerledikçe bunun operational grouping tarafında da önemli hale geldiğini fark ettim. Özellikle timeout, dependency failure veya deadlock gibi problemlerde AI’ın ürettiği açıklamalar, benzer incident’ların aynı operasyonel bağlam altında toplanmasını kolaylaştırmaya başladı.
Bu aşamada dikkat ettiğim önemli noktalardan biri de AI’ın doğrudan aksiyon alan bir yapıya dönüşmemesiydi. Recommended action alanı otomatik remediation üretmek yerine, incident’i inceleyecek kişiye hızlı başlangıç noktası sağlayacak seviyede tutuldu. Böylece sistem karar veren değil, operasyonel bağlam sağlayan bir yardımcı katman olarak konumlandı.
Süreç ilerledikçe classification çıktıları yalnızca kullanıcıya gösterilen bilgiler olmaktan çıkıp, fingerprinting, incident similarity ve Jira orchestration tarafını besleyen operasyonel metadata’ya dönüştü.
{
"schema_version": "2",
"candidates": [
{
"normalized_operational_title": "Payment capture declined",
"severity": "critical",
"category": "backend",
"technical_summary": "Payment capture requests are failing during checkout because the upstream payment provider returned issuer decline responses.",
"possible_root_cause": "External payment provider instability or issuer-side rejection behavior.",
"recommended_action": "Inspect payment provider health, retry policies, and issuer decline handling logic.",
"confidence": 0.91,
"matching_terms": [
"Payment capture declined",
"issuer decline",
"PaymentOrchestrator"
]
},
{
"normalized_operational_title": "Inventory API timeout",
"severity": "high",
"category": "external_service",
"technical_summary": "Inventory API calls are timing out under load and delaying checkout operations.",
"possible_root_cause": "High latency or degraded response times in downstream inventory services.",
"recommended_action": "Inspect Inventory API latency, timeout thresholds, and downstream dependency health.",
"confidence": 0.84,
"matching_terms": [
"timeout",
"InventoryApi",
"TaskCanceledException"
]
}
]
}
5. Multi-Candidate Incident Extraction ve AI Extraction Semantics
Incident-centric yapıya geçtikten sonra sistemin davranışı büyük ölçüde değişmişti ancak önemli bir problem hâlâ devam ediyordu. Periyodik analiz sırasında aynı batch içinde bulunan farklı operasyonel problemler, AI tarafından hâlâ tek bir özet altında birleştirilebiliyordu. Özellikle timeout, payment failure, TLS warning veya dependency problemleri aynı incident içinde toplanmaya başladığında Jira tarafında anlamsız ve yönetilemeyen task’lar oluşuyordu.
İlk yaklaşımım prompt’u biraz daha iyileştirmek oldu ancak kısa sürede problemin prompt kalitesinden daha büyük olduğunu fark ettim. Çünkü modelin doğal davranışı, birden fazla problemi ayrı operational incident’lar olarak ayırmak yerine hepsini tek bir genel özet altında toplamaya çalışmaktı.
Several backend failures detected across multiple services...
Bu yüzden extraction yaklaşımını tamamen değiştirdim. Pipeline artık tek bir summary üretmek yerine batch içinden birden fazla operational candidate çıkarmaya başladı. Böylece aynı batch içinde bulunan farklı problemler ayrı candidate incident’lara dönüştürülebiliyordu.
Prompt parçası:
Do not summarize the entire batch.
Extract operationally distinct incidents separately.
Return one candidate per operational problem.
Single Batch
↓
Candidate 1 → Payment capture declined
Candidate 2 → TLS certificate expiration warning
Candidate 3 → Inventory API timeout
Bu yapı için V2 contract tasarlandı ve AI’dan artık şu davranış beklenmeye başladı:
- batch’i tek problem gibi yorumlamak yerine operational olarak ayrıştırması,
- her problemi ayrı candidate olarak üretmesi,
- her candidate için severity, category, confidence ve matching_terms döndürmesi,
- semantic olarak benzer logları aynı candidate altında toplaması.
Buradaki zorlayıcı kısım extraction semantics tarafıydı. Çünkü model doğal olarak “özetleme” davranışına kayıyordu. Örneğin payment timeout, TLS warning ve webhook validation failure aynı response içinde “multiple backend problems detected” gibi tek bir cümleye dönüşebiliyordu.
Bu davranışı kırabilmek için prompt yapısını tamamen değiştirdim. Özellikle:
- incident decomposition kuralları,
- strict segmentation beklentisi,
- positive / negative extraction örnekleri,
- candidate isolation mantığı
prompt’un merkezine taşındı.
Amaç artık “batch’i anlatan bir açıklama” üretmek değil, batch içindeki operasyonel problemleri birbirinden ayırabilmekti.
Bu değişiklikten sonra sistemin davranışı da farklılaşmaya başladı. Aynı batch içinde bulunan payment failure, inventory timeout veya TLS warning gibi problemler artık ayrı candidate incident’lar olarak üretilmeye başladı. Bu da fingerprinting, incident reuse ve Jira orchestration tarafının çok daha anlamlı çalışmasını sağladı.
6. Operational Fingerprinting, Similarity ve Deduplication
Multi-candidate extraction yapısı oturduktan sonra bu kez farklı bir problem ortaya çıkmaya başladı. Sistem artık batch içindeki problemleri ayırabiliyordu ancak aynı operasyonel problemi her oluştuğunda yeni incident gibi algılamaya devam ediyordu.
Özellikle mock producer tarafında satır numarası, trace id, request id veya timestamp gibi alanlar sürekli değiştiği için aynı hata davranışı farklı fingerprint’ler üretmeye başlıyordu. Bu durum kısa sürede duplicate incident ve duplicate Jira task problemine dönüştü.
İlk yaklaşımım ham log içeriği üzerinden hash üretmekti ancak bunun gerçek sistem davranışı için yeterli olmadığını fark ettim. Çünkü operasyonel olarak aynı problemi temsil eden iki log satırı, teknik olarak tamamen farklı string’lere sahip olabiliyordu.
Bu yüzden fingerprinting yaklaşımını raw text eşitliği yerine operational meaning üzerine kurmaya karar verdim.
Raw Logs
↓
Normalization
↓
Volatile Token Cleanup
↓
Operational Signature
↓
Stable Fingerprint
Pipeline artık fingerprint üretmeden önce logları normalize etmeye başladı. Timestamp, trace id, request id, span id veya volatile numeric değerler temizleniyor, ardından daha stabil operational signature üretilecek şekilde sadeleştiriliyordu.
Özellikle şu tip alanlar duplicate davranışını ciddi şekilde bozuyordu:
trace_id=8f21...
request_id=91ab...
line:184
duration_ms=4213
Bu alanlar operasyonel problemi değiştirmediği halde hash çıktısını tamamen değiştiriyordu.
Normalizasyon sonrasında sistem yalnızca metin eşitliğine bakmak yerine operational similarity üretmeye başladı. Örneğin:
Timeout while calling InventoryApi
ve
InventoryApi request exceeded timeout threshold
aynı operasyonel problemi temsil edebiliyordu.
Bu noktada AI classification çıktıları da fingerprinting tarafını beslemeye başladı. Özellikle normalized operational title, category ve possible root cause alanları incident similarity tarafında önemli hale geldi.
Bu yaklaşım sayesinde sistem aynı operasyonel problemi tekrar oluştuğunda yeni incident üretmek yerine mevcut incident’i güncelleyebilmeye başladı. Occurrence count artırılıyor, incident yaşam döngüsü korunuyor ve Jira tarafında duplicate task oluşumu büyük ölçüde engelleniyordu.
Buradaki amaç birebir string eşitliği yakalamak değil, operasyonel olarak aynı davranışı temsil eden olayları aynı incident altında toplayabilmekti.

raw text ≠ operational meaning

7. Candidate-to-Log Assignment Heuristics
Multi-candidate extraction sonrasında pipeline artık aynı batch içinden birden fazla operational incident üretebiliyordu. Ancak bu kez başka bir problem ortaya çıktı. AI candidate’ları üretse bile batch içindeki log satırlarının hangi candidate’a ait olduğunun belirlenmesi gerekiyordu.
İlk bakışta bu problem basit görünse de pratikte oldukça kritik hale geldi. Çünkü yanlış candidate eşleşmeleri doğrudan fingerprinting, incident similarity ve Jira orchestration davranışını etkiliyordu. Özellikle aynı batch içinde timeout, dependency failure ve validation problemi birlikte bulunduğunda bazı log satırları birden fazla candidate ile ilişkili hale gelebiliyordu.
Bu yüzden candidate assignment tarafında lightweight heuristic yaklaşım kullandım. AI response içindeki matching_terms alanları extraction sonrasında scoring mekanizmasını beslemeye başladı. Her log satırı candidate’ların matching_terms listesi ile karşılaştırılıyor ve en yüksek semantic eşleşmeye sahip candidate’a atanıyordu.
Örneğin InventoryApi timeout candidate’ı şu terimleri içeriyorsa:
timeout
InventoryApi
TaskCanceledException
pipeline ilgili log satırlarında bu terimlerin geçiş yoğunluğunu kullanarak assignment score üretiyordu.

Ancak gerçek trafik altında bazı log satırlarının hiçbir candidate ile güçlü eşleşme üretmediğini fark ettim. Özellikle generic exception veya infrastructure noise içeren satırlar score=0 durumuna düşebiliyordu. Bu noktada assignment davranışının rastgele çalışmaması gerekiyordu çünkü aynı batch farklı çalıştırmalarda farklı incident dağılımı üretebilirdi.
Bu yüzden deterministic fallback davranışı ekledim. Eğer bir log satırı hiçbir candidate ile anlamlı eşleşme üretmiyorsa pipeline önce severity seviyesi daha yüksek olan candidate’ı, eşitlik durumunda confidence değeri daha yüksek olan candidate’ı, o da eşitse candidate index sırasını kullanıyordu.
score = 0
↓
highest severity
↓
highest confidence
↓
lowest candidate index
Bu yaklaşım sayesinde assignment davranışı deterministik hale geldi ve aynı operasyonel batch tekrar işlendiğinde candidate dağılımı stabil çalışmaya başladı.
Buradaki amaç mükemmel semantic clustering üretmek değil, explainable ve tekrar edilebilir operational grouping davranışı elde etmekti.
8. Batch Candidate Cache Persistence
Multi-candidate extraction yapısı çalışmaya başladıktan sonra bu kez performans ve maliyet tarafı problem olmaya başladı. Çünkü aynı batch tekrar işlendiğinde sistem yeniden OpenAI çağrısı yapıyor, aynı candidate extraction sürecini tekrar çalıştırıyor ve aslında değişmeyen bir veri için yeniden token harcıyordu.
Özellikle periodic pipeline çalıştıkça aynı operasyonel batch’lerin kısa aralıklarla tekrar oluştuğunu fark ettim. Incident reuse tarafı duplicate Jira oluşumunu engelliyordu ancak AI extraction katmanı hâlâ gereksiz şekilde tekrar çalışıyordu.
Bu yüzden extraction sonucunu batch seviyesinde cache’lemeye karar verdim.
Pipeline artık batch içeriği için stable batch hash üretiyor ve AI’dan dönen candidate response bu hash ile birlikte persistence katmanında saklanıyor.
Batch Logs
↓
Stable Batch Hash
↓
Cache Lookup
↓
(Cache miss)
↓
OpenAI Extraction
↓
Persist Candidates
Aynı batch tekrar işlendiğinde sistem yeniden extraction yapmak yerine mevcut candidate sonucunu doğrudan yükleyebiliyor.
Bu yaklaşım yalnızca maliyet optimizasyonu sağlamadı. Aynı zamanda extraction davranışını da daha deterministik hale getirdi. Çünkü aynı batch’in farklı zamanlarda yeniden analyze edilmesi durumunda model küçük semantic farklılıklar üretebiliyordu. Cache kullanımı sayesinde aynı operational input aynı candidate set’ini üretmeye başladı.
Persistence tarafında yalnızca raw AI response saklamak istemedim çünkü contract yapısı ve extraction davranışı zamanla değişebiliyordu. Bu yüzden cache katmanında contract version bilgisi de tutulmaya başladı.

Bu yapı sayesinde sistem yalnızca incident seviyesinde değil, extraction seviyesinde de duplicate çalışmayı azaltmaya başladı.
9. Async Jira Orchestration ve Resilience Katmanı
Incident pipeline operasyonel olarak anlamlı hale geldikten sonra sıradaki problem bu incident’ların nasıl yönetileceği oldu. Başlangıçta Jira task oluşturma işlemini doğrudan analiz akışının içinde çalıştırıyordum ancak kısa sürede bunun sürdürülebilir olmadığını fark ettim. Çünkü dış sistem bağımlılıkları, timeout problemleri veya geçici ağ hataları tüm pipeline’ı etkileyebiliyordu.
Bu yüzden Jira entegrasyonunu analiz akışından ayırıp async outbound workflow mimarisine taşıdım.
Pipeline artık incident oluşturduğunda doğrudan Jira çağrısı yapmıyor, önce bounded queue yapısına enqueue ediyor. Ardından hosted dispatcher arka planda bu işleri kontrollü şekilde işleyerek Jira REST API tarafına gönderiyor.
Incident
↓
Outbound Queue
↓
Hosted Dispatcher
↓
Retry Policy
↓
Jira REST API
Bu yaklaşımın önemli avantajlarından biri incident extraction pipeline’ını dış sistemlerden izole etmek oldu. Jira tarafında timeout veya rate limit problemi oluşsa bile incident analizi çalışmaya devam edebiliyordu.
Dispatcher tarafında retry ve timeout davranışlarını da ayrı yönettim. Özellikle transient HTTP hataları ile permanent validation hatalarını farklı sınıflandırmak önemli hale geldi. Örneğin 429, 502 veya timeout gibi durumlarda retry mekanizması devreye girerken, invalid payload veya authentication problemleri tekrar denenmiyordu.
Bu davranış zamanla deterministik payload üretimini de önemli hale getirdi. Çünkü aynı incident farklı retry denemelerinde farklı içerik üretirse duplicate veya anlamsız Jira task’ları oluşabiliyordu. Bu yüzden payload generation tarafında:
- stable field ordering,
- deterministic formatting,
- controlled truncation
kullanmaya başladım.
Queue tarafında dikkat ettiğim başka bir konu da sistemin baskı altında nasıl davranacağı oldu. Özellikle queue overflow durumunda pipeline’ın tamamen kilitlenmesini istemedim. Bu yüzden bounded queue yaklaşımı kullanarak kontrollü backpressure davranışı ekledim.
Ayrıca graceful shutdown desteği de ekledim. Sistem kapanırken dispatcher yarım kalan işleri kontrollü şekilde tamamlıyor, işlenmeyen queue item’ları telemetry üzerinden raporlanıyor ve pipeline state’i gözlemlenebilir hale geliyor.
Request
↓
Timeout?
↓ yes
Retry
↓
Retry Exhausted?
↓
Warning / Telemetry
Bu aşamadan sonra Jira entegrasyonu yalnızca “task açan bir servis” olmaktan çıkıp, retry davranışı, queue yönetimi ve operational resilience kuralları olan ayrı bir orchestration katmanına dönüşmeye başladı.
10. OpenTelemetry, Diagnostics ve .NET Aspire
Pipeline karmaşıklaştıkça sistemin yalnızca çalışması değil, gözlemlenebilir olması da kritik hale gelmeye başladı. Özellikle AI extraction, candidate decomposition, fingerprinting, queue orchestration ve retry davranışları devreye girdikten sonra “bir şey neden böyle çalıştı?” sorusunun cevabını log okuyarak bulmak yeterli olmamaya başladı.
Bu yüzden pipeline’ın farklı katmanlarını OpenTelemetry tabanlı tracing ve custom operational telemetry ile izlenebilir hale getirdim.
Özellikle extraction tarafında:
- candidate count,
- parse mode,
- repair attempt,
- fallback usage,
- fingerprint identity,
- retry attempt,
- queue state
gibi bilgiler telemetry event’leri üzerinden takip edilmeye başladı.
AI Extraction
↓
Candidate Generation
↓
Fingerprinting
↓
Queue Enqueue
↓
Jira Dispatch
Bu yapı sayesinde yalnızca hata durumlarını değil, pipeline’ın davranışını da izleyebilir hale geldim. Örneğin bir batch neden fallback pipeline’a düştü, hangi extraction sonucu duplicate incident’e dönüştü veya hangi retry davranışı queue baskısı oluşturdu gibi sorular telemetry üzerinden takip edilebilir hale geldi.
Özellikle AI tarafında observability önemli hale geldi çünkü model davranışı deterministik değildi. Prompt değişiklikleri, contract evrimi veya extraction semantics tarafındaki küçük değişiklikler pipeline davranışını doğrudan etkileyebiliyordu. Bu yüzden malformed response, repair attempt veya fallback senaryolarını ayrı telemetry etiketleri ile işaretlemeye başladım.
Süreç ilerledikçe yalnızca tracing değil, extraction diagnostics tarafı da önemli hale geldi. Candidate assignment davranışı, score=0 fallback senaryoları veya incident reuse kararları pipeline içinde ayrı diagnostic event’ler üretmeye başladı.
Bu noktada .NET Aspire entegrasyonu da faydalı hale geldi. Başlangıçta tüm sistemi container orchestration tarafına taşımayı düşünsem de süreç içinde Aspire’ı daha çok local orchestration, service visibility ve observability katmanı olarak kullanmaya başladım.
Aspire dashboard üzerinden:
- API davranışı,
- retry akışları,
- outbound queue,
- telemetry event’leri,
- distributed trace zinciri
tek noktadan izlenebilir hale geldi.
Mock Traffic
↓
AI Pipeline
↓
Incident Processing
↓
Outbound Queue
↓
Jira Integration
Bu aşamadan sonra sistem yalnızca çalışan bir pipeline olmaktan çıkıp, davranışı izlenebilir ve teşhis edilebilir bir operasyon platformuna dönüşmeye başladı.

11. Synthetic Traffic ve Test Stratejisi
Pipeline operasyonel olarak karmaşıklaştıkça en büyük problemlerden biri gerçek sistem davranışını tekrar üretmek oldu. Çünkü timeout, dependency failure, payment rejection veya TLS warning gibi olaylar gerçek ortamda düzensiz oluşuyordu ve aynı problemi kontrollü şekilde yeniden üretmek zorlaşıyordu.
Bu yüzden test sürecini yalnızca unit test seviyesinde bırakmak yerine synthetic traffic producer yaklaşımına geçtim.
Mock Producer
↓
Graylog
↓
Periodic Pipeline
↓
AI Extraction
↓
Candidate Incidents
↓
Jira Queue
Mock producer başlangıçta yalnızca rastgele log üreten basit bir yapıydı. Ancak süreç ilerledikçe operational scenario tabanlı çalışmaya başladı. Sistem artık payment failure, webhook validation failure, transient database timeout, inventory latency veya TLS expiration warning gibi farklı davranışları kontrollü şekilde üretebiliyordu.
Özellikle multi-candidate extraction geliştirmeleri sırasında deterministic multi-problem batch üretimi önemli hale geldi. Çünkü aynı batch içinde birden fazla operasyonel problemi tekrar tekrar üretebilmek gerekiyordu.
Örneğin aşağıdaki batch aynı operational davranışı deterministik şekilde tekrar oluşturabiliyordu:
[high] Payment capture declined at PaymentOrchestrator
[medium] InventoryApi request exceeded timeout threshold
[low] TLS certificate expiration warning detected
Bu yaklaşım sayesinde extraction semantics, candidate decomposition ve fingerprinting davranışlarını aynı input üzerinde tekrar test edebilir hale geldim.
Süreç ilerledikçe evaluation metadata yaklaşımı da önemli hale geldi. Mock producer tarafından üretilen loglara:
eval_severity=critical
eval_scenario_kind=payment_failure
eval_incident_profile=user_impacting_failure
gibi alanlar eklemeye başladım.
Ancak burada dikkat ettiğim önemli nokta, bu alanların production classification pipeline’ını doğrudan beslememesi oldu. Çünkü amaç modele “cevabı vermek” değil, extraction davranışını sonradan değerlendirebilmekti. Pipeline’ın operational reasoning davranışı hâlâ gerçek log içeriği üzerinden çalışıyordu.
Test tarafında yalnızca extraction doğruluğunu değil, resilience davranışını da ölçmeye başladım. Özellikle queue overflow, retry exhaustion, timeout davranışı, graceful shutdown ve dispatcher recovery senaryoları ayrı test akışlarına dönüştü.
Queue Full
↓
Backpressure
↓
Retry
↓
Retry Exhausted
↓
Telemetry Warning
Bu süreçte fark ettiğim önemli şeylerden biri, AI destekli sistemlerde test probleminin yalnızca “çıktı doğru mu?” sorusu olmadığıydı. Asıl problem aynı operational davranışı tekrar üretip üretememekti.
Bu yüzden deterministic traffic generation ve explainable heuristics yaklaşımı, pipeline’ın en kritik parçalarından biri haline geldi.
12. Explainable / Lightweight Incident Intelligence
Faz ilerledikçe fark ettiğim en önemli şeylerden biri, problemin aslında “AI kullanmak” olmadığıydı. Gerçek problem, operasyonel olarak anlamlı davranış üretebilen bir sistem tasarlamaktı. Yıllarca operasyona destek veren L3 görevinin yanında ekip lideri olarak ürün ekibi ile sprint planlaması yaptığım için, gelen logların işe dönüşmesi için hangi yollardan geçmesi gerektiğini planlayabiliyorum.
Başlangıçta daha karmaşık çözümler düşünmüştüm. Embedding tabanlı similarity, vector database kullanımı veya tamamen semantic clustering yapan yapılar ilk bakışta daha modern görünüyordu. Ancak sistem büyüdükçe production tarafında başka ihtiyaçların daha önemli hale geldiğini fark ettim.
Çünkü operasyonel sistemlerde yalnızca doğru sonuca yaklaşmak yetmiyor. Aynı zamanda:
- neden o sonucun oluştuğunu açıklayabilmek,
- aynı input için benzer davranış üretebilmek,
- incident grouping davranışını kontrol edebilmek,
- gerektiğinde sistemi debug edebilmek
de gerekiyor.
Bu yüzden pipeline’ı tamamen “black box AI reasoning” üzerine kurmak yerine explainable ve lightweight bir yaklaşım tercih ettim.
Örneğin sistem bir timeout problemini aynı incident altında topluyorsa bunun nedeni:
- matching_terms eşleşmesi,
- normalized operational title,
- stable fingerprint üretimi,
- candidate assignment score’u
gibi izlenebilir kurallara dayanıyordu.
Raw Logs
↓
AI Extraction
↓
Operational Candidate
↓
Heuristic Matching
↓
Stable Fingerprint
↓
Incident Identity
Bu yaklaşımın önemli avantajlarından biri de pipeline davranışının zamanla kontrolsüz şekilde drift etmemesi oldu. Çünkü tamamen semantic similarity kullanan yapılarda küçük model değişiklikleri bile incident grouping davranışını ciddi şekilde değiştirebiliyor.
Benim hedefim “insan gibi düşünen tam otonom sistem” üretmekten çok, operasyonel olarak anlamlı davranışlar sergileyen ve davranışı açıklanabilir kalan bir pipeline oluşturmaktı.
Bu yüzden AI tarafını tamamen merkezde konumlandırmak yerine:
- AI extraction,
- deterministic heuristics,
- operational fingerprinting,
- controlled orchestration
birlikte çalışacak şekilde tasarladım.
Süreç ilerledikçe şunu fark ettim: Production ortamında en değerli şey çoğu zaman en akıllı sistem değil, davranışı anlaşılabilir kalan sistem oluyor.
Ve açıkçası Faz 4 boyunca en fazla zaman harcadığım konu da modelin daha “zeki” olması değil, pipeline’ın daha tutarlı davranması oldu.
13. Faz 4 Sonunda Ortaya Çıkan Pipeline
Fazın başında hedef yalnızca logları analiz edip anlamlı özetler üretebilmekti. Süreç ilerledikçe yapı, AI destekli incident extraction, operational fingerprinting, async orchestration ve observability katmanları olan daha büyük bir pipeline’a dönüştü.
Son durumda sistemin akışı şu hale geldi:
Mock Traffic
↓
Graylog
↓
Periodic Log Pipeline
↓
AI Incident Extraction
↓
Multi-Candidate Decomposition
↓
Candidate Assignment
↓
Operational Fingerprinting
↓
Incident Reuse
↓
Async Jira Queue
↓
Hosted Dispatcher
↓
Jira Backlog
Bu yapının önemli taraflarından biri, pipeline’ın artık yalnızca “log yorumlayan” bir sistem olmamasıydı. AI extraction katmanı operasyonel problemleri ayırıyor, fingerprinting aynı problemi tekrar tanıyabiliyor, orchestration katmanı ise incident lifecycle davranışını yönetebiliyordu.
Özellikle multi-candidate extraction sonrası sistemin davranışı ciddi şekilde değişti. Başlangıçta aynı batch içindeki problemler tek bir Jira task altında birleşirken, son durumda operasyonel olarak farklı davranan problemler ayrı incident’lara dönüşmeye başladı.
Eski yaklaşım daha çok şu davranışı üretiyordu:
1 Batch
↓
1 Summary
↓
1 Jira Task
Yeni yapı ise operational decomposition odaklı çalışıyordu:
1 Batch
↓
N Operational Candidates
↓
N Incident
↓
N Jira Task
Ancak burada amaç mümkün olduğunca fazla task üretmek değildi. Asıl hedef aynı operasyonel problemi tekrar tekrar açmadan, gerçekten farklı davranan incident’ları ayırabilmekti.
Bu yüzden pipeline yalnızca AI extraction üzerine kurulmadı. Candidate assignment heuristics, stable fingerprint üretimi, incident similarity ve deterministic orchestration davranışları birlikte çalışacak şekilde tasarlandı.
Süreç boyunca dikkat ettiğim önemli noktalardan biri de sistemin tamamen autonomous davranmaması oldu. Pipeline operasyonel bağlam üretiyor, incident’ları ayırıyor ve backlog oluşturuyor ancak son karar hâlâ insan tarafında kalıyor.
Çünkü özellikle production ortamında tamamen otomatik karar veren sistemlerden çok, anlamlı bağlam üretebilen sistemlerin daha sürdürülebilir olduğunu düşünüyorum.
Bu fazın sonunda ortaya çıkan yapı tam anlamıyla bitmiş bir ürün değil. Ancak AI destekli operational incident management tarafında oldukça güçlü bir temel oluşturduğunu düşünüyorum.


14. Sonuç: AI Sistemlerde Asıl Problem
Fazın başında problemi daha çok teknik bir entegrasyon problemi gibi görüyordum. Logları toplayıp AI ile yorumlamak, ardından anlamlı çıktılar üretmek yeterli olacakmış gibi görünüyordu. Süreç ilerledikçe bunun aslında çok daha fazla “davranış yönetimi” problemi olduğunu fark ettim.
Özellikle production tarafında aynı problemin farklı şekillerde ortaya çıkması, AI’ın benzer olayları bazen farklı yorumlaması veya birbirinden bağımsız problemleri aynı incident altında toplaması sistemin davranışını doğrudan etkiliyordu.
Bu yüzden zamanla odak noktam modelden çok pipeline davranışı olmaya başladı.
En fazla zamanı:
- extraction semantics,
- operational grouping,
- fingerprinting,
- deterministic orchestration,
- explainable heuristics
gibi konular aldı.
Çünkü gerçek problem AI’ın bir logu açıklayabilmesi değil, aynı operasyonel davranışı tekrar tanıyabilmesiydi.
Süreç boyunca özellikle şunu fark ettim: Production ortamında tamamen autonomous çalışan sistemler tasarlamaktan çok, davranışı anlaşılabilir kalan sistemler oluşturmak daha sürdürülebilir oluyor.
Bu yüzden Faz 4 boyunca AI tarafını tek başına karar veren bir yapı haline getirmek yerine, deterministic heuristics ve operational kurallarla birlikte çalışan bir katman olarak konumlandırmaya çalıştım.
Eğer bu yapıyı geliştirmeye devam etseydim, bir sonraki odak noktam pipeline’ın operasyonel görünürlüğünü ve orchestration yeteneklerini artırmak olurdu. Özellikle UI tarafında incident dashboard’ları, AI trace görüntüleme, observability ekranları ve cost/token tracking gibi katmanlar bu yapının doğal devamı gibi duruyor.
Daha uzun vadede ise multi-agent architecture yaklaşımı, GitHub remediation akışları, otomatik PR generation süreçleri ve controlled approval flow içeren agentic workflow’ler ilginç bir evrim alanı olabilir.
Ama Faz 4 sonunda benim için en önemli kazanım, AI’ın logları yorumlamasından çok, operasyonel anlam üretebilen bir pipeline’ın nasıl evrildiğini görmek oldu.
Ortaya çıkan bu Incident Intelligence Pipeline, AI’ın operasyonel süreçlerde yalnızca bir “sohbet aracı” değil; anlam çıkarabilen, ayıklama yapabilen ve güvenilir bağlam üretebilen bir yardımcı katman olarak konumlanabileceğini bana gösterdi.
Logların içindeki kaosu operasyonel bir anlama dönüştürebilmek, bu projenin benim için en tatmin edici tarafı oldu.
Gelecek Yol Haritası (Eğer Devam Etseydim)
- Faz 5: Görünürlük ve Maliyet Optimizasyonu: Bir sonraki adımda tamamen UI/Dashboard tarafına odaklanarak; AI trace’lerini görselleştirmek, token kullanım maliyetlerini anlık takip etmek ve operasyonel metrikleri (observability) bir arayüz üzerinden yönetmek mümkündü.
- Faz 6: Otonom Müdahale (Self-Healing): En heyecan verici adım ise Multi-Agent mimarisine geçiş olurdu. Sadece Jira task’ı açan değil; GitHub ile entegre olup hata için otomatik PR (Pull Request) çıkartan, iyileştirme (remediation) önerilerini otonom iş akışlarıyla (approval flow) yöneten bir yapı bu mimarinin doğal bir uzantısı olarak kurgulanabilirdi. Biz canlı bir sistemden hata almayıp mock ile ürettiğimiz için GitHub düzeltme işlemini bu projede yapamayacağız.
Kapanış
Millet olarak bir huyumuz var, maliyeti öğrenmezsek kafamız rahat etmiyor. OpenAI API tarafı için; bu geliştirme için toplamda 13 istek göndermişim ve 18k token harcamışım. Bunun değeri olarak da $0.01 olarak maliyet çıkardı bana.
Yazmak yapmaktan bin kere zordu ama umarım faydalı olmuştur. Okuyan herkese teşekkür ederim, kendine yatırım yapan herkese selamlar olsun…
메타데이터
- post_id
- 327fe62f7ae2
- slug
- net-ile-ai-destekli-log-analiz-servisi-faz-4-incident-intelligence-multi-candidate-extraction-327fe62f7ae2
- url
- https://medium.com/@a.melihtuna/net-ile-ai-destekli-log-analiz-servisi-faz-4-incident-intelligence-multi-candidate-extraction-327fe62f7ae2
- canonical_url
- https://medium.com/@a.melihtuna/net-ile-ai-destekli-log-analiz-servisi-faz-4-incident-intelligence-multi-candidate-extraction-327fe62f7ae2
- author_url
- https://medium.com/@a.melihtuna
- status
- ok
- fetched_at
- 2026-06-15 20:49:13