ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

引入Jaeger——封装

2022-02-02 20:00:39  阅读:136  来源: 互联网

标签:封装 Jaeger tracer var context 引入 using public


  随着微服务的普及,微服务间的调用全链路跟踪也火了起来,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
{
//接收传入的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
{
/// <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);
// 记录请求信息到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);
}
}
}
/// <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,tracer,var,context,引入,using,public
来源: https://www.cnblogs.com/ljknlb/p/15860669.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有