blob: 1afc62cd969ebbe2f462571ea4adca192412d5e0 [file] [log] [blame] [edit]
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package otel
import (
"slices"
"golang.org/x/tools/internal/event"
"golang.org/x/tools/internal/event/core"
"golang.org/x/tools/internal/event/export"
"golang.org/x/tools/internal/event/keys"
)
// exportTraces sends traces to the OTLP endpoint.
func (e *Exporter) exportTraces(spans []otlpSpan) error {
req := otlpTraceExportRequest{
ResourceSpans: []otlpResourceSpans{{
Resource: e.resource,
ScopeSpans: []otlpScopeSpans{{
Scope: otlpScope{Name: "golang.org/x/tools"},
Spans: spans,
}},
}},
}
return e.post("/v1/traces", req)
}
// convertSpan converts an internal Span to an OTLP span.
func convertSpan(span *export.Span) otlpSpan {
s := otlpSpan{
TraceID: span.ID.TraceID.String(),
SpanID: span.ID.SpanID.String(),
Name: span.Name,
Kind: 1, // SPAN_KIND_INTERNAL
Status: otlpSpanStatus{Code: 0}, // STATUS_CODE_UNSET
}
if span.ParentID.IsValid() {
s.ParentSpanID = span.ParentID.String()
}
// Get timestamps from start event
startEvent := span.Start()
if !startEvent.At().IsZero() {
s.StartTimeUnixNano = intAsString(startEvent.At().UnixNano())
}
// Get end timestamp from finish event
finishEvent := span.Finish()
if !finishEvent.At().IsZero() {
s.EndTimeUnixNano = intAsString(finishEvent.At().UnixNano())
}
// Check for errors in span events to set status
if slices.ContainsFunc(span.Events(), event.IsError) {
s.Status.Code = 2 // STATUS_CODE_ERROR
}
// Extract attributes from span events
s.Attributes = extractAttributes(span)
return s
}
// extractAttributes extracts labels from span events as OTLP attributes.
func extractAttributes(span *export.Span) []otlpAttribute {
var attrs []otlpAttribute
// Extract from start event
startEvent := span.Start()
attrs = appendEventAttributes(attrs, startEvent)
// Extract from logged events
for _, ev := range span.Events() {
attrs = appendEventAttributes(attrs, ev)
}
return attrs
}
// appendEventAttributes appends labels from an event as attributes.
func appendEventAttributes(attrs []otlpAttribute, ev core.Event) []otlpAttribute {
for l := range ev.Labels() {
key := l.Key()
// Skip internal event type markers
if key == keys.Start || key == keys.End || key == keys.Label ||
key == keys.Detach || key == keys.Metric {
continue
}
if attr, ok := labelToAttribute(l); ok {
attrs = append(attrs, attr)
}
}
return attrs
}