func()

in exporter/trace/trace_proto.go [128:225]


func (e *traceExporter) protoFromReadOnlySpan(s sdktrace.ReadOnlySpan) (*tracepb.Span, string) {
	if s == nil {
		return nil, ""
	}

	traceIDString := s.SpanContext().TraceID().String()
	spanIDString := s.SpanContext().SpanID().String()
	projectID := e.projectID
	// override project ID with gcp.project.id, if present
	attrs := s.Resource().Attributes()
	for _, attr := range attrs {
		if attr.Key == resourcemapping.ProjectIDAttributeKey {
			projectID = attr.Value.AsString()
			break
		}
	}

	sp := &tracepb.Span{
		Name:                    "projects/" + projectID + "/traces/" + traceIDString + "/spans/" + spanIDString,
		SpanId:                  spanIDString,
		DisplayName:             trunc(s.Name(), 128),
		StartTime:               timestampProto(s.StartTime()),
		EndTime:                 timestampProto(s.EndTime()),
		SameProcessAsParentSpan: &wrapperspb.BoolValue{Value: !s.Parent().IsRemote()},
		SpanKind:                convertSpanKind(s.SpanKind()),
	}
	if s.Parent().SpanID() != s.SpanContext().SpanID() && s.Parent().SpanID().IsValid() {
		sp.ParentSpanId = s.Parent().SpanID().String()
	}
	switch s.Status().Code {
	case codes.Ok:
		sp.Status = &statuspb.Status{Code: int32(codepb.Code_OK)}
	case codes.Unset:
		// Don't set status code.
	case codes.Error:
		sp.Status = &statuspb.Status{Code: int32(codepb.Code_UNKNOWN), Message: s.Status().Description}
	default:
		sp.Status = &statuspb.Status{Code: int32(codepb.Code_UNKNOWN)}
	}

	attributes := attributeWithLabelsFromResources(s)
	e.copyAttributes(&sp.Attributes, attributes)
	// NOTE(ymotongpoo): omitting copyMonitoringReesourceAttributes()

	var annotations, droppedAnnotationsCount int
	es := s.Events()
	for i, ev := range es {
		if annotations >= maxAnnotationEventsPerSpan {
			droppedAnnotationsCount = len(es) - i
			break
		}
		annotation := &tracepb.Span_TimeEvent_Annotation{Description: trunc(ev.Name, maxAttributeStringValue)}
		e.copyAttributes(&annotation.Attributes, ev.Attributes)
		event := &tracepb.Span_TimeEvent{
			Time:  timestampProto(ev.Time),
			Value: &tracepb.Span_TimeEvent_Annotation_{Annotation: annotation},
		}
		annotations++
		if sp.TimeEvents == nil {
			sp.TimeEvents = &tracepb.Span_TimeEvents{}
		}
		sp.TimeEvents.TimeEvent = append(sp.TimeEvents.TimeEvent, event)
	}

	if sp.Attributes == nil {
		sp.Attributes = &tracepb.Span_Attributes{
			AttributeMap: make(map[string]*tracepb.AttributeValue),
		}
	}

	// Only set the agent label if it is not already set. That enables the
	// OpenTelemery service/collector to set the agent label based on the library that
	// sent the span to the service.
	// TODO(jsuereth): This scenario is highly unlikely.  This would require vanilla OTLP
	// sources of tracess to be setting "g.co/agent" labels on spans.  We should confirm
	// and remove/update this code.
	if _, hasAgent := sp.Attributes.AttributeMap[agentLabel]; !hasAgent {
		sp.Attributes.AttributeMap[agentLabel] = &tracepb.AttributeValue{
			Value: &tracepb.AttributeValue_StringValue{
				StringValue: trunc(userAgent, maxAttributeStringValue),
			},
		}
	}

	// TODO(ymotongpoo): add implementations for Span_TimeEvent_MessageEvent_
	// once OTel finish implementations for gRPC.

	if droppedAnnotationsCount != 0 {
		if sp.TimeEvents == nil {
			sp.TimeEvents = &tracepb.Span_TimeEvents{}
		}
		sp.TimeEvents.DroppedAnnotationsCount = clip32(droppedAnnotationsCount)
	}

	sp.Links = e.linksProtoFromLinks(s.Links())

	return sp, projectID
}