ASP.NET Core eğitiminde yüksek trafikli servislerin log maliyetini LoggerMessage source generator, dotnet-counters ve yapılandırılmış olay şemalarıyla nasıl ölçüp düşüreceğinizi uygulamalı olarak inceleyin.
ASP.NET Core Eğitimi: LoggerMessage ile Ölçülebilir Log Maliyeti
ASP.NET Core eğitimi: Log satırının gerçek maliyetini ayırmak
Yüksek trafikli bir endpoint'te log maliyeti yalnızca diske veya merkezi log platformuna gönderilen byte miktarı değildir. Log seviyesi Information kapalı olsa bile string interpolation, metodu çağırmadan önce string ve geçici nesne üretir. Bu nedenle klasik kullanımda _logger.LogInformation($"Order {orderId} accepted"), sağlayıcı bu kaydı yazmayacak olsa dahi interpolation çalıştırır. Bir .net core eğitimi kapsamında bu ayrımı görmek için önce çağrı sayısını ve tahsis oranını ölçmek gerekir; aksi halde sadece log platformundaki indeks maliyetine bakıp uygulama içi GC baskısını kaçırırsınız.
public sealed class OrdersService(ILogger<OrdersService> logger)
{
public void Accept(string orderId)
{
// Information kapalı olsa dahi interpolation bu satıra gelmeden çalışır.
logger.LogInformation($"Order {orderId} accepted");
}
}İlk baz ölçüm için uygulamayı temsilci trafikla çalıştırın ve işlem kimliğini kullanarak sayaçları izleyin. dotnet-counters monitor --process-id 12345 System.Runtime Microsoft.AspNetCore.Hosting komutunda özellikle allocation rate, GC Heap Size ve Gen 0 GC Count değerlerini istek hızıyla birlikte kaydedin. Aynı senaryoda Information seviyesini önce kapatıp sonra açın. Allocation rate iki durumda benzer kalıyorsa, maliyetin önemli bölümü sink'ten değil çağrı noktasındaki interpolation ve parametre paketlemesinden geliyordur.
C# eğitimi: LoggerMessage source generator ile şablon derlemek
LoggerMessage source generator, log şablonunu ve seviye kontrolünü derleme zamanında üretilen bir metoda taşır. Böylece sıcak yolda object[] parametre dizisi, boxing ve interpolation oluşmaz. Olay kimliğini sabit tutmak da sorgu yazarken metne bağımlılığı azaltır: örneğin merkezi log sisteminde EventId=1201 ile sürümden bağımsız filtre uygulanabilir. Aşağıdaki kodda exception, şablondaki bir alan değildir; sağlayıcının exception kanalına ayrı taşınır ve stack trace doğru biçimde korunur.
internal static partial class OrderLog
{
[LoggerMessage(
EventId = 1201,
Level = LogLevel.Information,
Message = "Order accepted. OrderId={OrderId} TenantId={TenantId}")]
internal static partial void Accepted(
ILogger logger,
string orderId,
string tenantId);
[LoggerMessage(
EventId = 1202,
Level = LogLevel.Warning,
Message = "Payment authorization failed. OrderId={OrderId} Provider={Provider}")]
internal static partial void PaymentFailed(
ILogger logger,
string orderId,
string provider,
Exception exception);
}
public sealed class OrdersService(ILogger<OrdersService> logger)
{
public void Accept(string orderId, string tenantId)
=> OrderLog.Accepted(logger, orderId, tenantId);
}Bu yaklaşım bir csharp eğitimi veya c# eğitimi içinde özellikle hot path analiziyle birlikte ele alınmalıdır: generator yalnızca sabit log şablonlarında kazanç sağlar. Kullanıcıdan gelen metni şablon olarak vermek hem şema patlamasına hem de arama alanlarının tutarsızlaşmasına neden olur. Örneğin logger.LogInformation(userInput) yerine kullanıcı girdisini sabit bir şablonun alanı yapın: logger.LogInformation("User action received. Action={Action}", userInput). Ayrıca alan adlarında OrderId ile order_id gibi iki farklı yazım kullanmak, Elasticsearch, Seq veya Application Insights sorgularında iki ayrı alan üretir.
.NET Core kursu için önce-sonra benchmark ve üretim profili
Mikro benchmark'ta iki yaklaşımı aynı log seviyesinde karşılaştırın. BenchmarkDotNet'te NullLogger kullanmak sink I/O'sunu devre dışı bırakır ve çağrı noktasındaki CPU ile allocation farkını izole eder. Information kapalı senaryosu kritik olmalıdır; gerçek servislerde debug ve information çoğu ortamda seçici olarak kapatılır. Ölçüm sonucunda yalnızca ortalama süreyi değil, BenchmarkDotNet'in raporladığı Allocated sütununu karşılaştırın.
[MemoryDiagnoser]
public class LoggingBenchmarks
{
private readonly ILogger _logger = NullLogger.Instance;
private const string OrderId = "ord-421";
[Benchmark(Baseline = true)]
public void Interpolated()
=> _logger.LogInformation($"Order {OrderId} accepted");
[Benchmark]
public void SourceGenerated()
=> OrderLog.Accepted(_logger, OrderId, "tenant-a");
}Projeyi dotnet run -c Release -- --filter *LoggingBenchmarks* ile çalıştırın. Ardından aynı değişikliği gerçek API'de doğrulamak için sabit bir yük üretin: wrk -t4 -c128 -d60s http://localhost:5000/orders/42. Değişiklik öncesi ve sonrası için istek sayısı, p95 gecikme ve dotnet-counters allocation rate çıktısını aynı trafik profili altında kaydedin. Bu, bir .net core kursu laboratuvarında source generator'ın sentetik testteki kazanımının endpoint, JSON serileştirme ve veritabanı maliyetleri yanında anlamlı olup olmadığını gösterir. Loglama CPU'nun küçük bir yüzdesiyse her çağrıyı dönüştürmek yerine en sıcak endpoint'lerden başlayın.
Microsoft teknolojileri eğitimi: Scope, trace bağlamı ve veri sınırı
Tek bir istek içindeki tüm olaylara OrderId eklemek için her log çağrısına parametre geçirmek yerine scope kullanın. JSON console sağlayıcısında scope'ları görünür kılmak için yapılandırmayı açıkça etkinleştirin. Dağıtık iz sürmede ayrıca Activity.Current?.TraceId alanını log olayına yazmak, OpenTelemetry trace görünümü ile log aramasını bağlar. Scope'un yanlış kullanımı önemli bir edge case'tir: büyük bir domain nesnesini scope'a koymak, sağlayıcının onu her satırda serileştirmesine ve yanlışlıkla PII alanlarının dışarı çıkmasına yol açar.
builder.Logging.AddJsonConsole(options =>
{
options.IncludeScopes = true;
options.TimestampFormat = "O";
});
app.MapPost("/orders/{orderId}", async (
string orderId,
ILogger<Program> logger,
CancellationToken cancellationToken) =>
{
using var scope = logger.BeginScope(new Dictionary<string, object?>
{
["OrderId"] = orderId,
["TraceId"] = Activity.Current?.TraceId.ToString()
});
logger.LogInformation("Order processing started");
await Task.Delay(10, cancellationToken);
return Results.Accepted();
});Kimlik doğrulama belirteci, Authorization başlığı, kart numarası ve ham istek gövdesini log şemasına hiç dahil etmeyin. ASP.NET Core HTTP logging kullanılıyorsa yalnızca inceleme için gereken başlıkları allowlist ile seçin; örneğin RequestHeaders.Add("X-Correlation-ID") ve ResponseHeaders.Add("X-Request-ID") ekleyip Authorization eklemeyin. Bu sınır, asp.net core eğitimi materyalinde middleware sırasıyla birlikte test edilmelidir: HTTP logging middleware'i kimlik doğrulama middleware'inden önce yer alırsa istenmeyen başlıkların görünürlüğü sağlayıcı ayarlarına göre değişebilir.
Entity Framework eğitimi ve Blazor eğitimi ekipleri için olay sözleşmesi
Log olayını serbest metin değil, geriye dönük uyumlu bir sözleşme olarak yönetin. entity framework eğitimi alan ekipler için SQL komutunun tamamını production Information seviyesinde açmak yerine sorgu süresi, etkilenen satır sayısı ve repository operasyon adını kaydetmek daha denetlenebilirdir. EF Core tarafında yalnızca yavaş komutları yakalamak için DbCommandInterceptor içinde Stopwatch.GetTimestamp() ile süre ölçüp, örneğin 500 ms üstündeki komutlarda EventId 2401 üretin. Parametre değerlerini loglamayın; kişisel veri ve sorgu planı önbelleği açısından ayırt edici değerler içerebilir.
Bir blazor eğitimi projesinde sunucu tarafı devre kimliğini veya kullanıcı e-postasını her UI olayına scope olarak eklemek yerine kısa ömürlü, rastgele üretilmiş bir interaction id kullanın. İstemci tarafında API'ye X-Correlation-ID gönderin, sunucuda biçimini doğrulayın ve log alanına alın. Böylece UI tıklaması ile API hatası eşleşir, ancak e-posta veya erişim belirteci gözlemlenebilirlik verisine taşınmaz. Bu ayrım hem csharp kursu hem de c# kursu katılımcılarının paylaşılan log sözleşmesini frontend-backend sınırında koruması için uygulanabilir bir pratiktir.
İlgili Eğitim
YTÜSEM İlgili Eğitim
.NET Core ReactJS FullStack Eğitimi (Yıldız Teknik Üniversitesi SEM)
Sık Sorulan Sorular
ASP.NET Core eğitiminde LoggerMessage ne zaman LogInformation yerine kullanılmalı?
Saniyede çok sayıda çalışan endpoint, döngü içi işlem ve Information seviyesi zaman zaman kapatılan servislerde sabit şablonlu kayıtlar için kullanın. Kararı BenchmarkDotNet ile Allocated değerini ve production benzeri yükte dotnet-counters allocation rate değerini önce-sonra karşılaştırarak verin. Nadir çalışan yönetim ekranı kayıtlarında dönüşümün getirisi genellikle sınırlıdır.
.net core kursu kapsamında loglama allocation miktarı nasıl ölçülür?
Önce Release derlemesini sabit trafikla çalıştırın, sonra dotnet-counters monitor --process-id
entity framework eğitimi sırasında EF Core SQL parametreleri loglanmalı mı?
Production ortamında varsayılan yaklaşım hayır olmalıdır. Parametreler e-posta, kimlik numarası veya erişim bilgisi içerebilir. Bunun yerine DbCommandInterceptor ile süre, operasyon adı, provider hata kodu ve etkilenen satır sayısını yapılandırılmış alanlar olarak kaydedin. Geliştirme ortamında hassas veri loglamayı açmanız gerekiyorsa bunu yalnızca ortam koşullu konfigürasyonla etkinleştirin ve örnek veri kullanın.
AI / LLM Discovery
Bu makale Opendart Akademi Microsoft / C# eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.


