博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
引入Jaeger——封装
阅读量:4035 次
发布时间:2019-05-24

本文共 9017 字,大约阅读时间需要 30 分钟。

随着微服务的普及,微服务间的调用全链路跟踪也火了起来,Jaeger(https://www.jaegertracing.io/)是CNCF孵化的全链路跟踪型项目,在.net core中,提供了一个Jaeger的Nuget(https://github.com/jaegertracing/jaeger-client-csharp)包来使用。

本例封装就是用这个Nuget包来做成asp.net core中间件和action过滤器:中间件可以把所有经过管道的请求都跟踪起来,如果觉得这样的跟踪太重,或者没有必要收集所有请求,只跟踪有链路关联的请求,那就可以用action过滤器。

定义一个Options,这是自定义跟踪收集数据的配置属性

namespace JaegerSharp{    ///     /// Jaeger选项    ///     public class JaegerOptions    {        ///         /// 是否启用Form数据转成Span        ///         public bool IsFormSpan { get; set; } = false;        ///         /// Form数据最大长度        ///         public int FormValueMaxLength { get; set; } = 100;        ///         /// 是否启用Query数据转成Span        ///         public bool IsQuerySpan { get; set; } = false;        ///         /// Query最大长度        ///         public int QueryValueMaxLength { get; set; } = 100;        ///         /// Form或Query中不作为Span的key集合        ///         public string[] NoSpanKeys { get; set; } = new string[] { "password", "pwd" };    }}

跟踪中间件,把所有的请求都收集起来

using Microsoft.AspNetCore.Http;using Microsoft.Extensions.Logging;using OpenTracing;using OpenTracing.Propagation;using System;using System.IO;using System.Linq;using System.Threading.Tasks;namespace JaegerSharp{    ///     /// Jaeger中间件    ///     public class JaegerSharpMiddleware    {        ///         /// jaeger选项        ///         private readonly JaegerOptions _jaegerOptions;        ///         /// 日志        ///         private readonly ILogger
_logger; ///
/// 请求代理 /// private readonly RequestDelegate _next; public JaegerSharpMiddleware(RequestDelegate next, ILogger
logger, JaegerOptions jaegerOptions = null) { _next = next; _jaegerOptions = jaegerOptions;            _logger = logger; } ///
/// 调用管道 /// ///
上下文 ///
跟踪器 ///
public async Task InvokeAsync(HttpContext context, ITracer tracer) { _logger.LogInformation("jaeger调用"); var path = context.Request.Path; if (Path.HasExtension(path)) { await _next(context); } else { //接收传入的Headers var callingHeaders = new TextMapExtractAdapter(context.Request.Headers.ToDictionary(m => m.Key, m => m.Value.ToString())); var spanContex = tracer.Extract(BuiltinFormats.HttpHeaders, callingHeaders); ISpanBuilder builder = null; if (spanContex != null) { builder = tracer.BuildSpan("中间件Span").AsChildOf(spanContex); } else { builder = tracer.BuildSpan("中间件Span"); } //开始设置Span using (IScope scope = builder.StartActive(true)) { scope.Span.SetOperationName(path); // 记录请求信息到span if (_jaegerOptions.IsQuerySpan) { foreach (var query in context.Request.Query) { //包含敏感词跳出 if (_jaegerOptions.NoSpanKeys.Contains(query.Key)) { continue; } var value = query.Value.ToString().Length > _jaegerOptions.QueryValueMaxLength ? query.Value.ToString()?.Substring(0, _jaegerOptions.QueryValueMaxLength) : query.Value.ToString(); scope.Span.SetTag(query.Key, value); } } if (_jaegerOptions.IsFormSpan && context.Request.HasFormContentType) { foreach (var form in context.Request.Form) { //包含敏感词跳出 if (_jaegerOptions.NoSpanKeys.Contains(form.Key)) { continue; } var value = form.Value.ToString().Length > _jaegerOptions.FormValueMaxLength ? form.Value.ToString()?.Substring(0, _jaegerOptions.FormValueMaxLength) : form.Value.ToString(); scope.Span.SetTag(form.Key, value); } } await _next(context); } } } }}

扩展中间件

using Microsoft.AspNetCore.Builder;namespace JaegerSharp{    ///     /// 使用JaegerSharp中间件    ///     public static class JaegerSharpMiddlewareExtensions    {        public static IApplicationBuilder UseJaegerSharp(this IApplicationBuilder builder)        {            return builder.UseMiddleware
(new JaegerOptions()); } public static IApplicationBuilder UseJaegerSharp(this IApplicationBuilder builder, JaegerOptions jaegerOptions) { return builder.UseMiddleware
(jaegerOptions); } }}

action过滤器,用来准确收集跟踪信息

using Microsoft.AspNetCore.Mvc;using Microsoft.AspNetCore.Mvc.Filters;using OpenTracing;using OpenTracing.Propagation;using System.Linq;namespace JaegerSharp{    ///     /// 使用Jaeger的Action过滤器添加Jaeger实列    ///     public class JaegerSharpAttribute : TypeFilterAttribute    {        public JaegerSharpAttribute() : base(typeof(JaegerFilterAttributeImpl))        {        }        ///         /// 真正实现Jaeger Scope的类        ///         private class JaegerFilterAttributeImpl : IActionFilter        {            private readonly ITracer _tracer;            public JaegerFilterAttributeImpl(ITracer tracer)            {                _tracer = tracer;            }            IScope _scope = null;            ///             /// 开始执行Action            ///             ///             public void OnActionExecuting(ActionExecutingContext context)            {                var path = context.HttpContext.Request.Path;                var callingHeaders = new TextMapExtractAdapter(context.HttpContext.Request.Headers.ToDictionary(m => m.Key, m => m.Value.ToString()));                var spanContex = _tracer.Extract(BuiltinFormats.HttpHeaders, callingHeaders);                ISpanBuilder builder = null;                if (spanContex != null)                {                    builder = _tracer.BuildSpan("中间件Span").AsChildOf(spanContex);                }                else                {                    builder = _tracer.BuildSpan("中间件Span");                }                _scope = builder.StartActive(true);                _scope.Span.SetOperationName(path);                // 记录请求信息到span                foreach (var query in context.HttpContext.Request.Query)                {                    _scope.Span.SetTag(query.Key, query.Value);                }                if (context.HttpContext.Request.HasFormContentType)                {                    foreach (var form in context.HttpContext.Request.Form)                    {                        _scope.Span.SetTag(form.Key, form.Value);                    }                }            }            ///             /// Action结束执行            ///             ///             public void OnActionExecuted(ActionExecutedContext context)            {                _scope?.Dispose();            }        }    }}

封装Jaeger在asp.net core中的注放步骤,使注入简单

using Jaeger;using Jaeger.Reporters;using Jaeger.Samplers;using Jaeger.Senders.Thrift;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;using OpenTracing;using OpenTracing.Util;using System.Reflection;namespace JaegerSharp{    public static class JaegerSharpExtensions    {        ///         /// 注入Jaeger        ///         /// 服务容器        /// Jaeger agent host        /// Jaeger agent port        /// Jaeger agent maxpacketsize        public static void AddJaegerSharp(this IServiceCollection services, string host, int port, int maxPacketSize)        {                 services.AddSingleton
(serviceProvider => { var loggerFactory = serviceProvider.GetRequiredService
(); var reporter = new RemoteReporter.Builder() .WithLoggerFactory(loggerFactory) .WithSender(new UdpSender(string.IsNullOrEmpty(host) ? UdpSender.DefaultAgentUdpHost : host, port <= 100 ? UdpSender.DefaultAgentUdpCompactPort : port, maxPacketSize <= 0 ? 0 : maxPacketSize)) .Build(); ITracer tracer = new Tracer.Builder(Assembly.GetEntryAssembly().GetName().Name) .WithReporter(reporter) .WithLoggerFactory(loggerFactory) .WithSampler(new ConstSampler(true)) .Build(); GlobalTracer.Register(tracer); return tracer; }); } }}

转载地址:http://ykudi.baihongyu.com/

你可能感兴趣的文章
计算机的发展史
查看>>
带WiringPi库的交叉编译如何处理一
查看>>
带WiringPi库的交叉笔译如何处理二之软链接概念
查看>>
Spring事务的七种传播行为
查看>>
ES写入找不到主节点问题排查
查看>>
Java8 HashMap集合解析
查看>>
ArrayList集合解析
查看>>
欢迎使用CSDN-markdown编辑器
查看>>
Android计算器实现源码分析
查看>>
Android系统构架
查看>>
Android 跨应用程序访问窗口知识点总结
查看>>
各种排序算法的分析及java实现
查看>>
SSH框架总结(框架分析+环境搭建+实例源码下载)
查看>>
js弹窗插件
查看>>
自定义 select 下拉框 多选插件
查看>>
js判断数组内是否有重复值
查看>>
js获取url链接携带的参数值
查看>>
gdb 调试core dump
查看>>
gdb debug tips
查看>>
arm linux 生成火焰图
查看>>