ITraceDiagnosticListener是我们方便操作DiagnosticListener定义的接口,接口仅包含DiagnosticName用来表示DiagnosticListener监听的名称,有了这个接口接下来的操作我们会方便许多,接下来我们来看订阅操作的实现。
public class TraceObserver :IObserver<DiagnosticListener> { private IEnumerable<ITraceDiagnosticListener> _traceDiagnostics; public TraceObserver(IEnumerable<ITraceDiagnosticListener> traceDiagnostics) { _traceDiagnostics = traceDiagnostics; } public void OnCompleted() { } public void OnError(Exception error) { } public void OnNext(DiagnosticListener listener) { //这样的话我们可以更轻松的扩展其他DiagnosticListener的操作 var traceDiagnostic = _traceDiagnostics.FirstOrDefault(i=>i.DiagnosticName==listener.Name); if (traceDiagnostic!=null) { //适配订阅 listener.SubscribeWithAdapter(traceDiagnostic); } } }
通过这种操作我们就无需关心如何将自定义的DiagnosticListener订阅类适配到DiagnosticAdapter中去,方便我们自定义其他DiagnosticListener的订阅类,这样的话我们只需注册自定义的订阅类即可。
services.AddSingleton<TraceObserver>(); services.AddSingleton<ITraceDiagnosticListener, HttpDiagnosticListener>();
通过这种改进方式,我们可以解决类似HttpClient封装到框架中,并且我们我们无法通过外部程序去修改设置的时候。比如我们在架构中引入了Ocelot网关,我们就可以采用类似这种方式,在网关层集成zipkin4net。
自定义埋点
通过上面我们查看TracingHandler的源码我们得知埋点主要是通过ClientTrace进行的,它是在发起请求的客户端进行埋点。在服务端埋点的方式我们可以通过TracingMiddleware中间件中的源码查看到[点击查看源码👈]叫ServerTrace。有了ClientTrace和ServerTrace我们可以非常轻松的实现一次完整的客户端和服务端埋点,只需要通过它们打上一些标签即可。其实它们都是对Trace类的封装,我们找到它们的源码进行查看
public class ClientTrace : BaseStandardTrace, IDisposable { public ClientTrace(string serviceName, string rpc) { if (Trace.Current != null) { Trace = Trace.Current.Child(); } Trace.Record(Annotations.ClientSend()); Trace.Record(Annotations.ServiceName(serviceName)); Trace.Record(Annotations.Rpc(rpc)); } public void Dispose() { Trace.Record(Annotations.ClientRecv()); } } public class ServerTrace : BaseStandardTrace, IDisposable { public override Trace Trace { get { return Trace.Current; } } public ServerTrace(string serviceName, string rpc) { Trace.Record(Annotations.ServerRecv()); Trace.Record(Annotations.ServiceName(serviceName)); Trace.Record(Annotations.Rpc(rpc)); } public void Dispose() { Trace.Record(Annotations.ServerSend()); } }
因此,如果你想通过更原始的方式去记录跟踪日志可以采用如下方式
var trace = Trace.Create(); trace.Record(Annotations.ServerRecv()); trace.Record(Annotations.ServiceName(serviceName)); trace.Record(Annotations.Rpc("GET")); trace.Record(Annotations.ServerSend()); trace.Record(Annotations.Tag("http.url", "<url>"));
示例Demo
由于上面说的比较多,而且有一部分关于源码的解读,为了防止由本人文笔有限,给大家带来理解误区,另一方面也为了更清晰的展示Zipkin的集成方式,我自己做了一套Demo,目录结构如下
下载链接:链接: https://pan.baidu.com/s/1LDyoRQehaE0FzedFTC4_Og 提取码: i45x
总结