小編給大家分享一下ASP.NET Core應(yīng)用中怎么記錄和查看日志,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
成都創(chuàng)新互聯(lián)公司是專業(yè)的浦北網(wǎng)站建設(shè)公司,浦北接單;提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行浦北網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!日志記錄不僅對(duì)于我們開(kāi)發(fā)的應(yīng)用,還是對(duì)于ASP.NET Core框架功能都是一項(xiàng)非常重要的功能特性。我們知道ASP.NET Core使用的是一個(gè)極具擴(kuò)展性的日志系統(tǒng),該系統(tǒng)由Logger、LoggerFactory和LoggerProvider這三個(gè)核心對(duì)象組成。我們可以通過(guò)簡(jiǎn)單的配置實(shí)現(xiàn)對(duì)LoggerFactory的定制,以及對(duì)LoggerProvider添加。
一、 配置LoggerFactory
我們?cè)谏厦嬉还?jié)演示了一個(gè)展示ASP.NET Core默認(rèn)注冊(cè)服務(wù)的實(shí)例,細(xì)心的讀者一定會(huì)看到顯示的列表中就包含了針對(duì)LoggerFactory的服務(wù)。如果這個(gè)默認(rèn)的LoggerFactory服務(wù)不能滿足我們的需求,我們完全可以配置任何一個(gè)需要的LoggerFactory,針對(duì)LoggerFactory的設(shè)置可以直接調(diào)用WebHostBuilder的UseLoggerFactory方法來(lái)實(shí)現(xiàn)。
public interface IWebHostBuilder { IWebHostBuilder UseLoggerFactory(ILoggerFactory loggerFactory); IWebHostBuilder ConfigureLogging(Action<ILoggerFactory> configureLogging); ... }
不過(guò)針對(duì)日志的配置更多地還是體現(xiàn)在針對(duì)某種LoggerProvider的添加,而這可以通過(guò)調(diào)用WebHostBuilder的ConfigureLogging方法來(lái)完成。我們?cè)谏厦嫜菔镜膶?shí)例中就曾經(jīng)采用如下的方式將一個(gè)ConsoleLoggerProvider注冊(cè)到LoggerFactory之上,這樣我們可以直接在宿主應(yīng)用的擴(kuò)展臺(tái)上看到記錄的日志信息。
new WebHostBuilder() .ConfigureLogging(factory=>factory.AddConsole()) ...
既然LoggerFactory已經(jīng)作為一個(gè)服務(wù)進(jìn)行了注冊(cè),那么我們完全按照依賴注入的來(lái)獲取這個(gè)對(duì)象,并利用它創(chuàng)建對(duì)應(yīng)的Logger對(duì)象來(lái)寫日志。如果我們需要在一個(gè)定義的中間件中寫入某種類型的日志,就可以按照如下的方式在Invoke方法中定義ILoggerFactory類型的參數(shù)注入這個(gè)LoggerFactory。
public class FoobarMiddleware { private RequestDelegate _next; public FoobarMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context, ILoggerFactory loggerFactory) { ILogger<FoobarMiddleware> logger = loggerFactory.CreateLogger<FoobarMiddleware>(); logger.LogInformation("..."); await _next(context); } }
不僅僅我們開(kāi)發(fā)的應(yīng)用或者中間件可以利用注冊(cè)的LoggerFactory來(lái)創(chuàng)建進(jìn)行日志記錄的Logger對(duì)象,ASP.NET Core管道本身也會(huì)在處理請(qǐng)求過(guò)程中采用相同的方式記錄一些日志。比如管道每次處理請(qǐng)求的開(kāi)始和結(jié)束時(shí)候分別會(huì)寫入兩條Information等級(jí)的日志,我們現(xiàn)在就來(lái)通過(guò)一個(gè)簡(jiǎn)單的實(shí)例看看這兩條日志信息具有怎樣的內(nèi)容。
public class Program { public static void Main() { new WebHostBuilder() .ConfigureLogging(factory=>factory.AddConsole()) .UseKestrel() .UseStartup<Startup>() .Build() .Run(); } } public class Startup { public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) { app.Run(async context => { loggerFactory.CreateLogger("App").LogInformation("Log entry for test..."); await context.Response.WriteAsync("Hello world!"); }); } }
如上所示的代碼有兩處與日志有關(guān),第一個(gè)地方是調(diào)用WebHostBuilder的ConfigureLogging方法通過(guò)調(diào)用擴(kuò)展方法AddConsole將一個(gè)ConsoleProvider添加到當(dāng)前LoggerFactory之上,另一個(gè)地方就是啟動(dòng)類的Configure方法注冊(cè)的中間件在執(zhí)行過(guò)程中會(huì)利用注入的LoggerFactory創(chuàng)建一個(gè)Logger對(duì)象,我們利用后者寫入了一條Information等級(jí)的日志。我們運(yùn)行程序之后利用瀏覽器訪問(wèn)目標(biāo)地址后,宿主控制臺(tái)上會(huì)出現(xiàn)如下圖所示的三條日志。除了第二條日志是由我們自己編寫的代碼寫入的之外,其余兩條都是ASP.NET Core框架自己寫入的。第一條日志包含不僅僅包含請(qǐng)求的目標(biāo)地址,還包括請(qǐng)求采用的協(xié)議(HTTP/1.1)和HTTP方法(GET),第三條則反映了整個(gè)請(qǐng)求處理過(guò)程所花的時(shí)間。
由于ASP.NET Core管道對(duì)請(qǐng)求的處理總是在一個(gè)由HttpApplication創(chuàng)建的執(zhí)行上下文中進(jìn)行,所以上下文的創(chuàng)建和回收釋放可以視為 整個(gè)請(qǐng)求處理流程開(kāi)始和結(jié)束的標(biāo)識(shí)。對(duì)于上述的這兩條分別在處理請(qǐng)求開(kāi)始和結(jié)束時(shí)寫入的日志,實(shí)際上是在HostingApplication的CreateContext和DisposeContext方法分別被調(diào)用的時(shí)候被記錄下來(lái)的。之所以在結(jié)束的時(shí)候能夠計(jì)算出整個(gè)請(qǐng)求處理過(guò)程所花的時(shí)間,是因?yàn)閯?chuàng)建的這個(gè)上下文對(duì)象保存了開(kāi)始處理請(qǐng)求的時(shí)間戳,該時(shí)間戳對(duì)應(yīng)著Context結(jié)構(gòu)的StartTimestamp屬性。
public class HostingApplication IHttpApplication<HostingApplication.Context> { public struct Context { public HttpContext HttpContext { get; set; } public IDisposable Scope { get; set; } public long StartTimestamp { get; set; } } }
二、以當(dāng)前請(qǐng)求作為日志范圍
我們知道日志系統(tǒng)有一個(gè)叫做“日志范圍”的概念,它的目的在于為多次相關(guān)的日志記錄創(chuàng)建一個(gè)上下文范圍,并為這個(gè)范圍提供一個(gè)標(biāo)識(shí),這個(gè)標(biāo)識(shí)會(huì)作為日志內(nèi)容的一部分被寫入。當(dāng)我們?cè)谶M(jìn)行日志分析的時(shí)候,可以根據(jù)日志范圍標(biāo)識(shí)將一組原本獨(dú)立的日志關(guān)聯(lián)起來(lái)。這個(gè)概念對(duì)于Web應(yīng)用尤為重要,因?yàn)楹芏嗲闆r下我們所做的日志分析都是針對(duì)某一個(gè)請(qǐng)求,這就要求我們必須明確地分辨出被記錄下來(lái)的日志隸屬于哪一個(gè)請(qǐng)求,只有這樣才能將針對(duì)同一請(qǐng)求的所有日志提取出來(lái)做綜合的分析以得出一個(gè)準(zhǔn)確的結(jié)論。
從上個(gè)實(shí)例最終寫入的三條日志來(lái)看,它們并不攜帶當(dāng)前請(qǐng)求的標(biāo)識(shí)信息。但是這不是ASP.NET Core的問(wèn)題,而是我們?cè)谡{(diào)用LoggerFactory的擴(kuò)展方法AddConsole注冊(cè)ConsoleLoggerProvider的時(shí)候并未顯式開(kāi)啟針對(duì)日志范圍的支持。為了讓注冊(cè)的ConsoleLoggerProvider創(chuàng)建的Logger能夠支持日志范圍,我們只需按照如下的方式在調(diào)用AddConsole方法的時(shí)候添加一個(gè)額外的參數(shù)(true)即可。
new WebHostBuilder() .ConfigureLogging(factory=>factory.AddConsole(true)) .UseKestrel() .UseStartup<Startup>() .Build() .Run();
我們?cè)俅握?qǐng)求應(yīng)用并利用瀏覽器對(duì)目標(biāo)地址發(fā)送兩次請(qǐng)求,六條寫入的日志將會(huì)以如下圖所示的形式輸出到控制臺(tái)上。不同于上面的輸出結(jié)果,本次輸出的日志包含請(qǐng)求的ID(Request Id),在同一個(gè)請(qǐng)求下被記錄下來(lái)的日志具有相同的ID。除了請(qǐng)求ID,記錄的日志還攜帶了請(qǐng)求的路徑(Request Path)。
日志范圍攜帶的用于標(biāo)識(shí)當(dāng)前請(qǐng)求的ID,同時(shí)也可以視為當(dāng)前HttpContext的標(biāo)識(shí),它對(duì)應(yīng)著HttpContext的TranceIdentifier屬性。對(duì)于DefaultHttpContext來(lái)說(shuō),針對(duì)這個(gè)屬性的讀寫是借助一個(gè)名為HttpRequestIdentifierFeature的特性實(shí)現(xiàn)的,下面的代碼提供了該對(duì)象對(duì)應(yīng)的接口IHttpRequestIdentifierFeature和默認(rèn)實(shí)現(xiàn)類HttpRequestIdentifierFeature的定義。
public abstract class HttpContext { //省略其他成員 public abstract string TraceIdentifier { get; set; } } public interface IHttpRequestIdentifierFeature { string TraceIdentifier { get; set; } } public class HttpRequestIdentifierFeature IHttpRequestIdentifierFeature { private string _id; private static long _requestId = DateTime.UtcNow.Ticks; private static unsafe string GenerateRequestId(long id); public string TraceIdentifier { get { return _id??(id= GenerateRequestId(Interlocked.Increment(ref _requestId))); } set { this._id = value; } } }
HttpRequestIdentifierFeature生成TraceIdentifier的邏輯很簡(jiǎn)單。如上面的代碼片斷所示,它具有一個(gè)靜態(tài)長(zhǎng)整型字段_requestId,其初始值為當(dāng)前時(shí)間戳。對(duì)于某個(gè)具體的HttpRequestIdentifierFeature對(duì)象來(lái)說(shuō),它的TraceIdentifier屬性的默認(rèn)值返回的是這個(gè)字段_requestId加1之后轉(zhuǎn)換的字符串。具體的轉(zhuǎn)換邏輯定義在GenerateRequestId方法中,它會(huì)采用相應(yīng)的算法 將指定的整數(shù)轉(zhuǎn)換一個(gè)長(zhǎng)度為13的字符串。
和開(kāi)始請(qǐng)求處理的時(shí)間戳一樣,被創(chuàng)建出來(lái)的日志范圍實(shí)際被保存在HostingApplication的上下文對(duì)象中,它對(duì)應(yīng)著Context結(jié)構(gòu)的Scope屬性。當(dāng)HostingApplication創(chuàng)建這個(gè)Context對(duì)象的時(shí)候,它會(huì)從當(dāng)前HttpContext中提取出請(qǐng)求的ID和路徑,創(chuàng)建出這個(gè)日志范圍并賦值給這個(gè)屬性。整個(gè)請(qǐng)求的處理其實(shí)就在這個(gè)日志范圍中進(jìn)行,請(qǐng)求處理結(jié)束,當(dāng)前日志范文也被回收釋放。
public class HostingApplication IHttpApplication<HostingApplication.Context> { public struct Context { public HttpContext HttpContext { get; set; } public IDisposable Scope { get; set; } public long StartTimestamp { get; set; } } }
三、記錄異常日志
由于ASP.NET Core在處理請(qǐng)求過(guò)程中導(dǎo)致的異常并不會(huì)導(dǎo)致應(yīng)用終止,考慮到安全,拋出的異常的詳細(xì)信息也不應(yīng)該直接返回到客戶端。所以在很多情況下我們根本感知不到應(yīng)用發(fā)生了異常,即使感知到了,也不知道導(dǎo)致異常的根源在何處。在這種情況下,我們就需要使用記錄的日志進(jìn)行差錯(cuò)和糾錯(cuò),因?yàn)锳SP.NET Core在處理請(qǐng)求遇到的異常都會(huì)記錄到日志中。
比如針對(duì)如下這段程序,毫無(wú)疑問(wèn)它針對(duì)任何一個(gè)請(qǐng)求的處理都會(huì)拋出一個(gè)DivideByZeroException的異常。如果我們利用瀏覽器來(lái)訪問(wèn)站點(diǎn)地址,它只會(huì)得到一個(gè)狀態(tài)為500的響應(yīng),并簡(jiǎn)單的提示服務(wù)端出現(xiàn)錯(cuò)誤。對(duì)于宿主程序來(lái)說(shuō),我們根本就是感知不到任何異常發(fā)生。
new WebHostBuilder() .UseKestrel() .Configure(app=>app.Run(async context=> { int x = 1; int y = 0; await context.Response.WriteAsync((x / y).ToString()); })) .Build() .Run();
在這種情況下我們可以通過(guò)查看日志得到異常的詳細(xì)信息,不過(guò)在這之前必須為L(zhǎng)oggerFactory注冊(cè)相應(yīng)的LoggerProvider。如果我們采用控制臺(tái)應(yīng)用作為宿主,在開(kāi)發(fā)或者調(diào)試的時(shí)候最簡(jiǎn)單的莫過(guò)于按照如下的方式注冊(cè)一個(gè)ConsoleLoggerProvider讓日志可以直接寫入宿主程序的控制臺(tái)。
new WebHostBuilder() .ConfigureLogging(factory=>factory.AddConsole (true)) .UseKestrel() .Configure(app=>app.Run(async context=> { int x = 1; int y = 0; await context.Response.WriteAsync((x / y).ToString()); })) .Build() .Run();
一旦為L(zhǎng)oggerFactory注冊(cè)了這么一個(gè)ConsoleLoggerProvider,對(duì)于服務(wù)端出現(xiàn)的未處理的任何異常,我們都可以直接在宿主控制臺(tái)上看到錯(cuò)誤的詳細(xì)信息,下圖就是上面這個(gè)例子拋出的DivideByZeroException異常的詳細(xì)信息。
以上是“ASP.NET Core應(yīng)用中怎么記錄和查看日志”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
當(dāng)前名稱:ASP.NETCore應(yīng)用中怎么記錄和查看日志-創(chuàng)新互聯(lián)
網(wǎng)站鏈接:http://redsoil1982.com.cn/article0/hppoo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、關(guān)鍵詞優(yōu)化、域名注冊(cè)、網(wǎng)站排名、品牌網(wǎng)站設(shè)計(jì)、建站公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容