Слияние кода завершено, страница обновится автоматически
//
// Copyright 2022 SkyAPM org
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package go2sky
import (
"context"
"github.com/SkyAPM/go2sky/internal/idgen"
"github.com/pkg/errors"
"github.com/SkyAPM/go2sky/internal/tool"
"github.com/SkyAPM/go2sky/propagation"
)
const (
errParameter = tool.Error("parameter are nil")
)
// Tracer is go2sky tracer implementation.
type Tracer struct {
service string
instance string
reporter Reporter
// 0 not init 1 init
initFlag int32
sampler Sampler
correlation *CorrelationConfig
cdsWatchers []AgentConfigChangeWatcher
}
// TracerOption allows for functional options to adjust behaviour
// of a Tracer to be created by NewTracer
type TracerOption func(t *Tracer)
// NewTracer return a new go2sky Tracer
func NewTracer(service string, opts ...TracerOption) (tracer *Tracer, err error) {
// read the service in the environment variable
service = serviceFormEnv(service)
if service == "" {
return nil, errParameter
}
// read the options in the environment variable
envOps, err := traceOptionsFormEnv()
if err != nil {
return nil, err
}
opts = append(opts, envOps...)
t := &Tracer{
service: service,
initFlag: 0,
}
// default correlation config
t.correlation = &CorrelationConfig{MaxKeyCount: 3, MaxValueSize: 128}
for _, opt := range opts {
opt(t)
}
if t.sampler == nil {
t.sampler = NewDynamicSampler(1, t)
}
if t.reporter != nil {
if t.instance == "" {
id, err := idgen.UUID()
if err != nil {
return nil, err
}
t.instance = id + "@" + tool.IPV4()
}
t.reporter.Boot(t.service, t.instance, t.cdsWatchers)
t.initFlag = 1
}
return t, nil
}
// CreateEntrySpan creates and starts an entry span for incoming request
func (t *Tracer) CreateEntrySpan(ctx context.Context, operationName string, extractor propagation.Extractor) (s Span, nCtx context.Context, err error) {
if ctx == nil || operationName == "" || extractor == nil {
return nil, nil, errParameter
}
if s, nCtx = t.createNoop(ctx); s != nil {
return
}
var refSc = &propagation.SpanContext{}
err = refSc.Decode(extractor)
if err != nil {
return
}
if !refSc.Valid {
refSc = nil
}
s, nCtx, err = t.CreateLocalSpan(ctx, WithContext(refSc), WithSpanType(SpanTypeEntry), WithOperationName(operationName))
return
}
// CreateLocalSpan creates and starts a span for local usage
func (t *Tracer) CreateLocalSpan(ctx context.Context, opts ...SpanOption) (s Span, c context.Context, err error) {
if ctx == nil {
return nil, nil, errParameter
}
if s, c = t.createNoop(ctx); s != nil {
return
}
ds := newLocalSpan(t)
for _, opt := range opts {
opt(ds)
}
parentSpan, ok := ctx.Value(ctxKeyInstance).(segmentSpan)
if !ok {
parentSpan = nil
}
isForceSample := len(ds.Refs) > 0
// Try to sample when it is not force sample
if parentSpan == nil && !isForceSample {
// Force sample
sampled := t.sampler.IsSampled(ds.OperationName)
if !sampled {
// Filter by sample just return noop span
s = &NoopSpan{}
return s, context.WithValue(ctx, ctxKeyInstance, s), nil
}
}
s, err = newSegmentSpan(ds, parentSpan)
if err != nil {
return nil, nil, err
}
return s, context.WithValue(ctx, ctxKeyInstance, s), nil
}
// CreateExitSpan creates and starts an exit span for client
func (t *Tracer) CreateExitSpan(ctx context.Context, operationName string, peer string, injector propagation.Injector) (s Span, err error) {
s, _, err = t.CreateExitSpanWithContext(ctx, operationName, peer, injector)
return
}
// CreateExitSpanWithContext creates and starts an exit span for client with context
func (t *Tracer) CreateExitSpanWithContext(ctx context.Context, operationName string, peer string,
injector propagation.Injector) (s Span, nCtx context.Context, err error) {
if ctx == nil || operationName == "" || peer == "" || injector == nil {
return nil, nil, errParameter
}
if s, nCtx = t.createNoop(ctx); s != nil {
return
}
s, nCtx, err = t.CreateLocalSpan(ctx, WithSpanType(SpanTypeExit), WithOperationName(operationName))
if err != nil {
return
}
noopSpan, ok := interface{}(s).(*NoopSpan)
if ok {
// Ignored, there is no need to inject SW8 in the request header
return noopSpan, nCtx, nil
}
s.SetPeer(peer)
spanContext := &propagation.SpanContext{}
span, ok := s.(ReportedSpan)
if !ok {
return nil, nil, errors.New("span type is wrong")
}
firstSpan := span.Context().FirstSpan
spanContext.Sample = 1
spanContext.TraceID = span.Context().TraceID
spanContext.ParentSegmentID = span.Context().SegmentID
spanContext.ParentSpanID = span.Context().SpanID
spanContext.ParentService = t.service
spanContext.ParentServiceInstance = t.instance
spanContext.ParentEndpoint = firstSpan.GetOperationName()
spanContext.AddressUsedAtClient = peer
spanContext.CorrelationContext = span.Context().CorrelationContext
err = spanContext.Encode(injector)
if err != nil {
return nil, nil, err
}
return
}
func (t *Tracer) createNoop(ctx context.Context) (s Span, nCtx context.Context) {
if ns, ok := ctx.Value(ctxKeyInstance).(*NoopSpan); ok {
nCtx = ctx
s = ns
return
}
if t.initFlag == 0 {
s = &NoopSpan{}
nCtx = context.WithValue(ctx, ctxKeyInstance, s)
return
}
return
}
//Reporter is a data transit specification
type Reporter interface {
Boot(service string, serviceInstance string, cdsWatchers []AgentConfigChangeWatcher)
Send(spans []ReportedSpan)
Close()
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )