引入Jaeger——封装

2023-11-06 02:48
文章标签 封装 引入 jaeger

本文主要是介绍引入Jaeger——封装,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

随着微服务的普及,微服务间的调用全链路跟踪也火了起来,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
{/// <summary>/// Jaeger选项/// </summary>public class JaegerOptions{/// <summary>/// 是否启用Form数据转成Span/// </summary>public bool IsFormSpan { get; set; } = false;/// <summary>/// Form数据最大长度/// </summary>public int FormValueMaxLength { get; set; } = 100;/// <summary>/// 是否启用Query数据转成Span/// </summary>public bool IsQuerySpan { get; set; } = false;/// <summary>/// Query最大长度/// </summary>public int QueryValueMaxLength { get; set; } = 100;/// <summary>/// Form或Query中不作为Span的key集合/// </summary>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
{/// <summary>/// Jaeger中间件/// </summary>public class JaegerSharpMiddleware{/// <summary>/// jaeger选项/// </summary>private readonly JaegerOptions _jaegerOptions;/// <summary>/// 日志/// </summary>private readonly ILogger<JaegerSharpMiddleware> _logger;/// <summary>/// 请求代理/// </summary>private readonly RequestDelegate _next;public JaegerSharpMiddleware(RequestDelegate next, ILogger<JaegerSharpMiddleware> logger, JaegerOptions jaegerOptions = null){_next = next;_jaegerOptions = jaegerOptions;_logger = logger;}/// <summary>/// 调用管道/// </summary>/// <param name="context">上下文</param>/// <param name="tracer">跟踪器</param>/// <returns></returns>public async Task InvokeAsync(HttpContext context, ITracer tracer){_logger.LogInformation("jaeger调用");var path = context.Request.Path;if (Path.HasExtension(path)){await _next(context);}else{//接收传入的Headersvar 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");}//开始设置Spanusing (IScope scope = builder.StartActive(true)){scope.Span.SetOperationName(path);             // 记录请求信息到spanif (_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
{/// <summary>/// 使用JaegerSharp中间件/// </summary>public static class JaegerSharpMiddlewareExtensions{public static IApplicationBuilder UseJaegerSharp(this IApplicationBuilder builder){return builder.UseMiddleware<JaegerSharpMiddleware>(new JaegerOptions());}public static IApplicationBuilder UseJaegerSharp(this IApplicationBuilder builder, JaegerOptions jaegerOptions){return builder.UseMiddleware<JaegerSharpMiddleware>(jaegerOptions);}}
}

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

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using OpenTracing;
using OpenTracing.Propagation;
using System.Linq;namespace JaegerSharp
{/// <summary>/// 使用Jaeger的Action过滤器添加Jaeger实列/// </summary>public class JaegerSharpAttribute : TypeFilterAttribute{public JaegerSharpAttribute() : base(typeof(JaegerFilterAttributeImpl)){}/// <summary>/// 真正实现Jaeger Scope的类/// </summary>private class JaegerFilterAttributeImpl : IActionFilter{private readonly ITracer _tracer;public JaegerFilterAttributeImpl(ITracer tracer){_tracer = tracer;}IScope _scope = null;/// <summary>/// 开始执行Action/// </summary>/// <param name="context"></param>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);// 记录请求信息到spanforeach (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);}}}/// <summary>/// Action结束执行/// </summary>/// <param name="context"></param>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{/// <summary>/// 注入Jaeger/// </summary>/// <param name="services">服务容器</param>/// <param name="host">Jaeger agent host</param>/// <param name="port">Jaeger agent port</param>/// <param name="maxPacketSize">Jaeger agent maxpacketsize</param>public static void AddJaegerSharp(this IServiceCollection services, string host, int port, int maxPacketSize){     services.AddSingleton<ITracer>(serviceProvider =>{var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();              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;});}}
}

这篇关于引入Jaeger——封装的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/354044

相关文章

CSS引入方式和选择符的讲解和运用小结

《CSS引入方式和选择符的讲解和运用小结》CSS即层叠样式表,是一种用于描述网页文档(如HTML或XML)外观和格式的样式表语言,它主要用于将网页内容的呈现(外观)和结构(内容)分离,从而实现... 目录一、前言二、css 是什么三、CSS 引入方式1、行内样式2、内部样式表3、链入外部样式表四、CSS 选

一文详解如何在Vue3中封装API请求

《一文详解如何在Vue3中封装API请求》在现代前端开发中,API请求是不可避免的一部分,尤其是与后端交互时,下面我们来看看如何在Vue3项目中封装API请求,让你在实现功能时更加高效吧... 目录为什么要封装API请求1. vue 3项目结构2. 安装axIOS3. 创建API封装模块4. 封装API请求

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

鸿蒙中Axios数据请求的封装和配置方法

《鸿蒙中Axios数据请求的封装和配置方法》:本文主要介绍鸿蒙中Axios数据请求的封装和配置方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.配置权限 应用级权限和系统级权限2.配置网络请求的代码3.下载在Entry中 下载AxIOS4.封装Htt

在React中引入Tailwind CSS的完整指南

《在React中引入TailwindCSS的完整指南》在现代前端开发中,使用UI库可以显著提高开发效率,TailwindCSS是一个功能类优先的CSS框架,本文将详细介绍如何在Reac... 目录前言一、Tailwind css 简介二、创建 React 项目使用 Create React App 创建项目

SpringBoot中封装Cors自动配置方式

《SpringBoot中封装Cors自动配置方式》:本文主要介绍SpringBoot中封装Cors自动配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录SpringBoot封装Cors自动配置背景实现步骤1. 创建 GlobalCorsProperties

一文教你Python引入其他文件夹下的.py文件

《一文教你Python引入其他文件夹下的.py文件》这篇文章主要为大家详细介绍了如何在Python中引入其他文件夹里的.py文件,并探讨几种常见的实现方式,有需要的小伙伴可以根据需求进行选择... 目录1. 使用sys.path动态添加路径2. 使用相对导入(适用于包结构)3. 使用pythonPATH环境

Java导入、导出excel用法步骤保姆级教程(附封装好的工具类)

《Java导入、导出excel用法步骤保姆级教程(附封装好的工具类)》:本文主要介绍Java导入、导出excel的相关资料,讲解了使用Java和ApachePOI库将数据导出为Excel文件,包括... 目录前言一、引入Apache POI依赖二、用法&步骤2.1 创建Excel的元素2.3 样式和字体2.

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表