2020-03-24 07:41:10 +02:00
|
|
|
// Copyright The OpenTelemetry Authors
|
2019-09-25 08:12:22 +02:00
|
|
|
//
|
|
|
|
// 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 internal
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"math/rand"
|
2020-02-28 23:44:53 +02:00
|
|
|
"reflect"
|
2019-09-25 08:12:22 +02:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
2020-08-10 18:17:09 +02:00
|
|
|
"go.opentelemetry.io/otel/codes"
|
2020-10-05 17:25:09 +02:00
|
|
|
"go.opentelemetry.io/otel/internal/baggage"
|
2020-02-04 18:55:03 +02:00
|
|
|
otelparent "go.opentelemetry.io/otel/internal/trace/parent"
|
2020-08-18 05:25:03 +02:00
|
|
|
"go.opentelemetry.io/otel/label"
|
2020-11-07 00:13:31 +02:00
|
|
|
"go.opentelemetry.io/otel/trace"
|
2019-09-25 08:12:22 +02:00
|
|
|
|
2019-11-01 20:40:29 +02:00
|
|
|
"go.opentelemetry.io/otel/bridge/opentracing/migration"
|
2019-09-25 08:12:22 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2020-08-18 05:25:03 +02:00
|
|
|
ComponentKey = label.Key("component")
|
|
|
|
ServiceKey = label.Key("service")
|
|
|
|
StatusCodeKey = label.Key("status.code")
|
|
|
|
StatusMessageKey = label.Key("status.message")
|
|
|
|
ErrorKey = label.Key("error")
|
|
|
|
NameKey = label.Key("name")
|
2019-09-25 08:12:22 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
type MockContextKeyValue struct {
|
|
|
|
Key interface{}
|
|
|
|
Value interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type MockTracer struct {
|
2020-10-05 17:25:09 +02:00
|
|
|
Resources baggage.Map
|
2019-09-25 08:12:22 +02:00
|
|
|
FinishedSpans []*MockSpan
|
2020-11-07 00:13:31 +02:00
|
|
|
SpareTraceIDs []trace.TraceID
|
|
|
|
SpareSpanIDs []trace.SpanID
|
2019-09-25 08:12:22 +02:00
|
|
|
SpareContextKeyValues []MockContextKeyValue
|
|
|
|
|
|
|
|
randLock sync.Mutex
|
|
|
|
rand *rand.Rand
|
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
var _ trace.Tracer = &MockTracer{}
|
2019-09-25 08:12:22 +02:00
|
|
|
var _ migration.DeferredContextSetupTracerExtension = &MockTracer{}
|
|
|
|
|
|
|
|
func NewMockTracer() *MockTracer {
|
|
|
|
return &MockTracer{
|
2020-10-05 17:25:09 +02:00
|
|
|
Resources: baggage.NewEmptyMap(),
|
2019-09-25 08:12:22 +02:00
|
|
|
FinishedSpans: nil,
|
|
|
|
SpareTraceIDs: nil,
|
|
|
|
SpareSpanIDs: nil,
|
|
|
|
SpareContextKeyValues: nil,
|
|
|
|
|
|
|
|
rand: rand.New(rand.NewSource(time.Now().Unix())),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (t *MockTracer) Start(ctx context.Context, name string, opts ...trace.SpanOption) (context.Context, trace.Span) {
|
|
|
|
config := trace.NewSpanConfig(opts...)
|
2020-09-03 16:34:36 +02:00
|
|
|
startTime := config.Timestamp
|
2019-09-25 08:12:22 +02:00
|
|
|
if startTime.IsZero() {
|
|
|
|
startTime = time.Now()
|
|
|
|
}
|
2020-11-07 00:13:31 +02:00
|
|
|
spanContext := trace.SpanContext{
|
2020-09-03 16:34:36 +02:00
|
|
|
TraceID: t.getTraceID(ctx, config),
|
2019-09-25 23:37:36 +02:00
|
|
|
SpanID: t.getSpanID(),
|
|
|
|
TraceFlags: 0,
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
span := &MockSpan{
|
|
|
|
mockTracer: t,
|
|
|
|
officialTracer: t,
|
|
|
|
spanContext: spanContext,
|
2020-09-03 16:34:36 +02:00
|
|
|
recording: config.Record,
|
2020-10-05 17:25:09 +02:00
|
|
|
Attributes: baggage.NewMap(baggage.MapUpdate{
|
2020-09-03 16:34:36 +02:00
|
|
|
MultiKV: config.Attributes,
|
2019-10-30 22:21:13 +02:00
|
|
|
}),
|
|
|
|
StartTime: startTime,
|
|
|
|
EndTime: time.Time{},
|
2020-09-03 16:34:36 +02:00
|
|
|
ParentSpanID: t.getParentSpanID(ctx, config),
|
2019-10-30 22:21:13 +02:00
|
|
|
Events: nil,
|
2020-11-07 00:13:31 +02:00
|
|
|
SpanKind: trace.ValidateSpanKind(config.SpanKind),
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
if !migration.SkipContextSetup(ctx) {
|
2020-11-07 00:13:31 +02:00
|
|
|
ctx = trace.ContextWithSpan(ctx, span)
|
2019-09-25 08:12:22 +02:00
|
|
|
ctx = t.addSpareContextValue(ctx)
|
|
|
|
}
|
|
|
|
return ctx, span
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *MockTracer) addSpareContextValue(ctx context.Context) context.Context {
|
|
|
|
if len(t.SpareContextKeyValues) > 0 {
|
|
|
|
pair := t.SpareContextKeyValues[0]
|
|
|
|
t.SpareContextKeyValues[0] = MockContextKeyValue{}
|
|
|
|
t.SpareContextKeyValues = t.SpareContextKeyValues[1:]
|
|
|
|
if len(t.SpareContextKeyValues) == 0 {
|
|
|
|
t.SpareContextKeyValues = nil
|
|
|
|
}
|
|
|
|
ctx = context.WithValue(ctx, pair.Key, pair.Value)
|
|
|
|
}
|
|
|
|
return ctx
|
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (t *MockTracer) getTraceID(ctx context.Context, config *trace.SpanConfig) trace.TraceID {
|
2020-09-03 16:34:36 +02:00
|
|
|
if parent := t.getParentSpanContext(ctx, config); parent.IsValid() {
|
2019-09-25 08:12:22 +02:00
|
|
|
return parent.TraceID
|
|
|
|
}
|
|
|
|
if len(t.SpareTraceIDs) > 0 {
|
|
|
|
traceID := t.SpareTraceIDs[0]
|
|
|
|
t.SpareTraceIDs = t.SpareTraceIDs[1:]
|
|
|
|
if len(t.SpareTraceIDs) == 0 {
|
|
|
|
t.SpareTraceIDs = nil
|
|
|
|
}
|
|
|
|
return traceID
|
|
|
|
}
|
2019-10-23 08:01:33 +02:00
|
|
|
return t.getRandTraceID()
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (t *MockTracer) getParentSpanID(ctx context.Context, config *trace.SpanConfig) trace.SpanID {
|
2020-09-03 16:34:36 +02:00
|
|
|
if parent := t.getParentSpanContext(ctx, config); parent.IsValid() {
|
2019-09-25 08:12:22 +02:00
|
|
|
return parent.SpanID
|
|
|
|
}
|
2020-11-07 00:13:31 +02:00
|
|
|
return trace.SpanID{}
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (t *MockTracer) getParentSpanContext(ctx context.Context, config *trace.SpanConfig) trace.SpanContext {
|
2020-09-03 16:34:36 +02:00
|
|
|
spanCtx, _, _ := otelparent.GetSpanContextAndLinks(ctx, config.NewRoot)
|
2020-02-04 18:55:03 +02:00
|
|
|
return spanCtx
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (t *MockTracer) getSpanID() trace.SpanID {
|
2019-09-25 08:12:22 +02:00
|
|
|
if len(t.SpareSpanIDs) > 0 {
|
|
|
|
spanID := t.SpareSpanIDs[0]
|
|
|
|
t.SpareSpanIDs = t.SpareSpanIDs[1:]
|
|
|
|
if len(t.SpareSpanIDs) == 0 {
|
|
|
|
t.SpareSpanIDs = nil
|
|
|
|
}
|
|
|
|
return spanID
|
|
|
|
}
|
2019-10-28 19:05:06 +02:00
|
|
|
return t.getRandSpanID()
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (t *MockTracer) getRandSpanID() trace.SpanID {
|
2019-10-23 08:01:33 +02:00
|
|
|
t.randLock.Lock()
|
|
|
|
defer t.randLock.Unlock()
|
2019-10-28 19:05:06 +02:00
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
sid := trace.SpanID{}
|
2019-10-28 19:05:06 +02:00
|
|
|
t.rand.Read(sid[:])
|
|
|
|
|
|
|
|
return sid
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (t *MockTracer) getRandTraceID() trace.TraceID {
|
2019-09-25 08:12:22 +02:00
|
|
|
t.randLock.Lock()
|
|
|
|
defer t.randLock.Unlock()
|
2019-10-23 08:01:33 +02:00
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
tid := trace.TraceID{}
|
2019-10-23 08:01:33 +02:00
|
|
|
t.rand.Read(tid[:])
|
|
|
|
|
|
|
|
return tid
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (t *MockTracer) DeferredContextSetupHook(ctx context.Context, span trace.Span) context.Context {
|
2019-09-25 08:12:22 +02:00
|
|
|
return t.addSpareContextValue(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
type MockEvent struct {
|
2020-10-16 17:09:27 +02:00
|
|
|
Timestamp time.Time
|
|
|
|
Name string
|
|
|
|
Attributes baggage.Map
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type MockSpan struct {
|
|
|
|
mockTracer *MockTracer
|
2020-11-07 00:13:31 +02:00
|
|
|
officialTracer trace.Tracer
|
|
|
|
spanContext trace.SpanContext
|
|
|
|
SpanKind trace.SpanKind
|
2019-09-25 08:12:22 +02:00
|
|
|
recording bool
|
|
|
|
|
2020-10-05 17:25:09 +02:00
|
|
|
Attributes baggage.Map
|
2019-09-25 08:12:22 +02:00
|
|
|
StartTime time.Time
|
2019-09-27 19:48:10 +02:00
|
|
|
EndTime time.Time
|
2020-11-07 00:13:31 +02:00
|
|
|
ParentSpanID trace.SpanID
|
2019-09-25 08:12:22 +02:00
|
|
|
Events []MockEvent
|
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
var _ trace.Span = &MockSpan{}
|
2019-09-25 08:12:22 +02:00
|
|
|
var _ migration.OverrideTracerSpanExtension = &MockSpan{}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (s *MockSpan) SpanContext() trace.SpanContext {
|
2019-09-25 08:12:22 +02:00
|
|
|
return s.spanContext
|
|
|
|
}
|
|
|
|
|
2019-10-11 03:07:35 +02:00
|
|
|
func (s *MockSpan) IsRecording() bool {
|
2019-09-25 08:12:22 +02:00
|
|
|
return s.recording
|
|
|
|
}
|
|
|
|
|
2020-03-07 20:38:59 +02:00
|
|
|
func (s *MockSpan) SetStatus(code codes.Code, msg string) {
|
|
|
|
s.SetAttributes(StatusCodeKey.Uint32(uint32(code)), StatusMessageKey.String(msg))
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MockSpan) SetName(name string) {
|
2019-12-03 07:58:55 +02:00
|
|
|
s.SetAttributes(NameKey.String(name))
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MockSpan) SetError(v bool) {
|
2019-12-03 07:58:55 +02:00
|
|
|
s.SetAttributes(ErrorKey.Bool(v))
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
|
|
|
|
2020-08-18 05:25:03 +02:00
|
|
|
func (s *MockSpan) SetAttributes(attributes ...label.KeyValue) {
|
2020-10-05 17:25:09 +02:00
|
|
|
s.applyUpdate(baggage.MapUpdate{
|
2019-10-30 22:21:13 +02:00
|
|
|
MultiKV: attributes,
|
2019-09-25 08:12:22 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-10-05 17:25:09 +02:00
|
|
|
func (s *MockSpan) applyUpdate(update baggage.MapUpdate) {
|
2019-09-25 08:12:22 +02:00
|
|
|
s.Attributes = s.Attributes.Apply(update)
|
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (s *MockSpan) End(options ...trace.SpanOption) {
|
2019-09-27 19:48:10 +02:00
|
|
|
if !s.EndTime.IsZero() {
|
2019-09-25 08:12:22 +02:00
|
|
|
return // already finished
|
|
|
|
}
|
2020-11-07 00:13:31 +02:00
|
|
|
config := trace.NewSpanConfig(options...)
|
2020-09-03 16:34:36 +02:00
|
|
|
endTime := config.Timestamp
|
2019-09-27 19:48:10 +02:00
|
|
|
if endTime.IsZero() {
|
|
|
|
endTime = time.Now()
|
2019-09-25 08:12:22 +02:00
|
|
|
}
|
2019-09-27 19:48:10 +02:00
|
|
|
s.EndTime = endTime
|
2019-09-25 08:12:22 +02:00
|
|
|
s.mockTracer.FinishedSpans = append(s.mockTracer.FinishedSpans, s)
|
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (s *MockSpan) RecordError(err error, opts ...trace.EventOption) {
|
2020-02-28 23:44:53 +02:00
|
|
|
if err == nil {
|
|
|
|
return // no-op on nil error
|
|
|
|
}
|
|
|
|
|
|
|
|
if !s.EndTime.IsZero() {
|
|
|
|
return // already finished
|
|
|
|
}
|
|
|
|
|
2020-10-16 17:09:27 +02:00
|
|
|
s.SetStatus(codes.Error, "")
|
2020-11-07 00:13:31 +02:00
|
|
|
opts = append(opts, trace.WithAttributes(
|
2020-08-18 05:25:03 +02:00
|
|
|
label.String("error.type", reflect.TypeOf(err).String()),
|
|
|
|
label.String("error.message", err.Error()),
|
2020-10-16 17:09:27 +02:00
|
|
|
))
|
|
|
|
s.AddEvent("error", opts...)
|
2020-02-28 23:44:53 +02:00
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (s *MockSpan) Tracer() trace.Tracer {
|
2019-09-25 08:12:22 +02:00
|
|
|
return s.officialTracer
|
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (s *MockSpan) AddEvent(name string, o ...trace.EventOption) {
|
|
|
|
c := trace.NewEventConfig(o...)
|
2019-09-25 08:12:22 +02:00
|
|
|
s.Events = append(s.Events, MockEvent{
|
2020-10-16 17:09:27 +02:00
|
|
|
Timestamp: c.Timestamp,
|
|
|
|
Name: name,
|
2020-10-05 17:25:09 +02:00
|
|
|
Attributes: baggage.NewMap(baggage.MapUpdate{
|
2020-10-16 17:09:27 +02:00
|
|
|
MultiKV: c.Attributes,
|
2019-10-30 22:21:13 +02:00
|
|
|
}),
|
2019-09-25 08:12:22 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-11-07 00:13:31 +02:00
|
|
|
func (s *MockSpan) OverrideTracer(tracer trace.Tracer) {
|
2019-09-25 08:12:22 +02:00
|
|
|
s.officialTracer = tracer
|
|
|
|
}
|