首页 > 编程语言 >skyapm-dotnet 源码执行

skyapm-dotnet 源码执行

时间:2023-09-03 15:44:35浏览次数:48  
标签:void value listener var 源码 context skyapm dotnet diagnosticProcessor

监听System.Data.SqlClient 为例 通过观察者模式和 DiagnosticListener获取监听数据, 在开始InstrumentationHostedService实现IHostedService启动 然后通过 DiagnosticListener.AllListeners.Subscribe();监听  

然后 TracingDiagnosticProcessorObserver : IObserver<DiagnosticListener>{

        private readonly IEnumerable<ITracingDiagnosticProcessor> _tracingDiagnosticProcessors;

  public void OnNext(DiagnosticListener listener)
  {
      foreach (var diagnosticProcessor in _tracingDiagnosticProcessors.Distinct(x => x.ListenerName))
      {
          if (listener.Name == diagnosticProcessor.ListenerName)
          {
              Subscribe(listener, diagnosticProcessor);
              _logger.Information(
                  $"Loaded diagnostic listener [{diagnosticProcessor.ListenerName}].");
          }
      }
  }
}
通过next()获取所有监听,然后注入 ITracingDiagnosticProcessor 下的自定义诊断对象,获取诊断名称(ITracingDiagnosticProcessor 为所有诊断的对象的父接口 )
通过遍历对比,然后订阅,订阅前会先将诊断对象获取它的 方法,以及方法里的参数,和参数对应的特性类型(ObjectAttribute,PropertyAttribute
,这两个特性类型会存入对应特性属性值中后续在获取加监听对象的匿名参数时会获取到
),并将获取到的方法存入集合,还会将对象集合转为字典,转为字典作用就是在注册时
检查是否重复注册(   listener.Subscribe(diagnosticProcessor, diagnosticProcessor.IsEnabled);第二个参数执行委托返回bool,判断啊诊断名称是否存在)

//订阅代码

protected virtual void Subscribe(DiagnosticListener listener,
ITracingDiagnosticProcessor tracingDiagnosticProcessor)
{
   var diagnosticProcessor = new TracingDiagnosticObserver(tracingDiagnosticProcessor, _loggerFactory);
   listener.Subscribe(diagnosticProcessor, diagnosticProcessor.IsEnabled);
}






  

TracingDiagnosticObserver : IObserver<KeyValuePair<string, object>>  订阅明细

  _methodCollection = new TracingDiagnosticMethodCollection(tracingDiagnosticProcessor)
.  ToDictionary(method => method.DiagnosticName);


这里 通过 字典里的名称执行

public void OnNext(KeyValuePair<string, object> value)
{
  if (!_methodCollection.TryGetValue(value.Key, out var method))
  return;

  try
  {
  method.Invoke(value.Key, value.Value);
  }
  catch (Exception exception)
  {
  _logger.Error("Invoke diagnostic method exception.", exception);
  }
}

 

 

TracingDiagnosticMethod.cs

   private readonly IParameterResolver[] _parameterResolvers;

 

这里通过前面注册时会有一个 参数数组,和传入的参数

通过Resolve 里(这里ObjectAttribute和 PropertyAttribute)抽象类ParameterBinderAttribute 为了前面注册时获取两个特性值

ObjectAttribute 时直接返回传入对象,(_parameterResolvers[i] 里的参数)

ParameterBinderAttribute 是  

{

var property = value.GetType().GetProperty(Name);

return property?.GetReflector()?.GetValue(value);

}

//执行方法和参数

public void Invoke(string diagnosticName, object value)
{
  if (_diagnosticName != diagnosticName)
  {
  r  eturn;
  }

  var args = new object[_parameterResolvers.Length];
  or (var i = 0; i < _parameterResolvers.Length; i++)
  {
    args[i] = _parameterResolvers[i].Resolve(value);
  }

  _reflector.Invoke(_tracingDiagnosticProcessor, args);
}





  

 执行到 这诊断对象  
 先创建上下文,添加前面传入的参数值到上下文

[DiagnosticName(SqlClientDiagnosticStrings.SqlBeforeExecuteCommand)] public void BeforeExecuteCommand([Property(Name = "Command")] DbCommand sqlCommand) { var context = _tracingContext.CreateExitSegmentContext(ResolveOperationName(sqlCommand), _peerFormatter.GetDbPeer(sqlCommand.Connection)); context.Span.SpanLayer = Tracing.Segments.SpanLayer.DB; context.Span.Component = Common.Components.SQLCLIENT; context.Span.AddTag(Common.Tags.DB_TYPE, "sql"); context.Span.AddTag(Common.Tags.DB_INSTANCE, sqlCommand.Connection.Database); context.Span.AddTag(Common.Tags.DB_STATEMENT, sqlCommand.CommandText); }
  //执行完成后发布,通过注入ITracingContext 上下文

  [DiagnosticName(SqlClientDiagnosticStrings.SqlAfterExecuteCommand)]
  public void AfterExecuteCommand()
  {
    var context = _contextAccessor.Context;
    if (context != null)
    {
      _tracingContext.Release(context);
    }
  }

 

TracingContext.cs

在Release 方法

通过ISegmentDispatcher _segmentDispatcher
 ConcurrentQueue<SegmentRequest> _segmentQueue;

_segmentDispatcher.Dispatch(segmentContext);将行下文 写入 队列中

InstrumentStartup.cs

最后通过GRPC发送
在监听的上一行有先买你的foreach
 DiagnosticListener.AllListeners.Subscribe(_observer);

注入了 IEnumerable<IExecutionService> _services;这个接口获取了 所有grpc 推送,差不多有些话要做一些数据准八日,如cpu 等

  foreach (var service in _services)
  await service.StartAsync(cancellationToken);


ExecutionService.cs
通过Time 定时 执行一次远程推送

public Task StartAsync(CancellationToken cancellationToken = default(CancellationToken))
{
  _cancellationTokenSource = new CancellationTokenSource();
  var source = CancellationTokenSource.CreateLinkedTokenSource(_cancellationTokenSource.Token, cancellationToken);
  _timer = new Timer(Callback, source, DueTime, Period);//
  Logger.Information($"Loaded instrument service [{GetType().FullName}].");
  return Task.CompletedTask;
}

private async void Callback(object state)
{
  if (!(state is CancellationTokenSource token) || token.IsCancellationRequested || !CanExecute()) return;

  try
  {
  await ExecuteAsync(token.Token);
  }
  catch (Exception ex)
  {
  Logger.Error(GetType().FullName + ".ExecuteAsync(token.Token) fail", ex);
  }
}












  

     

标签:void,value,listener,var,源码,context,skyapm,dotnet,diagnosticProcessor
From: https://www.cnblogs.com/liujian1368928/p/17674987.html

相关文章

  • [SpringSecurity5.6.2源码分析一]:spring.factories下有关SpringSecurity的配置类
    1、Spring.factories• 从下图可以看出spring-boot-autoconfigure/META-INF/spring.factories中关于SpringSecurity的自动配置类有以下这些org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\org.springframework.boot.autoconfigure.securi......
  • AQS源码解读之ReentrantLock
    1.背景1.AQS简介AQS全称为AbstractQueuedSynchronizer(抽象队列同步器)。AQS是一个用来构建锁和其他同步组件的基础框架,使用AQS可以简单且高效地构造出应用广泛的同步器,例如ReentrantLock、Semaphore、ReentrantReadWriteLock和FutureTask等等。2.原理AQS核心思想是,如果被请求的......
  • 记录centos stream 9 编译qt5.15.10源码
    开始装的一些依赖库没有记录gcc之类的,都是通过dnf安装的主要是make过程中出现的问题(qtwebengine)及其如何解决编译的命令如下./configure-prefix/home/kun/usr/Qt/5.15.10-opensource-confirm-licensemake-j16makeinstallconfigure阶段失败一般都是缺少,都是dnf解决的......
  • wangEditor增加源码模式,添加查看源码功能
    wangEditor是一款轻量级的富文本编辑器。使用还比较方便,但是缺少查看源码模式,需要我们自定义一个menu给增加查看源码模式下面是wangEditor增加源码模式的代码:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="......
  • 搭建高效的企业培训系统:源码解析与最佳实践
    在现代企业环境中,培训和发展员工的重要性变得越来越明显。为了保持竞争力,企业需要不断提升员工的技能和知识。搭建一个高效的企业培训系统可以帮助企业实现这一目标。一、什么是企业培训系统? 企业培训系统是一个涵盖广泛功能的复杂系统。它不仅要管理培训内容,还需要跟踪员工的进度......
  • 基于ASP的网上选课系统的设计与实现-计算机毕业设计源码+LW文档
    一、选题的目的和意义目的:网上选课系统的开发是为了更好的让各个高校充分的利用校园网的软硬件资源,通过B/S架构来实现网上选课系统,实现了网上选课系统的无纸化管理,让网上选课系统、查询课程更为方便,让导师审核选课更加快捷。意义:网上选课系统使学生足不出户就能够提交选课,有效的......
  • 忻州师院毕业论文管理系统的设计与实现-计算机毕业设计源码+LW文档
    一、选题的目的和意义目的:忻州师院毕业论文管理系统的开发是为了更好的让各个高校充分的利用校园网的软硬件资源,通过B/S架构来实现忻州师院毕业论文管理系统,管理毕业论文信息,老师可以在线查询毕业论文进程,节省时间,提高效率。意义:本文研发的忻州师院毕业论文管理系统结合高校具体的......
  • 基于ASP的人才招聘管理系统的设计与实现-计算机毕业设计源码+LW文档
    一、选题的目的和意义目的:基于ASP的人才招聘管理系统的开发是为了提高企业的工作效率,减少企业员工的工作量以及相应的时间,节省一些不必要的开支,从而让求职者可以更快的找到工作,企业快速的挖掘人才。人才招聘管理系统不仅能为经营者提供相对应的市场信息,并且能够随时掌握市场的发展......
  • 基于Android的红马国旅网上旅行社APP的设计与开发-计算机毕业设计源码+LW文档
    一、选题的目的和意义目的:基于Android的红马国旅网上旅行社APP是为了游客提供个性化的服务。用户注册登录APP后可根据自己的意向查询相关景点的攻略信息,还可将这些信息分享至微信、QQ、新浪微博等社交平台。合理规划自己的时间,出行前先做好攻略,查清楚景点的地理位置、营业时间、公......
  • 芦芽山旅游资源管理系统的设计与实现-计算机毕业设计源码+LW文档
    一、选题的目的和意义: 本课题拟开发一个基于java的芦芽山旅游资源管理系统,开发的主要目标是通过芦芽山旅游资源管理系统,提供有用的信息数据,为旅游者提供可靠的旅游信息,对推动地方旅游业的发展具有积极有效的促进作用。本芦芽山旅游资源管理系统主要包括景点展示、酒店查看、在线......