前言

Asp.Net Core中有一个不受人重视的属性HttpContext.TraceIdentifier,它在链路追踪中非常有用,下面是官方的定义:

在项目中一般会将该字段输出到每一条日志中,也可以将此Id作为通用响应字段返回前端,后续可以根据该属性和日志匹配,快速定位整个链路日志。在本地开发时我通常观察到该值的格式大概如下长这个样子0HLEACIU86PT6:0000000D,在生产环境中查看日志时,却不是这种格式,而是Guid格式,虽然都是唯一标识,都能满足我的需要,但是为什么会产生这一差异令我困惑,最初以为是第三方日志组件对该字段进行了赋值,在我的不懈努力下,最终确定该差异的原因是部署方式差异导致,分享给各位。

差异对比

创建一个Asp.Net Core新项目,在示例代码中添加一行日志,打印该属性

[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
    _logger.LogInformation(Request.HttpContext.TraceIdentifier);

    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateTime.Now.AddDays(index),
        TemperatureC = Random.Shared.Next(-20, 55),
        Summary = Summaries[Random.Shared.Next(Summaries.Length)]
    })
    .ToArray();
}

Kestre部署时的表现

VS中使用控制台启动项目,调用几次接口,输出如下
HttpContext.TraceIdentifier那严谨的设计-LMLPHP
可见TraceIdentifier有下面两部分组成{ConnectionId}:{Request number},第一部分ConnectionId标识同一次连接,第二部分Request number标识,当前是该连接的第n次请求起到计数的作用。
而两者的组成{ConnectionId}:{Request number}就可以标识唯一一次请求。

IIS部署时的表现

用上面的的程序,不做任何更改,在VSIIS Express启动,调用几次接口,输出如下,由于没使用文件日志,IIS Express启动时没有窗口可以看输出,只能通过VS的调试窗口查看输出如下:
HttpContext.TraceIdentifier那严谨的设计-LMLPHP
这里可以很明显的看出,我们打印的TraceIdentifierGUID格式。

差异的原因

本地开发时我一般不会选择IIS Express启动,因为它速度慢,也不能方便的查看日志输出。所以正如上文测试的那样,我在本地使用只看到一种格式:{ConnectionId}:{Request number}

我们生产环境是部署在Windows Server中,而在windows下部署,使用IIS托管则比使用控制台更加安全稳定,所以这中部署方式输出的TraceIdentifier和上文中使用IIS Express表现是一致的。

那为何不同的部署方式产生该差异呢?

其实这是Asp.Net Core设计使然。在IIS上,它(TraceIdentifier)来自HTTP.sys(内核驱动程序)并暴露给应用程序,以便您可以跟踪该ID,从内核到应用程序并返回到内核,它的值来自IIS生成并传递给我们的应用。使用Kestrel,请求不需要iis对其进行转发,我们的应用程序就是链路的第一个程序,没有程序会传给它一个链路ID,所以程序自己需要生成一个,也就是我们看到的这种{ConnectionId}:{Request number}

总结

在不同的部署方式下,Asp.Net Core对TraceIdentifier有不同的表现,是技术上的一种严谨。在IIS部署时,该属性值来自IIS内核的传递,以便我们可以跟踪IIS内核到我们的程序,也保持了IIS式的风格。

本文来自博客园,作者:gui.h,转载请注明原文链接:https://www.cnblogs.com/springhgui/p/16282726.html

HttpContext.TraceIdentifier那严谨的设计-LMLPHP
05-17 22:42