Derleme zamanı günlük kaynağı oluşturma
.NET 6 türü tanıtır LoggerMessageAttribute . Bu öznitelik, Microsoft.Extensions.Logging ad alanının bir parçasıdır ve kullanıldığında, kaynak-performans günlüğü API 'leri oluşturur. Kaynak oluşturma günlüğü desteği, modern .NET uygulamaları için yüksek düzeyde kullanılabilir ve yüksek performanslı günlük çözümü sunacak şekilde tasarlanmıştır. Otomatik olarak oluşturulan kaynak kodu, ILogger LoggerMessage.Define işlevleri işlevlerle birlikte kullanır.
Kaynak Oluşturucu, LoggerMessageAttribute partial günlüğe kaydetme yöntemlerinde kullanıldığında tetiklenir. Tetiklendiğinde, bu, dekorasyon yöntemlerin uygulanmasını otomatik hale başlatabilir ya da partial uygun kullanım hakkında ipuçları ile derleme zamanı tanılaması üretebilir. Derleme zamanı günlüğü çözümü, çalışma zamanında mevcut günlük yaklaşımlarından önemli ölçüde daha hızlıdır. Bu, kutulamayı, geçici ayırmaları ortadan kaldırarak ve mümkün olan en yüksek ölçüde kopyalar.
Temel kullanım
Öğesini kullanmak için LoggerMessageAttribute , tüketen sınıf ve yöntemin olması gerekir partial . Kod Oluşturucu derleme zamanında tetiklenir ve yönteminin bir uygulamasını oluşturur partial .
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, günlük metodu static ve öznitelik tanımında günlük düzeyi belirtilir. Özniteliği statik bir bağlamda kullanılırken, ILogger örnek bir parametre olarak gereklidir. Özniteliğini statik olmayan bir bağlamda kullanmayı da tercih edebilirsiniz. Günlüğe kaydetme yönteminin bir örnek yöntemi olarak bildirildiği aşağıdaki örneği göz önünde bulundurun. Bu bağlamda, Logging yöntemi, kapsayan sınıftaki bir alana erişerek günlükçü 'yi alır ILogger .
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);
}
Bazen, kod içine statik olarak yerleştirilmektense günlük düzeyinin dinamik olması gerekir. Bu, günlük düzeyini öznitelikten atlayarak ve bunun yerine günlük metoduna parametre olarak gerektirerek 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);
}
Günlüğe kaydetme iletisini atlayabilirsiniz ve String.Empty ileti için sağlanacaktır. Durum, anahtar-değer çiftleri olarak biçimlendirilen bağımsız değişkenleri içerir.
using System.Text.Json;
using Microsoft.Extensions.Logging;
ILogger<SampleObject> logger = LoggerFactory.Create(
builder =>
builder.AddJsonConsole(
options =>
options.JsonWriterOptions = new JsonWriterOptions()
{
Indented = true
}))
.CreateLogger<SampleObject>();
logger.CustomLogEvent(LogLevel.Information, "Liana", "California");
public static partial class SampleObject
{
[LoggerMessage(EventId = 23)]
public static partial void CustomLogEvent(
this ILogger logger, LogLevel logLevel,
string name, string state);
}
Biçimlendirici kullanılırken örnek günlük çıkışını göz önünde bulundurun JsonConsole .
{
"EventId": 23,
"LogLevel": "Information",
"Category": "ConsoleApp.SampleObject",
"Message": "",
"State": {
"Message": "",
"name": "Liana",
"state": "California",
"{OriginalFormat}": ""
}
}
Günlük yöntemi kısıtlamaları
LoggerMessageAttributeGünlüğe kaydetme yöntemlerini kullanırken, izlenmesi gereken bazı kısıtlamalar vardır:
- Günlüğe kaydetme yöntemlerinin
static,partialve döndürmesi gerekirvoid. - Günlüğe kaydetme yöntemi adları alt çizgiyle başlamamalıdır.
- Günlüğe kaydetme yöntemlerinin parametre adları bir alt çizgiyle başlamamalıdır .
- Günlüğe kaydetme yöntemleri , iç içe yerleştirilmiş bir tür içinde tanımlanamaz.
- Günlük yöntemleri genel olamaz .
Kod oluşturma modeli, modern bir C# derleyicisi, sürüm 9 veya üzeri ile derlenen koda bağlıdır. C# 9,0 derleyicisi .NET 5 ile kullanılabilir duruma geldi. Modern bir C# derleyicisine yükseltmek için proje dosyanızı C# 9,0 ' i hedefleyecek şekilde düzenleyin.
<PropertyGroup>
<LangVersion>9.0</LangVersion>
</PropertyGroup>
Daha fazla bilgi için bkz. C# dil sürümü oluşturma.
Günlük yöntemi anatomisi
ILogger.Logİmza, LogLevel Exception aşağıda gösterildiği gibi, ve isteğe bağlı olarak bir kabul eder.
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,, ve, ilk ILogger örneği LogLevel Exception kaynak oluşturucunun günlük yöntemi imzasında özel olarak değerlendirilir. Sonraki örnekler, ileti şablonuna normal parametreler gibi 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
Oluşturulan uyarılar, doğru kullanımının ayrıntılarını sağlar LoggerMessageAttribute . Yukarıdaki örnekte, ' WarningLogMethod a rapor eder DiagnosticSeverity.Warning SYSLIB0025 .
Don't include a template for `ex` in the logging message since it is implicitly taken care of.
Büyük/küçük harf duyarsız şablon adı desteği
Oluşturucu ileti şablonundaki öğeler ve günlük iletisindeki bağımsız değişken adları arasında büyük/küçük harfe duyarsız bir karşılaştırma yapar. Bu, ILogger durumu numaralandırdıkları zaman, bağımsız değişkenin ileti şablonu tarafından alındığı, bu da günlüklerin tüketilmesi durumunda olduğunu gösterir:
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");
}
}
Biçimlendirici kullanılırken örnek günlük çıkışını göz önünde bulundurun JsonConsole :
{
"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ı
Günlük yöntemi parametrelerinin sıralaması üzerinde hiçbir kısıtlama yoktur. Bir geliştirici, ILogger en son parametre olarak tanımlayabilir, ancak bu bir bit awkileri 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);
İpucu
Bir günlük yöntemindeki parametrelerin sırası, şablon yer tutucuların sırasına karşılık gelmesi için gerekli değildir . Bunun yerine, şablondaki yer tutucu adlarının parametrelerle eşleşmesi beklenir. Aşağıdaki JsonConsole çıktıyı 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}"
}
}
Ek günlük örnekleri
Aşağıdaki örneklerde nasıl yapılacağı gösterilmektedir:
LogWithCustomEventName: Öznitelik aracılığıyla olay adı almaLoggerMessage.LogWithDynamicLogLevel: Günlük düzeyinin yapılandırma girişine göre ayarlanbilmesini sağlamak için günlük düzeyini dinamik olarak ayarlayın.UsingFormatSpecifier: Günlük parametrelerini biçimlendirmek için biçim belirticileri 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);
}
}
Biçimlendirici kullanılırken örnek günlük çıkışını göz önünde bulundurun SimpleConsole :
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
Biçimlendirici kullanılırken örnek günlük çıkışını göz önünde bulundurun JsonConsole :
{
"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}"
}
}
Özet
C# kaynak oluşturucularından oluşan havalandırma sayesinde yüksek performanslı günlük API 'Leri yazmak çok daha kolay. Kaynak Oluşturucu yaklaşımını kullanmanın birkaç önemli avantajı vardır:
- Günlüğe kaydetme yapısının korunmalarını sağlar ve Ileti şablonlarıiçin gereken tam biçim sözdizimini sağlar.
- Şablon yer tutucuları ve biçim belirticilerini kullanarak alternatif adlar sağlamaya izin verir.
- Tüm özgün verilerin olduğu gibi, onunla ilgili bir işlem yapılmadan önce nasıl depolandığına ilişkin herhangi bir zorluk yapılmaksızın (oluşturma dışında) izin verir
string. - Günlüğe kaydetmeye özgü Tanılamalar sağlar ve yinelenen olay kimlikleri için uyarı yayar.
Ayrıca, kullanarak el ile de faydalanır LoggerMessage.Define .
- Daha kısa ve basit sözdizimi: ortak kodlama yerine bildirime dayalı öznitelik kullanımı.
- Kılavuzlu geliştirici deneyimi: Oluşturucu, geliştiricilerin doğru şeyi gerçekleştirmelerine yardımcı olmak için uyarılar verir.
- Rastgele sayıda günlük parametresi desteği.
LoggerMessage.Defineen fazla altı destekler. - Dinamik günlük düzeyi desteği. Tek başına bu mümkün değildir
LoggerMessage.Define.