...

Source file src/go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform/span.go

Documentation: go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform

     1  // Copyright The OpenTelemetry Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tracetransform // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform"
    16  
    17  import (
    18  	"go.opentelemetry.io/otel/attribute"
    19  	"go.opentelemetry.io/otel/codes"
    20  	"go.opentelemetry.io/otel/sdk/instrumentation"
    21  	tracesdk "go.opentelemetry.io/otel/sdk/trace"
    22  	"go.opentelemetry.io/otel/trace"
    23  	tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
    24  )
    25  
    26  // Spans transforms a slice of OpenTelemetry spans into a slice of OTLP
    27  // ResourceSpans.
    28  func Spans(sdl []tracesdk.ReadOnlySpan) []*tracepb.ResourceSpans {
    29  	if len(sdl) == 0 {
    30  		return nil
    31  	}
    32  
    33  	rsm := make(map[attribute.Distinct]*tracepb.ResourceSpans)
    34  
    35  	type key struct {
    36  		r  attribute.Distinct
    37  		is instrumentation.Scope
    38  	}
    39  	ssm := make(map[key]*tracepb.ScopeSpans)
    40  
    41  	var resources int
    42  	for _, sd := range sdl {
    43  		if sd == nil {
    44  			continue
    45  		}
    46  
    47  		rKey := sd.Resource().Equivalent()
    48  		k := key{
    49  			r:  rKey,
    50  			is: sd.InstrumentationScope(),
    51  		}
    52  		scopeSpan, iOk := ssm[k]
    53  		if !iOk {
    54  			// Either the resource or instrumentation scope were unknown.
    55  			scopeSpan = &tracepb.ScopeSpans{
    56  				Scope:     InstrumentationScope(sd.InstrumentationScope()),
    57  				Spans:     []*tracepb.Span{},
    58  				SchemaUrl: sd.InstrumentationScope().SchemaURL,
    59  			}
    60  		}
    61  		scopeSpan.Spans = append(scopeSpan.Spans, span(sd))
    62  		ssm[k] = scopeSpan
    63  
    64  		rs, rOk := rsm[rKey]
    65  		if !rOk {
    66  			resources++
    67  			// The resource was unknown.
    68  			rs = &tracepb.ResourceSpans{
    69  				Resource:   Resource(sd.Resource()),
    70  				ScopeSpans: []*tracepb.ScopeSpans{scopeSpan},
    71  				SchemaUrl:  sd.Resource().SchemaURL(),
    72  			}
    73  			rsm[rKey] = rs
    74  			continue
    75  		}
    76  
    77  		// The resource has been seen before. Check if the instrumentation
    78  		// library lookup was unknown because if so we need to add it to the
    79  		// ResourceSpans. Otherwise, the instrumentation library has already
    80  		// been seen and the append we did above will be included it in the
    81  		// ScopeSpans reference.
    82  		if !iOk {
    83  			rs.ScopeSpans = append(rs.ScopeSpans, scopeSpan)
    84  		}
    85  	}
    86  
    87  	// Transform the categorized map into a slice
    88  	rss := make([]*tracepb.ResourceSpans, 0, resources)
    89  	for _, rs := range rsm {
    90  		rss = append(rss, rs)
    91  	}
    92  	return rss
    93  }
    94  
    95  // span transforms a Span into an OTLP span.
    96  func span(sd tracesdk.ReadOnlySpan) *tracepb.Span {
    97  	if sd == nil {
    98  		return nil
    99  	}
   100  
   101  	tid := sd.SpanContext().TraceID()
   102  	sid := sd.SpanContext().SpanID()
   103  
   104  	s := &tracepb.Span{
   105  		TraceId:                tid[:],
   106  		SpanId:                 sid[:],
   107  		TraceState:             sd.SpanContext().TraceState().String(),
   108  		Status:                 status(sd.Status().Code, sd.Status().Description),
   109  		StartTimeUnixNano:      uint64(sd.StartTime().UnixNano()),
   110  		EndTimeUnixNano:        uint64(sd.EndTime().UnixNano()),
   111  		Links:                  links(sd.Links()),
   112  		Kind:                   spanKind(sd.SpanKind()),
   113  		Name:                   sd.Name(),
   114  		Attributes:             KeyValues(sd.Attributes()),
   115  		Events:                 spanEvents(sd.Events()),
   116  		DroppedAttributesCount: uint32(sd.DroppedAttributes()),
   117  		DroppedEventsCount:     uint32(sd.DroppedEvents()),
   118  		DroppedLinksCount:      uint32(sd.DroppedLinks()),
   119  	}
   120  
   121  	if psid := sd.Parent().SpanID(); psid.IsValid() {
   122  		s.ParentSpanId = psid[:]
   123  	}
   124  
   125  	return s
   126  }
   127  
   128  // status transform a span code and message into an OTLP span status.
   129  func status(status codes.Code, message string) *tracepb.Status {
   130  	var c tracepb.Status_StatusCode
   131  	switch status {
   132  	case codes.Ok:
   133  		c = tracepb.Status_STATUS_CODE_OK
   134  	case codes.Error:
   135  		c = tracepb.Status_STATUS_CODE_ERROR
   136  	default:
   137  		c = tracepb.Status_STATUS_CODE_UNSET
   138  	}
   139  	return &tracepb.Status{
   140  		Code:    c,
   141  		Message: message,
   142  	}
   143  }
   144  
   145  // links transforms span Links to OTLP span links.
   146  func links(links []tracesdk.Link) []*tracepb.Span_Link {
   147  	if len(links) == 0 {
   148  		return nil
   149  	}
   150  
   151  	sl := make([]*tracepb.Span_Link, 0, len(links))
   152  	for _, otLink := range links {
   153  		// This redefinition is necessary to prevent otLink.*ID[:] copies
   154  		// being reused -- in short we need a new otLink per iteration.
   155  		otLink := otLink
   156  
   157  		tid := otLink.SpanContext.TraceID()
   158  		sid := otLink.SpanContext.SpanID()
   159  
   160  		sl = append(sl, &tracepb.Span_Link{
   161  			TraceId:                tid[:],
   162  			SpanId:                 sid[:],
   163  			Attributes:             KeyValues(otLink.Attributes),
   164  			DroppedAttributesCount: uint32(otLink.DroppedAttributeCount),
   165  		})
   166  	}
   167  	return sl
   168  }
   169  
   170  // spanEvents transforms span Events to an OTLP span events.
   171  func spanEvents(es []tracesdk.Event) []*tracepb.Span_Event {
   172  	if len(es) == 0 {
   173  		return nil
   174  	}
   175  
   176  	events := make([]*tracepb.Span_Event, len(es))
   177  	// Transform message events
   178  	for i := 0; i < len(es); i++ {
   179  		events[i] = &tracepb.Span_Event{
   180  			Name:                   es[i].Name,
   181  			TimeUnixNano:           uint64(es[i].Time.UnixNano()),
   182  			Attributes:             KeyValues(es[i].Attributes),
   183  			DroppedAttributesCount: uint32(es[i].DroppedAttributeCount),
   184  		}
   185  	}
   186  	return events
   187  }
   188  
   189  // spanKind transforms a SpanKind to an OTLP span kind.
   190  func spanKind(kind trace.SpanKind) tracepb.Span_SpanKind {
   191  	switch kind {
   192  	case trace.SpanKindInternal:
   193  		return tracepb.Span_SPAN_KIND_INTERNAL
   194  	case trace.SpanKindClient:
   195  		return tracepb.Span_SPAN_KIND_CLIENT
   196  	case trace.SpanKindServer:
   197  		return tracepb.Span_SPAN_KIND_SERVER
   198  	case trace.SpanKindProducer:
   199  		return tracepb.Span_SPAN_KIND_PRODUCER
   200  	case trace.SpanKindConsumer:
   201  		return tracepb.Span_SPAN_KIND_CONSUMER
   202  	default:
   203  		return tracepb.Span_SPAN_KIND_UNSPECIFIED
   204  	}
   205  }
   206  

View as plain text