Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Kaynak tarafından oluşturulan günlük kaydı, modern .NET uygulamaları için yüksek oranda kullanılabilir ve yüksek performanslı bir günlük çözümü sunmak üzere tasarlanmıştır. Otomatik olarak oluşturulan kaynak kodu, ILogger arabirimi ve LoggerMessage.Define işlevselliği ile birlikte çalışır.
Kaynak oluşturucu, günlüğe kaydetme yöntemlerinde LoggerMessageAttribute kullanıldığında tetikleniyorpartial. Tetiklendiğinde, süslediği yöntemlerin partial uygulamasını otomatik olarak oluşturur. Bir sorun varsa, doğru kullanımla ilgili ipuçları içeren derleme zamanı tanılamaları oluşturur. Bu derleme zamanı günlüğe kaydetme çözümü, çalışma zamanında daha önce kullanılabilir günlük yaklaşımlarından çok daha hızlıdır. Kutulama, geçici ayırmalar ve mümkün olan en yüksek ölçüde kopyaları ortadan kaldırır.
Temel kullanım
LoggerMessageAttribute'yi kullanmak için, tüketici sınıfın ve metodun partial olması gerekir. Kod üreteci derleme zamanında tetiklenir ve partial yönteminin bir uygulamasını oluşturur.
public static partial class Log
{
[LoggerMessage(
EventId = 0,
Level = LogLevel.Critical,
Message = "Could not open socket to `{HostName}`")]
public static partial void CouldNotOpenSocket(
ILogger logger, string hostName);
}
Önceki örnekte kayıt yöntemi static ve kayıt düzeyi öznitelik tanımında belirtilmiştir. Statik bağlamda LoggerMessageAttribute kullandığınızda, ILogger örneği bağımsız değişken olarak geçirilmelidir. Alternatif olarak, yöntemini uzantı yöntemi olarak tanımlamak için değiştiriciyi this parametresine ekleyinILogger.
public static partial class Log
{
[LoggerMessage(
EventId = 0,
Level = LogLevel.Critical,
Message = "Could not open socket to `{HostName}`")]
public static partial void CouldNotOpenSocket(
this ILogger logger, string hostName);
}
Özniteliği statik olmayan bir bağlamda da kullanmayı seçebilirsiniz. Loglama yönteminin nesne yöntemi olarak bildirildiği aşağıdaki örneği göz önünde bulundurun. Bu bağlamda, loglama yöntemi, içeren sınıftaki bir ILogger alana erişerek günlükçüyü elde eder.
public partial class InstanceLoggingExample
{
private readonly ILogger _logger;
public InstanceLoggingExample(ILogger logger)
{
_logger = logger;
}
[LoggerMessage(
EventId = 0,
Level = LogLevel.Critical,
Message = "Could not open socket to `{HostName}`")]
public partial void CouldNotOpenSocket(string hostName);
}
.NET 9'dan itibaren, günlüğe kaydetme yöntemi, içeren sınıfın ILogger birincil yapıcı parametresinden logger'ı alabilir.
public partial class InstanceLoggingExample(ILogger logger)
{
[LoggerMessage(
EventId = 0,
Level = LogLevel.Critical,
Message = "Could not open socket to `{HostName}`")]
public partial void CouldNotOpenSocket(string hostName);
}
Hem ILogger alanı hem de birincil oluşturucu parametresi varsa, günlük kaydı metodu günlükçüyü alandan alır.
Dinamik günlük düzeyi
Bazen günlük seviyesinin kodda statik olarak değil, dinamik olması gerekir. Bunu, kayıt seviyesini öznitelikten çıkarıp yerine kayıt yöntemi için bir parametre olarak belirterek yapabilirsiniz.
public static partial class Log
{
[LoggerMessage(
EventId = 0,
Message = "Could not open socket to `{HostName}`")]
public static partial void CouldNotOpenSocket(
ILogger logger,
LogLevel level, /* Dynamic log level as parameter, rather than defined in attribute. */
string hostName);
}
Message özellik
Message ve LoggerMessageAttribute üzerindeki özellik isteğe bağlıdır. Atlarsanız, String.Empty ileti için kullanılır. Ancak, günlük yönteminde karşılık gelen şablon yer tutucuları olmayan parametreler varsa, derleyici SYSLIB1015 uyarısı yayar. Bu parametreler günlük durumunda depolanır, ancak biçimlendirilmiş günlük çıkışında görünmez. Yalnızca günlük durumunu listeleyen yapılandırılmış günlük sağlayıcıları bunları görünür hale getirir.
Günlükleme yöntemi kısıtlamaları
LoggerMessageAttribute ile süslenmiş günlükleme yöntemleri aşağıdaki gereksinimleri karşılamalıdır:
- Günlük tutma yöntemleri
partialvevoiddöndürmelidir. - Günlüğe kaydetme yöntemi adları alt çizgiyle başlamamalıdır.
- Günlük yöntemlerinin parametre adları alt çizgiyle başlamamalıdır.
- Günlük tutma yöntemleri genel tür parametrelerini destekler, ancak C# 13
allows ref structkarşı-kısıtlama desteklenmemektedir. - Günlüğe kaydetme yöntemi parametreleri
params,scopedveyaoutdeğiştiricilerini kullanamaz veref structtüründe olamaz. - Eğer bir günlük yöntemi
staticbelirtilmişse,ILoggerörneği parametre olarak gereklidir.
Kod oluşturma modeli, kodun modern bir C# derleyicisi olan sürüm 9 veya üzeri ile derlendiğine bağlıdır. Dil sürümünü değiştirme hakkında bilgi için bkz. C# dil sürümü oluşturma.
Log yöntemi anatomisi
İmza, ILogger.Log aşağıdaki kod örneğinde gösterildiği gibi ve isteğe bağlı olarak bir LogLeveldeğerini kabul ederException.
public interface ILogger
{
void Log<TState>(
Microsoft.Extensions.Logging.LogLevel logLevel,
Microsoft.Extensions.Logging.EventId eventId,
TState state,
System.Exception? exception,
Func<TState, System.Exception?, string> formatter);
}
Genel bir kural olarak, ILogger, LogLevel ve Exception'nin ilk örnekleri, kaynak kod üreteci tarafından günlük yöntemi imzasında özel olarak ele alınır. Sonraki örnekler, ileti şablonunda normal parametreler olarak değerlendirilir:
// This is a valid attribute usage
[LoggerMessage(
EventId = 110, Level = LogLevel.Debug, Message = "M1 {Ex3} {Ex2}")]
public static partial void ValidLogMethod(
ILogger logger,
Exception ex,
Exception ex2,
Exception ex3);
// This causes a warning
[LoggerMessage(
EventId = 0, Level = LogLevel.Debug, Message = "M1 {Ex} {Ex2}")]
public static partial void WarningLogMethod(
ILogger logger,
Exception ex,
Exception ex2);
Önemli
Gösterilen uyarılar, doğru kullanımıyla LoggerMessageAttributeilgili ayrıntıları sağlar. Yukarıdaki örnekte, WarningLogMethod bir DiagnosticSeverity.Warning değerini SYSLIB0025raporlar.
Don't include a template for `ex` in the logging message since it is implicitly taken care of.
Büyük/küçük harfe duyarlı olmayan şablon adı desteği
Oluşturucu, ileti şablonundaki öğelerle günlük iletisindeki bağımsız değişken adları arasında büyük/küçük harfe duyarlı olmayan bir karşılaştırma yapar. Bu, durum numaralandırıldığında ILogger bağımsız değişkenin ileti şablonu tarafından alınıp günlüklerin daha iyi bir şekilde tüketilebileceği anlamına gelir:
public partial class LoggingExample
{
private readonly ILogger _logger;
public LoggingExample(ILogger logger)
{
_logger = logger;
}
[LoggerMessage(
EventId = 10,
Level = LogLevel.Information,
Message = "Welcome to {City} {Province}!")]
public partial void LogMethodSupportsPascalCasingOfNames(
string city, string province);
public void TestLogging()
{
LogMethodSupportsPascalCasingOfNames("Vancouver", "BC");
}
}
JsonConsole formatlayıcısını kullanırken örnek günlük çıktısını göz önünde bulundurun.
{
"EventId": 13,
"LogLevel": "Information",
"Category": "LoggingExample",
"Message": "Welcome to Vancouver BC!",
"State": {
"Message": "Welcome to Vancouver BC!",
"City": "Vancouver",
"Province": "BC",
"{OriginalFormat}": "Welcome to {City} {Province}!"
}
}
Belirsiz parametre sırası
Log yöntemi parametrelerinin sıralanmasında herhangi bir kısıtlama yoktur. Geliştirici, ILogger öğesini son parametre olarak tanımlayabilir ancak bu biraz garip görünebilir.
[LoggerMessage(
EventId = 110,
Level = LogLevel.Debug,
Message = "M1 {Ex3} {Ex2}")]
static partial void LogMethod(
Exception ex,
Exception ex2,
Exception ex3,
ILogger logger);
Tavsiye
Bir log yöntemindeki parametrelerin sırasının, şablon yer tutucularının sırasına karşılık gelmesi gerekmez. Bunun yerine, şablondaki değişken adlarının parametrelerle uyumlu olması beklenir. Aşağıdaki JsonConsole çıkışı ve hataların sırasını göz önünde bulundurun.
{
"EventId": 110,
"LogLevel": "Debug",
"Category": "ConsoleApp.Program",
"Message": "M1 System.Exception: Third time's the charm. System.Exception: This is the second error.",
"State": {
"Message": "M1 System.Exception: Third time's the charm. System.Exception: This is the second error.",
"ex2": "System.Exception: This is the second error.",
"ex3": "System.Exception: Third time's the charm.",
"{OriginalFormat}": "M1 {Ex3} {Ex2}"
}
}
Daha fazla günlük örneği
Aşağıdaki örnekler, olayın adını almayı, kayıt seviyesini dinamik bir şekilde ayarlamayı ve kayıt parametrelerini biçimlendirmeyi göstermektedir. Günlüğe kaydetme yöntemleri şunlardır:
-
LogWithCustomEventName: Öznitelik aracılığıylaLoggerMessageolay adını alın. -
LogWithDynamicLogLevel: Günlük düzeyinin yapılandırma girişine göre ayarlanmasına izin vermek için günlük düzeyini dinamik olarak ayarlayın. -
UsingFormatSpecifier: Günlük parametrelerini biçimlendirmek için format tanımlayıcılarını kullanın.
public partial class LoggingSample
{
private readonly ILogger _logger;
public LoggingSample(ILogger logger)
{
_logger = logger;
}
[LoggerMessage(
EventId = 20,
Level = LogLevel.Critical,
Message = "Value is {Value:E}")]
public static partial void UsingFormatSpecifier(
ILogger logger, double value);
[LoggerMessage(
EventId = 9,
Level = LogLevel.Trace,
Message = "Fixed message",
EventName = "CustomEventName")]
public partial void LogWithCustomEventName();
[LoggerMessage(
EventId = 10,
Message = "Welcome to {City} {Province}!")]
public partial void LogWithDynamicLogLevel(
string city, LogLevel level, string province);
public void TestLogging()
{
LogWithCustomEventName();
LogWithDynamicLogLevel("Vancouver", LogLevel.Warning, "BC");
LogWithDynamicLogLevel("Vancouver", LogLevel.Information, "BC");
UsingFormatSpecifier(logger, 12345.6789);
}
}
SimpleConsole formatlayıcısını kullanırken örnek günlük çıktısını göz önünde bulundurun.
trce: LoggingExample[9]
Fixed message
warn: LoggingExample[10]
Welcome to Vancouver BC!
info: LoggingExample[10]
Welcome to Vancouver BC!
crit: LoggingExample[20]
Value is 1.234568E+004
JsonConsole formatlayıcısını kullanırken örnek günlük çıktısını göz önünde bulundurun.
{
"EventId": 9,
"LogLevel": "Trace",
"Category": "LoggingExample",
"Message": "Fixed message",
"State": {
"Message": "Fixed message",
"{OriginalFormat}": "Fixed message"
}
}
{
"EventId": 10,
"LogLevel": "Warning",
"Category": "LoggingExample",
"Message": "Welcome to Vancouver BC!",
"State": {
"Message": "Welcome to Vancouver BC!",
"city": "Vancouver",
"province": "BC",
"{OriginalFormat}": "Welcome to {City} {Province}!"
}
}
{
"EventId": 10,
"LogLevel": "Information",
"Category": "LoggingExample",
"Message": "Welcome to Vancouver BC!",
"State": {
"Message": "Welcome to Vancouver BC!",
"city": "Vancouver",
"province": "BC",
"{OriginalFormat}": "Welcome to {City} {Province}!"
}
}
{
"EventId": 20,
"LogLevel": "Critical",
"Category": "LoggingExample",
"Message": "Value is 1.234568E+004",
"State": {
"Message": "Value is 1.234568E+004",
"value": 12345.6789,
"{OriginalFormat}": "Value is {Value:E}"
}
}
Günlüklerde hassas bilgileri sansürleme
Hassas verilerin günlüğe kaydedilmesi sırasında, yanlışlıkla açığa çıkmasını önlemek önemlidir. Derleme zamanında üretilen günlük yöntemlerinde bile ham hassas değerlerin günlüğe kaydedilmesi veri sızıntılarına ve uyumluluk sorunlarına yol açabilir.
Microsoft.Extensions.Telemetry kitaplığı, .NET uygulamaları için gelişmiş günlük ve telemetri zenginleştirme özellikleri sağlar. Günlükleri yazarken sınıflandırılmış verileri otomatik olarak gizlemek için günlük işlem hattını genişletir. Günlük iş akışınıza redaksiyon uygulamasını tümleştirerek uygulamanız genelinde veri koruma ilkelerini zorunlu kılmanıza olanak tanır. Gelişmiş telemetri ve kayıt yönetimi içgörülerine ihtiyaç duyan uygulamalar için tasarlanmıştır.
Yeniden düzeltmeyi etkinleştirmek için Microsoft.Extensions.Compliance.Redaction kitaplığını kullanın. Bu kitaplık, örneğin silme, maskeleme veya karma oluşturma yoluyla hassas verileri dönüştüren bileşenler sağlayan düzenleyiciler içerir ve böylece verileri güvenli bir şekilde sunar. Redaktörler, verileri duyarlılığına göre (kişisel, özel veya genel gibi) etiketlemenizi sağlayan veri sınıflandırmasına göre seçilir.
Kaynak tarafından oluşturulan loglama yöntemleriyle sansür veya düzenleme yapmak için şunları izlemeniz gerekir:
- Veri sınıflandırma sistemi kullanarak hassas verilerinizi sınıflandırma.
- DI kapsayıcınızdaki her sınıflandırma için redaktörleri kaydedin ve yapılandırın.
- Günlük işlem hattında yeniden düzeltmeyi etkinleştirin.
- Hassas verilerin gösterilmediğinden emin olmak için günlüklerinizi denetleyin.
Örneğin, özel olarak kabul edilen bir parametresi olan bir günlük iletiniz varsa:
[LoggerMessage(0, LogLevel.Information, "User SSN: {SSN}")]
public static partial void LogPrivateInformation(
this ILogger logger,
[MyTaxonomyClassifications.Private] string SSN);
Şuna benzer bir ayara sahip olmanız gerekir:
using Microsoft.Extensions.Telemetry;
using Microsoft.Extensions.Compliance.Redaction;
var services = new ServiceCollection();
services.AddLogging(builder =>
{
// Enable redaction.
builder.EnableRedaction();
});
services.AddRedaction(builder =>
{
// configure redactors for your data classifications
builder.SetRedactor<StarRedactor>(MyTaxonomyClassifications.Private);
});
public void TestLogging()
{
LogPrivateInformation("MySSN");
}
Çıkış şu şekilde olmalıdır:
User SSN: *****
Bu yaklaşım, derleme zamanında oluşturulan günlük API'leri kullanılırken bile yalnızca gizlenmiş verilerin günlüğe kaydedilmesini sağlar. Farklı veri türleri veya sınıflandırmalar için farklı redaktörler kullanabilir ve redaksiyon mantığınızı merkezi olarak güncelleştirebilirsiniz.
Verilerinizi sınıflandırma hakkında daha fazla bilgi için bkz. .NET'te Veri sınıflandırması. Redaksiyon ve redaktörler hakkında daha fazla bilgi için bkz. .NET'te Veri redaksiyonu.
Özet
C# kaynak oluşturucularının ortaya çıkmasıyla birlikte, yüksek performanslı günlük API'leri yazmak daha kolaydır. Kaynak oluşturucu yaklaşımını kullanmanın çeşitli temel avantajları vardır:
- Günlük yapısının korunmasına izin verir ve İleti Şablonları için gereken tam biçim söz dizimini etkinleştirir.
- Şablon yer tutucuları için alternatif adlar sağlamanıza ve biçim tanımlayıcılarını kullanmanıza izin verir.
- Tüm özgün verilerin, üzerinde bir işlem yapılmadan önce nasıl depolandığıyla ilgili herhangi bir sorun yaşamadan (bir
stringoluşturma dışında), olduğu gibi aktarılmasına izin verir. - Günlüğe özgü tanılamalar sağlar ve yinelenen olay kimlikleri için uyarılar yayar.
Ayrıca, el ile kullanmanın LoggerMessage.Defineavantajları da vardır:
- Daha kısa ve daha basit söz dizimi: Şablon kodlama yerine bildirim temelli öznitelik kullanımı.
- Destekli geliştirici deneyimi: Oluşturucu, geliştiricilerin doğru şeyi yapmalarına yardımcı olmak için uyarılar verir.
- Belirli olmayan sayıda log parametresi desteği.
LoggerMessage.Defineen fazla altıyı destekler. - Dinamik günlük düzeyi desteği. Bu,
LoggerMessage.Definetek başına mümkün değildir.