func()

in module/apmotel/tracer.go [41:128]


func (t *tracer) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
	config := trace.NewSpanStartConfig(opts...)

	startTime := config.Timestamp()
	if startTime.IsZero() {
		startTime = time.Now()
	}

	s := &span{
		provider:   t.provider,
		attributes: config.Attributes(),
		spanKind:   config.SpanKind(),
		startTime:  startTime,
	}

	var links []apm.SpanLink
	for _, l := range config.Links() {
		links = append(links, apm.SpanLink{
			Trace: [16]byte(l.SpanContext.TraceID()),
			Span:  [8]byte(l.SpanContext.SpanID()),
		})
	}

	var psc trace.SpanContext
	if config.NewRoot() {
		ctx = trace.ContextWithSpanContext(ctx, psc)
	} else {
		// If not root, check if a *span is already present, if it's not,
		// attempt to obtain an APM transaction from the context.
		psc = trace.SpanContextFromContext(ctx)
		s.spanContext = psc

		var parent *span
		var ok bool
		if parent, ok = trace.SpanFromContext(ctx).(*span); !ok {
			// Try to find a obtain an APM transaction from the agent context.
			if tx := apm.TransactionFromContext(ctx); tx != nil {
				parent = &span{tx: tx}
			}
		}

		// Use the parent if it exists. Otherwise, we'll create a new
		// transaction using the trace context from `psc`.
		if parent != nil {
			// This is a child span. Create a span, not a transaction.
			// The parent may be a span or a transaction.
			var tc apm.TraceContext
			if parent.span != nil {
				tc = parent.span.TraceContext()
			} else {
				tc = parent.tx.TraceContext()
			}
			s.span = parent.tx.StartSpanOptions(spanName, "", apm.SpanOptions{
				Parent: tc,
				Start:  startTime,
				Links:  links,
			})
			ctx = apm.ContextWithSpan(ctx, s.span)
			s.tx = parent.tx
			s.spanContext = trace.NewSpanContext(trace.SpanContextConfig{
				TraceID:    trace.TraceID(s.span.TraceContext().Trace),
				SpanID:     trace.SpanID(s.span.TraceContext().Span),
				TraceFlags: trace.TraceFlags(0).WithSampled(s.tx.Sampled()),
			})
			return trace.ContextWithSpan(ctx, s), s
		}
	}

	tranOpts := apm.TransactionOptions{
		Links: links,
	}
	if psc.HasTraceID() && psc.HasSpanID() {
		tranOpts.TraceContext = apm.TraceContext{
			Trace:   [16]byte(psc.TraceID()),
			Span:    [8]byte(psc.SpanID()),
			Options: apm.TraceOptions(0).WithRecorded(psc.IsSampled()),
		}
	}
	s.tx = t.provider.apmTracer.StartTransactionOptions(spanName, "", tranOpts)
	ctx = apm.ContextWithTransaction(ctx, s.tx)
	s.spanContext = trace.NewSpanContext(trace.SpanContextConfig{
		TraceID:    trace.TraceID(s.tx.TraceContext().Trace),
		SpanID:     trace.SpanID(s.tx.TraceContext().Span),
		TraceFlags: trace.TraceFlags(0).WithSampled(s.tx.Sampled()),
	})

	return trace.ContextWithSpan(ctx, s), s
}