...

Source file src/k8s.io/component-base/tracing/tracing.go

Documentation: k8s.io/component-base/tracing

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package tracing
    18  
    19  import (
    20  	"context"
    21  	"time"
    22  
    23  	"go.opentelemetry.io/otel/attribute"
    24  	"go.opentelemetry.io/otel/trace"
    25  
    26  	utiltrace "k8s.io/utils/trace"
    27  )
    28  
    29  const instrumentationScope = "k8s.io/component-base/tracing"
    30  
    31  // Start creates spans using both OpenTelemetry, and the k8s.io/utils/trace package.
    32  // It only creates an OpenTelemetry span if the incoming context already includes a span.
    33  func Start(ctx context.Context, name string, attributes ...attribute.KeyValue) (context.Context, *Span) {
    34  	// If the incoming context already includes an OpenTelemetry span, create a child span with the provided name and attributes.
    35  	// If the caller is not using OpenTelemetry, or has tracing disabled (e.g. with a component-specific feature flag), this is a noop.
    36  	ctx, otelSpan := trace.SpanFromContext(ctx).TracerProvider().Tracer(instrumentationScope).Start(ctx, name, trace.WithAttributes(attributes...))
    37  	// If there is already a utiltrace span in the context, use that as our parent span.
    38  	utilSpan := utiltrace.FromContext(ctx).Nest(name, attributesToFields(attributes)...)
    39  	// Set the trace as active in the context so that subsequent Start calls create nested spans.
    40  	return utiltrace.ContextWithTrace(ctx, utilSpan), &Span{
    41  		otelSpan: otelSpan,
    42  		utilSpan: utilSpan,
    43  	}
    44  }
    45  
    46  // Span is a component part of a trace. It represents a single named
    47  // and timed operation of a workflow being observed.
    48  // This Span is a combination of an OpenTelemetry and k8s.io/utils/trace span
    49  // to facilitate the migration to OpenTelemetry.
    50  type Span struct {
    51  	otelSpan trace.Span
    52  	utilSpan *utiltrace.Trace
    53  }
    54  
    55  // AddEvent adds a point-in-time event with a name and attributes.
    56  func (s *Span) AddEvent(name string, attributes ...attribute.KeyValue) {
    57  	s.otelSpan.AddEvent(name, trace.WithAttributes(attributes...))
    58  	if s.utilSpan != nil {
    59  		s.utilSpan.Step(name, attributesToFields(attributes)...)
    60  	}
    61  }
    62  
    63  // End ends the span, and logs if the span duration is greater than the logThreshold.
    64  func (s *Span) End(logThreshold time.Duration) {
    65  	s.otelSpan.End()
    66  	if s.utilSpan != nil {
    67  		s.utilSpan.LogIfLong(logThreshold)
    68  	}
    69  }
    70  
    71  // RecordError will record err as an exception span event for this span.
    72  // If this span is not being recorded or err is nil then this method does nothing.
    73  func (s *Span) RecordError(err error, attributes ...attribute.KeyValue) {
    74  	s.otelSpan.RecordError(err, trace.WithAttributes(attributes...))
    75  }
    76  
    77  func attributesToFields(attributes []attribute.KeyValue) []utiltrace.Field {
    78  	fields := make([]utiltrace.Field, len(attributes))
    79  	for i := range attributes {
    80  		attr := attributes[i]
    81  		fields[i] = utiltrace.Field{Key: string(attr.Key), Value: attr.Value.AsInterface()}
    82  	}
    83  	return fields
    84  }
    85  
    86  // SpanFromContext returns the *Span from the current context. It is composed of the active
    87  // OpenTelemetry and k8s.io/utils/trace spans.
    88  func SpanFromContext(ctx context.Context) *Span {
    89  	return &Span{
    90  		otelSpan: trace.SpanFromContext(ctx),
    91  		utilSpan: utiltrace.FromContext(ctx),
    92  	}
    93  }
    94  
    95  // ContextWithSpan returns a context with the Span included in the context.
    96  func ContextWithSpan(ctx context.Context, s *Span) context.Context {
    97  	return trace.ContextWithSpan(utiltrace.ContextWithTrace(ctx, s.utilSpan), s.otelSpan)
    98  }
    99  

View as plain text