前言
.NetCore日志,相信大家多少都接触过,博客园有关 ① AspNetCore依赖注入第三方日志组件 ②第三方日志组件Nlog,Serilog 应用方法的博文层出不穷。
结合程序的部署结构,本文分单体和微服务聊一聊AspNetCore中追踪日志流的方法。
TraceId
AspNetCore程序基于Pipeline和中间件处理请求, 根据需要记录日志; 生产出故障时,在数量庞大的日志记录中追踪某个请求完整的处理链显得很有必要(这个深有体会)。
针对单体程序,AspNetCore贴心的为我们提供了HttpContext.TraceIdentifier属性, 这个TraceId由{ConnectionId}:{Request Number}组成,理论上这个id标记了位于某Http连接上的某次请求。
① 为什么由 {ConnectionId}:{Request Number}组成?
默认大部分读者知晓Http1.1 一个连接上可发起多个Http请求
② TraceId 中ConnectionId由Kestrel从{0-9,a-z}中生成,可参考:https://github.com/aspnet/KestrelHttpServer/blob/a48222378b8249a26b093b5b835001c7c7b45815/src/Kestrel.Core/Internal/Infrastructure/CorrelationIdGenerator.cs
ok, 现在着重聊一下使用方式和衍生知识点
① 启用NLog日志
添加
public class Program
{
public static void Main(string[] args)
{
var webHost = WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, configureDelagate) =>
{
configureDelagate.AddJsonFile($"appsettings.secrets.json", optional: true, reloadOnChange: true);
})
.ConfigureLogging((hostingContext, loggingBuilder) =>
{
loggingBuilder.AddConsole().AddDebug();
})
.UseNLog() // 默认会找工作目录下nlog.config配置文件
.UseStartup()
.Build();
webHost.Run();
}
}
很明显,Nlog要在Pipeline中自由获取HttpContext属性,这里需要注册IHttpContextAccessor
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton();
}
}
② 配置Nlog 以显示TraceId
TraceId在Nlog 是以Layout Renderer形式表达的:
更多的Renderer参考。下面的Nlog配置文件呈现了TraceId & User_Id(业务上的UserId能帮助我们在茫茫日志中快速缩小日志)
"1.0" encoding="utf-8" ?>"http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true" throwExceptions="false" internalLogFile="internal-nlog.txt"> "logDir" value="logs/${date:format=yyyyMMdd}" /> "format" value="${date:format=yy/MM/dd HH\:mm\:ss} [${level}].[${logger}].[${aspnet-TraceIdentifier}].[${aspnet-user-identity}]${newline}${message} ${exception:format=tostring}" /> "info" xsi:type="File" layout="${format}" fileName="${logDir}/info.log" encoding="utf-8"/> "*" minlevel="Info" writeTo="info" />
结果如下:
以上是在单体程序内根据traceid追踪请求流的方法。
进一步思考,在微服务中,各服务独立形成TraceId,在初始阶段生成 TraceId 并在各微服务中保持该Traceid即可追踪微服务的请求流。
CorrelationId
这里首先假设你的微服务/ 分布式服务已经部署ELK 等日志几种采集处理框架,没有部署ELK也可将多个服务的日志写到同一个物理文件夹。
隆重介绍轮子 CorrelationId: https:/github.com/stevejgordon/CorrelationId
CorrelationId是通过自定义Header来标记TraceId概念
-
CorrelationId 在首次收到请求时自定义名为【
X-Correlation-ID
】 的请求头,在本服务Response写入该Header -
后置服务检测到请求头中包含该Header, 将该CorrelationId作为本服务的TraceId 向后流转
这样在集中日志中,能通过某TraceID追踪微服务/分布式 全链路请求处理日志。
使用方式也相当简单:
// Install-Package CorrelationId -Version 2.1.0
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddCorrelationId();
}
一般在所有请求处理Middleware之前注册 CorrelationId, 这样在所有中间件就能获取到 TraceId:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCorrelationId();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
打算应用该TraceId追踪全流程请求日志的服务都需要包含 中间件。
Ok, 本文由浅入深TraceID在单体程序和 分布式程序中的应用, 希望对大家在日志排障时有所帮助。