日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

优化 .NET Core logging 中的泛型 logger

發布時間:2023/12/4 asp.net 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 优化 .NET Core logging 中的泛型 logger 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

優化 .NET Core?logging 中的泛型 logger

Intro

在微軟的 logging 組件中,我們可以比較方便的使用泛型 Logger,如:ILogger<Generic> 這樣的,

但是如果泛型 Logger 的類型是一個泛型類型就會有些問題,具體的泛型參數不會作為 categoryName 的一部分,我們可以實現一個自己的 ILogger<T> 來改變這個行為,詳細可以參考下面的介紹

Reproduce

這個問題非常好重現,只需要一個測試的泛型類就可以了,我寫了一個簡單的測試類,定義如下:

private?class?GenericTest<T> {private?readonly?ILogger<GenericTest<T>>?_logger;public?GenericTest(ILogger<GenericTest<T>>?logger){_logger?=?logger;}public?void?Test()?=>?_logger.LogInformation("test"); }

測試代碼如下:

using?var?services?=?new?ServiceCollection().AddLogging(builder?=>?builder.AddConsole()).AddSingleton(typeof(GenericTest<>)).BuildServiceProvider(); services.GetRequiredService<GenericTest<int>>().Test(); services.GetRequiredService<GenericTest<string>>().Test();

這里使用了兩個泛型類型,一個泛型參數是 int,一個是 string,來看上面代碼的輸出結果吧,輸出結果如下:

可以看到,默認的日志行為我們沒有辦法區分泛型類的泛型參數具體是什么,這對于我們來說有時候是很不方便的

What's inside

我們可以在 Github 上找到 logging 組件的源代碼,可以參考:https://github.com/dotnet/runtime/blob/fa06656c41947e22fc6efd909cce0a6a180f1078/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/LoggerT.cs

通過源碼我們可以看到默認的行為,并不會記錄泛型參數,經過測試如果我們需要包含泛型參數信息只需要把 includeGenericParameters 參數設置為 true 即可,既然明確了如何實現我們期望的效果改起來就會很簡單

Cutom Generic Logger

微軟的 Logging 非常的依賴注入,泛型的 Logger 也是依賴注入的,我們只需要注入自己的泛型 Logger 實現就可以代替默認的行為了,可以參考:https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Logging/src/LoggingServiceCollectionExtensions.cs#L42


為了不造成 breaking change,我們可以加一個配置,默認還是與微軟現在的行為保持一致,針對想要區分的類型使用帶泛型參數的行為,實現代碼如下:

//?泛型?logger?配置 public?sealed?class?GenericLoggerOptions {//?返回?true?則使用帶泛型參數的?typeName,否則使用默認的行為public?Func<Type,?bool>??FullNamePredict?{?get;?set;?} }internal?sealed?class?GenericLogger<T>?:?ILogger<T> {private?readonly?ILogger?_logger;///?<summary>///?Creates?a?new?<see?cref="GenericLogger{T}"/>.///?</summary>///?<param?name="factory">The?factory.</param>///?<param?name="options">GenericLoggerOptions</param>public?GenericLogger(ILoggerFactory?factory,?IOptions<GenericLoggerOptions>?options){if?(factory?==?null){throw?new?ArgumentNullException(nameof(factory));}//?通過配置的委托來判斷是否要包含泛型參數var?includeGenericParameters?=?options.Value.FullNamePredict?.Invoke(typeof(T))?==?true;_logger?=?factory.CreateLogger(TypeHelper.GetTypeDisplayName(typeof(T),?includeGenericParameters:?includeGenericParameters,?nestedTypeDelimiter:?'.'));}///?<inheritdoc?/>IDisposable?ILogger.BeginScope<TState>(TState?state){return?_logger.BeginScope(state);}///?<inheritdoc?/>bool?ILogger.IsEnabled(LogLevel?logLevel){return?_logger.IsEnabled(logLevel);}///?<inheritdoc?/>void?ILogger.Log<TState>(LogLevel?logLevel,?EventId?eventId,?TState?state,?Exception??exception,?Func<TState,?Exception?,?string>?formatter){_logger.Log(logLevel,?eventId,?state,?exception,?formatter);}public?void?Log<TState>(LogLevel?logLevel,?EventId?eventId,?TState?state,?Exception?exception,?Func<TState,?Exception,?string>?formatter)?=>?throw?new?NotImplementedException();public?bool?IsEnabled(LogLevel?logLevel)?=>?throw?new?NotImplementedException();public?IDisposable?BeginScope<TState>(TState?state)?=>?throw?new?NotImplementedException(); }

TypeHelper 中的方法就是微軟 Logging 中引用的 TypeNameHelper,因為是 internal,所以單獨拷出來一份,

上面的 Logger 與微軟默認的 logger 唯一的不同之處就在于多了一個配置。。

為了使用起來方便,定義了一個 ILoggingBuilder 的擴展方法,定義如下:

public?static?ILoggingBuilder?UseCustomGenericLogger(this?ILoggingBuilder?loggingBuilder,?Action<GenericLoggerOptions>?genericLoggerConfig) {Guard.NotNull(loggingBuilder,?nameof(loggingBuilder));Guard.NotNull(genericLoggerConfig,?nameof(genericLoggerConfig));loggingBuilder.Services.Configure(genericLoggerConfig);loggingBuilder.Services.AddSingleton(typeof(ILogger<>),?typeof(GenericLogger<>));return?loggingBuilder; }

好了,現在我們來測試一下我們自己的泛型 logger 吧,測試代碼如下:

using?var?services?=?new?ServiceCollection().AddLogging(builder?=>?builder.AddConsole().UseCustomGenericLogger(options?=>?options.FullNamePredict?=?_?=>?true)).AddSingleton(typeof(GenericTest<>)).BuildServiceProvider(); services.GetRequiredService<GenericTest<int>>().Test(); services.GetRequiredService<GenericTest<string>>().Test();

輸出結果如下:

可以看到現在的輸出日志中已經包含了泛型類型的泛型參數,如果你對自己名稱還不夠滿意,也可以自定義 GetTypeDisplayName 的行為

More

上面的測試代碼有需要的可以從 Github 上獲取:https://github.com/WeihanLi/WeihanLi.Common/blob/dev/samples/DotNetCoreSample/LoggerTest.cs#L37

感覺泛型參數還是記錄一下的比較好,這樣我們才能知道具體是哪一個類型打印出來的日志,像第一種方式打印出來的日志,完全就是一臉懵逼,真正出現了問題,完全不知道是哪一個類型的日志,只能靠猜了,這體驗就太不好了,不過還好我們可以比較方便的進行定制。

不知道你是否也有這樣的想法呢,在 Github 上提了一個 issue https://github.com/dotnet/runtime/issues/51368,如果感興趣,可以關注一下 ,留下你的看法

References

  • https://github.com/dotnet/runtime/issues/51368

  • https://github.com/WeihanLi/WeihanLi.Common/blob/dev/samples/DotNetCoreSample/LoggerTest.cs#L37

總結

以上是生活随笔為你收集整理的优化 .NET Core logging 中的泛型 logger的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。