诊断日志DiagnosticSource针对活动的跟踪

本文是《ASP.NET Core 3 框架揭秘》8.5.4 的案例。
由于很简单,作者没有写案例。但是自己在尝试写的时候还是遇到点困难的。所有分享一下,希望能帮到别人。
我的案例是基于本书案例S812(事件日志EventSource的活动跟踪)和S815(诊断日志DiagnosticSource 强类型事件订阅)改造的。
活动跟踪我是通过Activity对象的传输实现的,不知道对不对,也希望大家指出问题。

首先是发布者的定义

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace ConsoleApp6
{
  public sealed class FoobarSource : DiagnosticListener
  {
    public FoobarSource(string name) : base(name) { }

    public static FoobarSource Instance = new FoobarSource("Web");
     
    public Activity FooStart(long timestamp)
    {
      var activity = new Activity("Foo");
      Instance.StartActivity(activity, new { Activity = activity, Index =1, TimeStamp =timestamp });
      return activity;
    }

    public void FooStop(Activity activity, double elapsed)
    {
      Instance.StopActivity(activity, new { Activity= activity,Index = 2, Elapsed = elapsed });
    }

    public Activity BarStart(long timestamp)
    {
      var activity = new Activity("Bar");
      Instance.StartActivity(activity, new { Activity = activity, Index = 3, TimeStamp = timestamp });
      return activity;
    }
   
    public void BarStop(Activity activity, double elapsed)
    {
      Instance.StopActivity(activity, new { Activity = activity, Index = 4, Elapsed = elapsed });
    }

    public Activity BazStart(long timestamp)
    {
      var activity = new Activity("Baz");
      Instance.StartActivity(activity, new { Activity = activity, Index = 5, TimeStamp = timestamp });
      return activity;
    } 

    public void BazStop(Activity activity, double elapsed)
    {
      Instance.StopActivity(activity, new { Activity = activity, Index = 6, Elapsed = elapsed });
    }

    public Activity GuxStart(long timestamp)
    {
      var activity = new Activity("Gux");
      Instance.StartActivity(activity, new { Activity = activity, Index = 7, TimeStamp = timestamp });
      return activity;
    } 

    public void GuxStop(Activity activity, double elapsed)
    {
      Instance.StopActivity(activity, new { Activity = activity, Index = 8, Elapsed = elapsed });
    }
  }
}

还是Foo,Bar,Bza,Gux的start,stop几个函数。
start时,自己创建了一个Activity,并指定operationName。调用StartActivity并返回这个Activity。
stop时,需要以参数方式传入Activity.其实就是对应的start时创建的Activity。调用StopActivity。

根据书中8.5.4对DiagnosticSource的StartActivity方法和StopActivity方法的说明。两个方法内部除了调用Start方法和Stop方法开始与结束指定活动对象之外,只是调用Write方法发送了一个日志事件。发送日志事件的名称为指定Activity对象的操作名称分别加上对应后缀“.Start”和“.Stop”,所以需要根据此命名规则来订阅活动的开始事件和结束事件。

public abstract class DiagnosticSource
  {
    public Activity StartActivity(Activity activity,object args)
    {
      activity.Start();
      Write(activity.OperationName + ".Start", args);
      return activity;
    }

    public void StopActivity(Activity activity,object args)
    {
      if (activity.Duration == TimeSpan.Zero)
      {
        activity.SetEndTime(Activity.GetUtcNow());
      }
      Write(activity.OperationName + ".Stop", args);
      activity.Stop();
    }
    ...
  }

所以我的订阅者的定义如下

using Microsoft.Extensions.DiagnosticAdapter;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Text;

namespace ConsoleApp6
{
  public sealed class DiagnosticCollector
  {
    [DiagnosticName("Foo.Start")]
    public void OnFooStart(Activity activity,int Index, long TimeStamp)
      => Console.WriteLine($"FooStart,ActivityId:{activity.Id,-32}-{ activity.ParentId,-32},index:{Index},timestamp:{TimeStamp}");


    [DiagnosticName("Foo.Stop")]
    public void OnFooStop(Activity activity, int Index, double Elapsed)
      => Console.WriteLine($"FooStop ,ActivityId:{activity.Id,-32}-{ activity.ParentId,-32},index:{Index};Elapsed:{Elapsed}");

    [DiagnosticName("Bar.Start")]
    public void OnBarStart(Activity activity, int Index, long TimeStamp)
     => Console.WriteLine($"BarStart,ActivityId:{activity.Id,-32}-{ activity.ParentId,-32},index:{Index},timestamp:{TimeStamp}");


    [DiagnosticName("Bar.Stop")]
    public void OnBarStop(Activity activity, int Index, double Elapsed)
      => Console.WriteLine($"BarStop ,ActivityId:{activity.Id,-32}-{ activity.ParentId,-32},index:{Index};Elapsed:{Elapsed}");

    [DiagnosticName("Baz.Start")]
    public void OnBazStart(Activity activity, int Index, long TimeStamp)
     => Console.WriteLine($"BazStart,ActivityId:{activity.Id,-32}-{ activity.ParentId,-32},index:{Index},timestamp:{TimeStamp}");


    [DiagnosticName("Baz.Stop")]
    public void OnBazStop(Activity activity, int Index, double Elapsed)
      => Console.WriteLine($"BazStop ,ActivityId:{activity.Id,-32}-{ activity.ParentId,-32},index:{Index};Elapsed:{Elapsed}");

    [DiagnosticName("Gux.Start")]
    public void OnGuxStart(Activity activity, int Index, long TimeStamp)
     => Console.WriteLine($"GuxStart,ActivityId:{activity.Id,-32}-{ activity.ParentId,-32},index:{Index},timestamp:{TimeStamp}");


    [DiagnosticName("Gux.Stop")]
    public void OnGuxStop(Activity activity, int Index, double Elapsed)
      => Console.WriteLine($"GuxStop ,ActivityId:{activity.Id,-32}-{ activity.ParentId,-32},index:{Index};Elapsed:{Elapsed}");
  }
}

最后是main方法调用,和S812中也很类似

using System;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace ConsoleApp6
{
  public class Program
  {
    static readonly Random _random = new Random();
    public static async Task Main(string[] args)
    {
      DiagnosticListener.AllListeners.Subscribe(listener =>
      {
        if (listener.Name == "Web")
        {
          listener.SubscribeWithAdapter(new DiagnosticCollector());
        }
      });
       
      await FooAsync();
    }


    static Task FooAsync() => InvokeAsync(FoobarSource.Instance.FooStart, FoobarSource.Instance.FooStop,
         async () =>
         {
           await BarAsync();
           await GuxAsync();
         });
    static Task BarAsync() => InvokeAsync(FoobarSource.Instance.BarStart, FoobarSource.Instance.BarStop,
        BazAsync);
    static Task BazAsync() => InvokeAsync(FoobarSource.Instance.BazStart, FoobarSource.Instance.BazStop,
           () => Task.CompletedTask);
    static Task GuxAsync() => InvokeAsync(FoobarSource.Instance.GuxStart, FoobarSource.Instance.GuxStop,
        () => Task.CompletedTask);

    static async Task InvokeAsync(Func<long,Activity> start, Action<Activity,double> stop, Func<Task> body)
    {
    //这里返回Activity,后面传入Stop方法
      var activity = start(Stopwatch.GetTimestamp());
      var sw = Stopwatch.StartNew();
      await Task.Delay(_random.Next(10, 100));
      await body();
      stop(activity,sw.ElapsedMilliseconds);
    }
  }
}

当我写完了我发现确实很简单,作者没必要专门写一个案例。只是自己理解不到位。

源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值