在ProductApi中我们只需要编写挪用RegisterZipkinTrace要领即可,和OrderApi一样,我们就不反复粘贴了。因为ProductApi不需要挪用此外处事,所以可以不必利用集成HttpClient,只需要提供简朴的接口即可
[Route("productapi/[controller]")] public class ProductController : ControllerBase { private List<ProductDto> productDtos = new List<ProductDto>(); public ProductController() { productDtos.Add(new ProductDto { Id = 1,Name="酒精",Price=22.5m }); productDtos.Add(new ProductDto { Id = 2, Name = "84消毒液", Price = 19.9m }); } /// <summary> /// 获取所有商品信息 /// </summary> /// <returns></returns> [HttpGet("getall")] public IEnumerable<ProductDto> GetAll() { return productDtos; } }
启动这两个项目,挪用OrderApi的getdetails接口,完成后打开zipkin界面
点击进去可查察链路详情总结起来焦点操纵其实就两个,一个是在发送请求的处所,利用TracingHandler记录提倡端的链路环境,然后在吸收请求的处事端利用UseTracing记录来自于客户端请求的链路环境。
改造集成方法
其实在上面的演示中,我们可以明明的看到明明的不敷,就是许多时候其实我们没步伐去配置HttpClient相关的参数的,许多框架固然也是利用的HttpClient或HttpClientFactory相关,可是在外部我们没步伐通过自界说的方法去配置他们的相关操纵,好比Ocelot其实也是利用HttpClient相关提倡的转发请求,可是对外我们没步伐通过我们的措施去配置HttpClient的参数。尚有就是在.Net Core中WebRequest其实也是对HttpClient的封装,可是我们同样没步伐在我们的措施中给他们通报雷同TracingHandler的操纵。此刻我们从TracingHandler源码开始解读看看它的内部到底是如何事情的,zipkin官方提供的.net core插件zipkin4net的源码位于
https://github.com/openzipkin/zipkin4net,我们找到TracingHandler类地址的位置[点击查察源码👈],由于TracingHandler自己就是DelegatingHandler的子类,所以我们主要看SendAsync要领,大抵抽离出来如下
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { Func<HttpRequestMessage, string> _getClientTraceRpc = _getClientTraceRpc = getClientTraceRpc ?? (request => request.Method.ToString()); IInjector<HttpHeaders> _injector = Propagations.B3String.Injector<HttpHeaders>((carrier, key, value) => carrier.Add(key, value)); //记录提倡请求客户端链路信息的类是ClientTrace using (var clientTrace = new ClientTrace(_serviceName, _getClientTraceRpc(request))) { if (clientTrace.Trace != null) { _injector.Inject(clientTrace.Trace.CurrentSpan, request.Headers); } var result = await clientTrace.TracedActionAsync(base.SendAsync(request, cancellationToken)); //AddAnnotation是记录标签信息,我们可以在zipkin链路详情中看到这些标签 if (clientTrace.Trace != null) { //记录请求路径 clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_PATH, result.RequestMessage.RequestUri.LocalPath)); //记录请求的http要领 clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_METHOD, result.RequestMessage.Method.Method)); if (_logHttpHost) { //记录主机 clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_HOST, result.RequestMessage.RequestUri.Host)); } if (!result.IsSuccessStatusCode) { clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_STATUS_CODE, ((int)result.StatusCode).ToString())); } } return result; } }
实现方法较量简朴,就是借助ClientTrace记录一些标签,其他的相关操纵都是由zipkin4net提供的。我们在之前的文章.Net Core中的诊断日志DiagnosticSource讲授中层说道HttpClient底层会有发出诊断日志,我们可以借助这个思路,来对HttpClient举办链路跟踪埋点。
我们团结Microsoft.Extensions.DiagnosticAdapter扩展包界说如下类
public class HttpDiagnosticListener: ITraceDiagnosticListener { public string DiagnosticName => "HttpHandlerDiagnosticListener"; private ClientTrace clientTrace; private readonly IInjector<HttpHeaders> _injector = Propagations.B3String.Injector<HttpHeaders>((carrier, key, value) => carrier.Add(key, value)); [DiagnosticName("System.Net.Http.Request")] public void HttpRequest(HttpRequestMessage request) { clientTrace = new ClientTrace("apigateway", request.Method.Method); if (clientTrace.Trace != null) { _injector.Inject(clientTrace.Trace.CurrentSpan, request.Headers); } } [DiagnosticName("System.Net.Http.Response")] public void HttpResponse(HttpResponseMessage response) { if (clientTrace.Trace != null) { clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_PATH, response.RequestMessage.RequestUri.LocalPath)); clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_METHOD, response.RequestMessage.Method.Method)); clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_HOST, response.RequestMessage.RequestUri.Host)); if (!response.IsSuccessStatusCode) { clientTrace.AddAnnotation(Annotations.Tag(zipkinCoreConstants.HTTP_STATUS_CODE, ((int)response.StatusCode).ToString())); } } } [DiagnosticName("System.Net.Http.Exception")] public void HttpException(HttpRequestMessage request,Exception exception) { } }