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

歡迎訪問 生活随笔!

生活随笔

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

asp.net

ASP.NET Core 沉思录 - 结构化日志

發布時間:2023/12/4 asp.net 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core 沉思录 - 结构化日志 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在 《ASP.NET Core 沉思錄 - Logging 的兩種介入方法》中我們介紹了 ASP.NET Core 中日志的基本設計結構。這一次我們來觀察日志記錄的格式,并進一步考慮如何在應用程序中根據不同的需求選擇不同的日志記錄形式。

太長不讀:直接飛到文章最后 :-D

Microsoft.Extension.Logging 體系下的日志格式

為了便于閱讀,我們仍然將 Microsoft.Extension.Logging 的基本設計結構放在這里:

奇怪的不合理之處

注:所謂奇怪就是這種不合理是只是從某一種特定視角看的。

對于記錄日志而言,雖然一些具體的日志記錄目標和記錄的格式會有一些聯系,但是日志記錄的目標和日志記錄的格式應該是兩件事情。貌似 Microsoft.Extension.Logging 在此處進行了一些抽象。首先,日志具體的記錄地點和記錄格式全部由具體的 ILoggerProvider 創建的 ILogger 來完成。而對于日志的格式化方法,則使用 ILogger.Log 方法中的委托來完成。該委托中包含了一個 formatter 委托參數。該委托接收需要記錄的對象,關聯的異常實例并返回日志字符串。我們可以在其中定義自己的格式化邏輯。總結起來感覺是:

  • 特定的 ILoggerProvider 創建將日志記錄到特定種類的目的地的日志記錄器。例如,ConsoleLogger。

  • 指定 ILogger.Log 方法中的 formatter 參數對日志對象進行格式化。

ILogger.Log 方法除了 formatter 之外還包含如下的參數:

  • logLevel:日志的級別。

  • eventId:當前事件的標識。

  • state:日志對象。

  • exception:關聯的異常對象。

而 formatter 參數將使用其中的 state 參數和 exception 參數對日志進行格式化。這樣通過替換 formatter 的邏輯就可以更改日志的形式了。例如,使用如下的邏輯就可以將 state 格式化為 JSON 形式:

//?Capture?output?so?that?we?can?assert?its?content
var?writer?=?new?StringWriter();
Console.SetOut(writer);

//?Normal?initialization?logic
var?serviceCollection?=?new?ServiceCollection();
serviceCollection.AddLogging(
????config?=>?config.SetMinimumLevel(LogLevel.Debug).AddConsole());
ServiceProvider?provider?=?serviceCollection.BuildServiceProvider();
var?loggerFactory?=?provider.GetService<ILoggerFactory>();
var?logger?=?loggerFactory.CreateLogger("category");

//?Write?log?message
logger.Log(
????LogLevel.Information,
????1,
????new?{message?=?"Hello?{name}",?name?=?"World"},
????null,
????(state,?exception)?=>?JsonConvert.SerializeObject(state));

//?This?is?very?important.?The?console?logger?using?a?async?processor?to?consume
//?the?queued?log?message.
Thread.Sleep(1000);

Assert.Equal("...(omitted)...",?writer.ToString())

如果您嘗試了上述范例程序就會感到這個設計好像有問題,而如果聯系整個 Extension.Logging 體系則感覺問題就更大了:

  • formatter只是解決了日志 message 部分的格式化問題,而無法影響其他信息的格式化,例如 eventId、logLevel、exception 等。

  • 我們根本不會用到具體的 ILoggerProvider 而是會使用 ILoggerFactory 提供的 Logger 門面。這個 Logger 是一個組合 Logger,也就是它會將 ILogger&lt;&gt;.Log 調用分發出來。但是我們很少使用 ILogger&lt;&gt;.Log 方法,而會使用擴展方法使用 template message 進行日志記錄,這意味著所有的子 ILogger 實現都會接到同樣的 formatter。自此,不同的目標采用不同的消息格式的理想破滅了。

總結一下就是,日志的記錄目標和日志的格式混合了起來。職責區分不清。message 的格式化職責交給了門面擴展方法;而另一部分格式化職責交給了具體的 ILoggerProvider。

從另一種視角看的合理之處

我們換一個視角可能就會得到不一樣的體驗。首先我們更改分析問題的策略。從端到端的角度來思考問題。當我們記錄日志的時候希望有哪幾類信息呢?日志作為追蹤一個事件的依據,應當能夠清晰的說明這個事件。那么小學語文老師就告訴過我們,記錄一件事情需要有:

  • 時間

  • 地點

  • 人物

  • 起因

  • 經過

  • 結果

如果我們將這些信息歸一歸類,我們就可以得到這些信息:

  • 物理世界的環境參數:時間

  • 判斷事件嚴重程度的依據:結果

  • 事件過程的上下文參數:地點(例如 URI 或代表某種操作的入口)、人物(例如誰進行的操作)、起因(例如方法調用參數)、經過(例如調用的那個方法)

而要記錄這些信息,則可以對應到程序中的以下幾種形式的數據:

  • 物理世界的環境參數:例如 DateTime、DateTimeOffset

  • 判斷事件嚴重程度的依據:例如 LogLevel

  • 事件過程上下文的參數:例如事件的類別 CategoryName;一個包含各種各樣上下文參數的 object[] 對象;以及對人類友好,能夠將這些參數串起來的消息模板。

至此,你能夠看到這些參數正是 Microsoft.Extension.Logging 中門面擴展方法中需要你來提供的參數。它本來也沒有希望你調用 ILogger.Log 方法。而是希望你調用擴展方法用最舒服的方式達成日志記錄的目的。

而作為 ILoggerProvider 開發者,你并不一定必須得接受 formatter 生成的格式化后的日志消息。你可以選擇處理每一個傳入參數。具體的請參見 FormattedLogValues 類型的源代碼。

階段性總結

  • 日志記錄和記敘文一樣,只要滿足了六要素就可以說清楚一件事情。而記錄這六要素的形式正式 Extension.Logging 提供給我們的擴展方法的參數形式。

  • 分析問題從端到端分析是一種非常靠譜的分析方法。可以避免走彎路。

  • ILogger 的擴展方法負責生成日志消息,ILoggerProvider 和負責記錄工作的 ILogger 實現負責格式化日志消息并將日志記錄到特定的目標上去。

利用 SeriLog 實現靈活的日志記錄形式

通過上述分析我們應該能夠看到這種設計的合理性。但是不爭的事實是 ILoggerProvider 一系包攬兩種職能,并沒有進一步抽象,有沒有人來對日志記錄的目標和日志記錄的整體格式進行抽象呢?有!那就是被千萬人喜愛的 SeriLog。它在 ILoggerProvider 一級抽象了 ITextFormatter 解決了這個問題:

我不會在這里介紹 SeriLog 的具體使用方法。網上教程一大堆大家去搜搜好了。我建議直接去官網。

例如,我可以將日志記錄到 Console 中,默認情況下,這種日志的格式是給人看的:

//?normal?initialization?logic
var?serviceCollection?=?new?ServiceCollection();
serviceCollection.AddLogging(b?=>
{
????Logger?seriLogger?=?new?LoggerConfiguration()
????????.WriteTo.Console()
????????.MinimumLevel.Debug()
????????.CreateLogger();

????b.AddSerilog(seriLogger);
});
ServiceProvider?provider?=?serviceCollection.BuildServiceProvider();

//?create?logger
var?loggerFactory?=?provider.GetService<ILoggerFactory>();
var?logger?=?loggerFactory.CreateLogger("category");

//?write?log
logger.LogInformation("Hello?{name}",?"world");

此時屏幕上會輸出高亮版的,適于閱讀的日志,類似這樣:

[18:41:27 INF] Hello world

但是如果希望使用其他的格式,則可以通過 ITextFormatter 快速的轉換格式:

var?serviceCollection?=?new?ServiceCollection();
serviceCollection.AddLogging(b?=>
{
????Logger?seriLogger?=?new?LoggerConfiguration()
????????//?PLEASE?NOTE?that?we?use?JsonFormatter?as?input?paramter
????????.WriteTo.Console(new?JsonFormatter())
????????.MinimumLevel.Debug()
????????.CreateLogger();

????b.AddSerilog(seriLogger);
});

ServiceProvider?provider?=?serviceCollection.BuildServiceProvider();

var?loggerFactory?=?provider.GetService<ILoggerFactory>();
var?logger?=?loggerFactory.CreateLogger("category");

logger.LogInformation("Hello?{name}",?"world");

這樣就會得到以下的日志:

{
????"Timestamp":"2019-03-24T19:38:54.4833240+08:00",
????"Level":"Information",
????"MessageTemplate":"Hello?{name}",
????"Properties":{"name":"world","SourceContext":"category"}
}

如果還需要 formatter 格式化之后的完整消息,可以在創建 JsonFormatter 時指定 new JsonFormatter(renderMessage: true) 這樣就會得到包含完整可讀消息的結果:

{
????"Timestamp":"2019-03-24T19:44:51.0430260+08:00",
????"Level":"Information",
????"MessageTemplate":"Hello?{name}",
????"RenderedMessage":"Hello?\"world\"",
????"Properties":{"name":"world","SourceContext":"category"}
}

這樣,在實際的操作中。我們可以直接使用 Microsoft.Extension.Logging 默認體系對 ILoggerProvider 進行擴展達到對記錄目標和記錄格式的控制;也可以將其與 SeriLog 集成。通過 Sink 和 ITextFormatter 組合的方式分別對記錄目標和記錄格式進行控制。

總結

一圖勝千言:

圖-1 默認 Microsoft.Extension.Logging 類型及信息傳遞路徑

圖-2 集成 SeriLog 后類型及信息傳遞路徑

如果您覺得本文對您有幫助,也歡迎分享給其他的人。我們一起進步。歡迎關注我的博客(https://clrdaily.com)和微信公眾號:

總結

以上是生活随笔為你收集整理的ASP.NET Core 沉思录 - 结构化日志的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 人人爱操 | 高清视频一区二区 | 人人爱人人澡 | 天天插天天射 | 亚洲第九十九页 | 亚洲综合五月天婷婷丁香 | 99性视频| 成人免费观看在线视频 | 欧美精品色 | 在线观看视频你懂得 | av网址导航 | 欧美精品不卡 | 林由奈在线观看 | 久草视频免费 | 亚洲人成在线观看 | 处破女av一区二区 | 一本一道久久综合 | 久久久久久av无码免费网站 | 精品久久久在线观看 | 中文字幕网站在线观看 | 日韩阿v | 日韩黄视频 | av网站有哪些 | 日日夜夜操视频 | 成人国产精品入口免费视频 | 男女黄床上色视频 | 日韩在线资源 | 国产一区二区精品久久 | mm1313亚洲精品| 免费a网| 久久久久在线观看 | 日韩国产欧美 | 国产欧美日韩综合 | 国产成人无码一区二区三区在线 | 亚洲精品天堂网 | 国产精品视频合集 | 极品探花在线 | 农夫色综合 | av操操操 | 制服.丝袜.亚洲.中文.综合懂色 | 亚洲成人播放 | 国产av成人一区二区三区 | 日本成人综合 | 少妇视频一区 | 97超碰人人在线 | 国产精品爽爽 | 久久免费视屏 | 黄色三级小视频 | 欧美大色 | 日本韩国三级 | 国产一区二区视频免费观看 | 国产suv精品一区二区68 | 中文字幕理伦片免费看 | 久久亚洲AV无码精品 | 高潮又黄又刺激 | 欧美a级在线免费观看 | 国产熟女高潮一区二区三区 | 一区二区 中文字幕 | 国产成人精品无码播放 | 成人黄色在线免费观看 | 国产精品乱码一区二区三区 | av第一页| 凹凸日日摸日日碰夜夜 | 偷拍福利视频 | 日本www黄 | 国产精品一卡二卡三卡 | a级黄片毛片| 国产成人精品一区二区在线观看 | 日韩美女福利视频 | 日本亚洲欧美 | 伊人中文字幕在线 | 成人图片小说 | 婷婷777| 亚洲激情在线观看 | 操视频网站 | 丁香花高清在线观看完整动漫 | 高清av网址 | 四虎在线网址 | www.成人av| 青青草免费在线观看 | 在线观看黄色片网站 | 色综综| 一区二区中文字幕在线观看 | 久久人 | 无码精品一区二区免费 | 国产a v一区二区三区 | 精射女上司 | 青青草社区视频 | 亚洲国产精品久久久久久久 | 色图网址| 麻豆一区产品精品蜜桃的特点 | 一区二区免费在线观看 | 黄色av网站免费在线观看 | 嫩草研究院在线 | 一区二区伊人 | 美女扒开内看个够网站 | 亚洲蜜桃精久久久久久久久久久久 | 欧美性色黄大片手机版 | 舐め犯し波多野结衣在线观看 |