operatortrace-go/pkg/client/span_helpers.go (97 lines of code) (raw):
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// pkg/client/span_helpers.go
package client
import (
"context"
"strconv"
"time"
constants "github.com/Azure/operatortrace/operatortrace-go/pkg/constants"
"github.com/go-logr/logr"
"go.opentelemetry.io/otel/trace"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// startSpanFromContext starts a new span from the context and attaches trace information to the object
func startSpanFromContext(ctx context.Context, logger logr.Logger, tracer trace.Tracer, obj client.Object, scheme *runtime.Scheme, operationName string) (context.Context, trace.Span) {
span := trace.SpanFromContext(ctx)
if span.SpanContext().IsValid() {
spanContext := trace.NewSpanContext(trace.SpanContextConfig{
TraceID: span.SpanContext().TraceID(),
SpanID: span.SpanContext().SpanID(),
})
ctx = trace.ContextWithRemoteSpanContext(ctx, spanContext)
ctx, span = tracer.Start(ctx, operationName)
return ctx, span
}
if !span.SpanContext().IsValid() {
if obj != nil {
// no valid trace ID in context, check object conditions
if traceID, err := getConditionMessage("TraceID", obj, scheme); err == nil {
// Check if the traceID is more than 10 minutes old, if it is, we will not use it
if traceIdTime, err := getConditionTime("TraceID", obj, scheme); err == nil {
if traceIdTime.Time.Before(metav1.Now().Add(-constants.TraceExpirationTime * time.Minute)) {
logger.Info("TraceID is more than " + strconv.Itoa(constants.TraceExpirationTime) + " minutes old, not using it")
} else {
if traceIDValue, err := trace.TraceIDFromHex(traceID); err == nil {
spanContext := trace.NewSpanContext(trace.SpanContextConfig{})
if spanID, err := getConditionMessage("SpanID", obj, scheme); err == nil {
if spanIDValue, err := trace.SpanIDFromHex(spanID); err == nil {
spanContext = trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceIDValue,
SpanID: spanIDValue,
})
} else {
spanContext = trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceIDValue,
})
}
}
ctx = trace.ContextWithRemoteSpanContext(ctx, spanContext)
}
}
}
} else {
// No valid trace ID in context, check object annotations
if traceID, ok := obj.GetAnnotations()[constants.TraceIDAnnotation]; ok {
// Check if the traceID is more than 10 minutes (from constants) old, if it is, we will not use it
if traceIDTime, ok := obj.GetAnnotations()[constants.TraceIDTimeAnnotation]; ok {
if traceIdTimeValue, err := time.Parse(time.RFC3339, traceIDTime); err == nil {
if traceIdTimeValue.Before(time.Now().Add(-constants.TraceExpirationTime * time.Minute)) {
logger.Info("TraceID is more than " + strconv.Itoa(constants.TraceExpirationTime) + " minutes old, not using it")
} else {
if traceIDValue, err := trace.TraceIDFromHex(traceID); err == nil {
spanContext := trace.NewSpanContext(trace.SpanContextConfig{})
if spanID, ok := obj.GetAnnotations()[constants.SpanIDAnnotation]; ok {
if spanIDValue, err := trace.SpanIDFromHex(spanID); err == nil {
spanContext = trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceIDValue,
SpanID: spanIDValue,
})
} else {
spanContext = trace.NewSpanContext(trace.SpanContextConfig{
TraceID: traceIDValue,
})
}
}
ctx = trace.ContextWithRemoteSpanContext(ctx, spanContext)
} else {
logger.Error(err, "Invalid trace ID", "traceID", traceID)
}
}
}
}
}
}
}
}
// Create a new span
ctx, span = tracer.Start(ctx, operationName)
return ctx, span
}
func startSpanFromContextList(ctx context.Context, logger logr.Logger, tracer trace.Tracer, obj client.ObjectList, operationName string) (context.Context, trace.Span) {
span := trace.SpanFromContext(ctx)
if span.SpanContext().IsValid() {
spanContext := trace.NewSpanContext(trace.SpanContextConfig{
TraceID: span.SpanContext().TraceID(),
SpanID: span.SpanContext().SpanID(),
})
ctx = trace.ContextWithRemoteSpanContext(ctx, spanContext)
ctx, span = tracer.Start(ctx, operationName)
return trace.ContextWithSpan(ctx, span), span
}
// Create a new span
ctx, span = tracer.Start(ctx, operationName)
return ctx, span
}