Conversation
|
|
||
| The tracerManager structure is as follows: | ||
| ```go | ||
| type TracerManager struct { |
There was a problem hiding this comment.
是不是有一个抽象的 TracerManager,然后其中一个实现是 JaegerManager,这样后续更容易扩展其他的分布式追踪后端?
There was a problem hiding this comment.
TracerManager是管理所有的driver,目前只有默认的JaegerDriver,后续可以根据需要扩展成map。
| defer rootSpan.Finish() | ||
| s.ls.FilterChain.ServeHTTP(w, r.WithContext(ctx)) | ||
|
|
||
| ``` |
There was a problem hiding this comment.
可以分别添加一下,在 Networkfilter 和 HttpFilter 中使用 Tracer 进行上报的案例。比如说在 https://github.com/apache/dubbo-go-pixiu/blob/develop/pkg/filter/http/remote/call.go 中或者 https://github.com/apache/dubbo-go-pixiu/blob/develop/pkg/common/grpc/manager.go 也想要进行记录
There was a problem hiding this comment.
对tracer.go进行修改,及时删改追踪完成的trace。
type Tracer struct {
Id String
T opentracing.Tracer
closer io.Closer
}
func (t *Tracer) Close() {
delete(holder.tracers, t.Id)
t.Close()
}当http_listener监听到HTTP请求:
tracer, _, _ := NewTracer("HTTP")
defer tracer.Close()
rootSpan := tracer.StartSpan("http-listener")
ctx := tracer.T.ContextWithSpan(r.Context(), rootSpan)
defer rootSpan.Finish()
s.ls.FilterChain.ServeHTTP(w, r.WithContext(ctx))HTTPConnectionManager 中追踪:
我们抽离出获取Tracer的公共方法:
// TODO 增强代码健壮性
func GetTracer(protocolName, tracerId string) api.Tracer {
driver := GetTraceDriverManager().getDriver()
return driver.getTracer(prtocolName, traceId);
}func (hcm *HttpConnectionManager) ServeHTTP(w stdHttp.ResponseWriter, r *stdHttp.Request) {
...
hc.Reset()
traceId := r.Header.Get("trace-id")
tracer := trace.GetTracer("HTTP", traceId)
hcmSpan, spanContext := opentracing.StartSpanFromContextWithTracer(r.Context(), tracer, "Filter---HttpConnectionManager封装HttpContext")
hc.Ctx = spanContext
defer hcmSpan.Finish()
err := hcm.Handle(hc)
...
}
func (hcm *HttpConnectionManager) Handle(hc *pch.HttpContext) error {
// hc.Ctx = context.Background()
traceId := hc.Request.Header.Get("trace-id")
tracer := trace.GetTracer("HTTP", traceId)
hcmSpan, spanContext := opentracing.StartSpanFromContextWithTracer(r.Context(), tracer, "Filter---HttpConnectionManager查找路由,确定集群")
hc.Ctx = spanContext
defer hcmSpan.Finish()
err := hcm.findRoute(hc)
if err != nil {
return err
}
hcm.handleHTTPRequest(hc)
return nil
}Note:hcm这里是一个空Context,这里直接注释了源代码。另外,在NetWorkFilter和HttpFilter中的处理过程与上述过程基本一致,不再演示。
There was a problem hiding this comment.
这个看起来不错,将一些细节隐藏到共有的抽象方法中,真正要使用 tracer 进行记录的位置只感知项目提供的接口,不需要了解底层的具体实现
| Disabled bool | ||
| //默认是HTTP | ||
| ServiceName string | ||
| Driver string |
There was a problem hiding this comment.
是否需要不同 driver 所特有的 config 字段?比如 skywalking 的配置和 jaeger 的配置数据可能有些差异
There was a problem hiding this comment.
目前只考虑了jaeger,可以考虑扩充:
type TracerConfigs struct {
jaegerConfig JaegerConfig
skywalking SkyWalkingConfig
}There was a problem hiding this comment.
一阶段可以只支持 jaeger,但是需要考虑并给出扩展机制,可以按照后续要支持 skywalking为例进行说明。比如说 :
- 不同的driver类型如何进行识别和读取不同的config设置到对应的变量中;
- 初始化建立 TracerProvider 时可能的差异怎么处理;
- 不同 lib 如果有 api 方面差异,如何统一使用,比如说 StartSpan。
可以和下面的 DriverManager 一起进行扩展性描述。
|
rename file name to ur [$feature-$version] |
|
model包下的TraceConfig如下: type TracerConfig struct {
Name string
Sampler Sampler
Config interface{}
}
type Sampler struct {
Type string
Param float64
}系统的trace采用otel,driver结构如下: type Holder struct {
Tracers map[string]protocol.Trace
Id uint64
}
type TraceDriver struct {
holders map[protocolName]*Holder
tp *sdktrace.TracerProvider
context context.Context
}holder中Tracers的键会使用Id进行拼接之后原子递增,保证唯一性。在TraceDriverManager的初始化中,主要是对driver的初始化,包括设置exprter(支持jaeger,otlp等)和TraceProvider。 func (driver *TraceDriver) Init(bs *model.Bootstrap) *TraceDriver {
config := bs.Trace
ctx := context.Background()
exp, err := newExporter(ctx, config)
if err != nil {
//TODO 错误处理
return nil
}
provider := newTraceProvider(exp, config)
otel.SetTracerProvider(provider)
return &TraceDriver{
tp: provider,
}
} 其中可根据config的name属性选择不同的exporter设置,并在TraceProvider的生成中设置采样率。 为支持不同协议请求的Tracer,提供Trace接口,并提供默认实现Tracer。如果其他协议请求(比如HTTP)支持自己协议的span方法,重写部分方法即可。 type Trace interface {
GetId() string
StartSpan(name string, request interface{}) (context.Context, trace.Span)
StartSpanFromContext(name string, tx context.Context) (context.Context, trace.Span)
Close()
}
type Tracer struct {
Id string
T trace.Tracer
H *trace2.Holder
}
type HTTPTracer struct {
*Tracer
}
func (t *Tracer) GetId() string {
return t.Id
}
func (t *Tracer) Close() {
delete(t.H.Tracers, t.Id)
}
func (t *Tracer) StartSpan(name string, request interface{}) (context.Context, trace.Span) {
return t.T.Start(request.(*http.Request).Context(), name)
}
func (t *Tracer) StartSpanFromContext(name string, ctx context.Context) (context.Context, trace.Span) {
return t.T.Start(ctx, name)
}
func (t *HTTPTracer) StartSpan(name string, request interface{}) (context.Context, trace.Span) {
...
}
func (t *HTTPTracer) StartSpanFromContext(name string, ctx context.Context) (context.Context, trace.Span) {
...
}最终在程序中调用流程如下: //http_listener.go
func (s *DefaultHttpWorker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
tracer := trace.NewTracer(trace.HTTP)
defer tracer.Close()
ctx, span := tracer.StartSpan("http", r)
defer span.End()
r.Header.Set("trace-id", tracer.GetId())
s.ls.FilterChain.ServeHTTP(w, r.WithContext(ctx))
}
//manager.go
func (hcm *HttpConnectionManager) ServeHTTP(w stdHttp.ResponseWriter, r *stdHttp.Request) {
...
traceId := r.Header.Get("trace-id")
tracer, _ := trace.GetTracer(trace.HTTP, traceId)
ctx, span := tracer.StartSpanFromContext("HttpConnectionManager", hc.Ctx)
defer span.End()
hc.Ctx = ctx
...
} |
The main ideas about this proposal are as follows: