gpt4 book ai didi

spring-cloud Sleuth的使用方法

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 29 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章spring-cloud Sleuth的使用方法由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

一直没弄明白sleuth的tracercontext是如何创建和传递的,闲来无事研究了一下。由于对sleuth的源码不熟悉,准备通过debug brave.tracer的nextid()方法,查看方法调用栈来找来龙去脉.

首先创建两个service a和b,记作srva、srvb,在srva中添加testa controller,sevb中添加testb controller,testa中通过feign调用testb.

spring-cloud Sleuth的使用方法

先看当用户通过浏览器调用srva的时候,srva是作为server的.

configuration: tracewebservletautoconfiguration==>tracingfilter tracehttpautoconfiguration==>httptracing traceautoconfiguration==>tracing sleuthlogautoconfiguration.slf4jconfiguration==>currenttracecontext 。

spring-cloud Sleuth的使用方法

配置中,tracingfilter在实例化时需要一个httptracing:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static filter create(httptracing httptracing) {
  return new tracingfilter(httptracing);
}
 
//servlet运行时类
final servletruntime servlet = servletruntime.get();
//slf4jcurrenttracecontext
final currenttracecontext currenttracecontext;
final tracer tracer;
final httpserverhandler<httpservletrequest, httpservletresponse> handler;
//tracecontext的数据提取器
final tracecontext.extractor<httpservletrequest> extractor;
 
tracingfilter(httptracing httptracing) {
  tracer = httptracing.tracing().tracer();
  currenttracecontext = httptracing.tracing().currenttracecontext();
  handler = httpserverhandler.create(httptracing, adapter);
  extractor = httptracing.tracing().propagation().extractor(getter);
}

httptracing builder模式构造时接收一个tracing:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
tracing tracing;
//客户端span解析器
httpclientparser clientparser;
string servername;
//服务端span解析器
httpserverparser serverparser;
httpsampler clientsampler, serversampler;
 
builder(tracing tracing) {
  if (tracing == null ) throw new nullpointerexception( "tracing == null" );
  final errorparser errorparser = tracing.errorparser();
  this .tracing = tracing;
  this .servername = "" ;
  // override to re-use any custom error parser from the tracing component
  this .clientparser = new httpclientparser() {
   @override protected errorparser errorparser() {
    return errorparser;
   }
  };
  this .serverparser = new httpserverparser() {
   @override protected errorparser errorparser() {
    return errorparser;
   }
  };
  this .clientsampler = httpsampler.trace_id;
  this .serversampler(httpsampler.trace_id);
}

tracing实例化:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@bean
@conditionalonmissingbean
// note: stable bean name as might be used outside sleuth
tracing tracing( @value ( "${spring.zipkin.service.name:${spring.application.name:default}}" ) string servicename,
     propagation.factory factory,
     currenttracecontext currenttracecontext,
     reporter<zipkin2.span> reporter,
     sampler sampler,
     errorparser errorparser,
     sleuthproperties sleuthproperties
) {
   return tracing.newbuilder()
       .sampler(sampler)
       .errorparser(errorparser)
       .localservicename(servicename)
       //extrafieldpropagation.factory
       .propagationfactory(factory)
       .currenttracecontext(currenttracecontext)
       .spanreporter(adjustedreporter(reporter))
       .traceid128bit(sleuthproperties.istraceid128())
       .supportsjoin(sleuthproperties.issupportsjoin())
       .build();
}

下面看tracingfilter的dofilter:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
span span = handler.handlereceive(extractor, httprequest);
 
  // add attributes for explicit access to customization or span context
  request.setattribute(spancustomizer. class .getname(), span.customizer());
  request.setattribute(tracecontext. class .getname(), span.context());
 
  throwable error = null ;
  scope scope = currenttracecontext.newscope(span.context());
  try {
   // any downstream code can see tracer.currentspan() or use tracer.currentspancustomizer()
   chain.dofilter(httprequest, httpresponse);
  } catch (ioexception | servletexception | runtimeexception | error e) {
   error = e;
   throw e;
  } finally {
   scope.close();
   if (servlet.isasync(httprequest)) { // we don't have the actual response, handle later
    servlet.handleasync(handler, httprequest, httpresponse, span);
   } else { // we have a synchronous response, so we can finish the span
    handler.handlesend(adapter.adaptresponse(httprequest, httpresponse), error, span);
   }
  }
}

在sleuthlogautoconfiguration中如果有slfj的包,则注入currenttracecontext:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@configuration
  @conditionalonclass (mdc. class )
  @enableconfigurationproperties (sleuthslf4jproperties. class )
  protected static class slf4jconfiguration {
 
    @bean
    @conditionalonproperty (value = "spring.sleuth.log.slf4j.enabled" , matchifmissing = true )
    @conditionalonmissingbean
    public currenttracecontext slf4jspanlogger() {
      return slf4jcurrenttracecontext.create();
    }
   
    ...
   }

slf4jcurrenttracecontext中,delegate就是currenttracecontext.default.inheritable():

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public static final class default extends currenttracecontext {
  static final threadlocal<tracecontext> default = new threadlocal<>();
  // inheritable as brave 3's threadlocalserverclientandlocalspanstate was inheritable
  static final inheritablethreadlocal<tracecontext> inheritable = new inheritablethreadlocal<>();
 
  final threadlocal<tracecontext> local;
 
  //静态方法create,local对象为threadlocal类型
  /** uses a non-inheritable static thread local */
  public static currenttracecontext create() {
   return new default ( default );
  }
 
  //local对象为inheritablethreadlocal类型
  //官方文档指出,inheritable方法在线程池的环境中需谨慎使用,可能会取出错误的tracecontext,这样会导致span等信息会记录并关联到错误的traceid上
  /**
   * uses an inheritable static thread local which allows arbitrary calls to {@link
   * thread#start()} to automatically inherit this context. this feature is available as it is was
   * the default in brave 3, because some users couldn't control threads in their applications.
   *
   * <p>this can be a problem in scenarios such as thread pool expansion, leading to data being
   * recorded in the wrong span, or spans with the wrong parent. if you are impacted by this,
   * switch to {@link #create()}.
   */
  public static currenttracecontext inheritable() {
   return new default (inheritable);
  }
 
  default (threadlocal<tracecontext> local) {
   if (local == null ) throw new nullpointerexception( "local == null" );
   this .local = local;
  }
 
  @override public tracecontext get() {
   return local.get();
  }
 
  //替换当前tracecontext,close方法将之前的tracecontext设置回去
  //scope接口继承了closeable接口,在try中使用会自动调用close方法,为了避免用户忘记close方法,还提供了runnable,callable,executor,executorservice包装方法
  @override public scope newscope( @nullable tracecontext currentspan) {
   final tracecontext previous = local.get();
   local.set(currentspan);
   class defaultcurrenttracecontextscope implements scope {
    @override public void close() {
     local.set(previous);
    }
   }
   return new defaultcurrenttracecontextscope();
  }
}

slf4jcurrenttracecontext的delegate使用的就是一个inheritablethreadlocal,inheritablethreadlocal在创建子线程的时候,会将父线程的inheritablethreadlocals继承下来。这样就实现了tracecontext在父子线程中的传递.

看一下currenttracecontext的maybescope:

?
1
2
3
4
5
6
7
8
9
10
11
//返回一个新的scope,如果当前scope就是传入的scope,返回一个空scope
public scope maybescope( @nullable tracecontext currentspan) {
  //获取当前tracecontext
  tracecontext currentscope = get();
  //如果传入的tracecontext为空,且当前tracecontext为空返回空scope
  if (currentspan == null ) {
   if (currentscope == null ) return scope.noop;
   return newscope( null );
  }
  return currentspan.equals(currentscope) ? scope.noop : newscope(currentspan);
}

tracingfilter中httpserverhandler解析request:请输入代码 。

2.srva请求到servb时作为client.

traceloadbalancerfeignclient-->loadbalancerfeignclient-->feignloadbalancer-->lazytracingfeignclient-->client 。

 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.

原文链接:https://segmentfault.com/a/1190000018115247 。

最后此篇关于spring-cloud Sleuth的使用方法的文章就讲到这里了,如果你想了解更多关于spring-cloud Sleuth的使用方法的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com