commit
1018595476
|
@ -1,141 +0,0 @@
|
||||||
// Copyright The OpenTelemetry Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package tracetransform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/attribute"
|
|
||||||
commonpb "go.opentelemetry.io/proto/otlp/common/v1"
|
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/sdk/resource"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Attributes transforms a slice of KeyValues into a slice of OTLP attribute key-values.
|
|
||||||
func Attributes(attrs []attribute.KeyValue) []*commonpb.KeyValue {
|
|
||||||
if len(attrs) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
out := make([]*commonpb.KeyValue, 0, len(attrs))
|
|
||||||
for _, kv := range attrs {
|
|
||||||
out = append(out, toAttribute(kv))
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceAttributes transforms a Resource into a slice of OTLP attribute key-values.
|
|
||||||
func ResourceAttributes(resource *resource.Resource) []*commonpb.KeyValue {
|
|
||||||
if resource.Len() == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
out := make([]*commonpb.KeyValue, 0, resource.Len())
|
|
||||||
for iter := resource.Iter(); iter.Next(); {
|
|
||||||
out = append(out, toAttribute(iter.Attribute()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func toAttribute(v attribute.KeyValue) *commonpb.KeyValue {
|
|
||||||
result := &commonpb.KeyValue{
|
|
||||||
Key: string(v.Key),
|
|
||||||
Value: new(commonpb.AnyValue),
|
|
||||||
}
|
|
||||||
switch v.Value.Type() {
|
|
||||||
case attribute.BOOL:
|
|
||||||
result.Value.Value = &commonpb.AnyValue_BoolValue{
|
|
||||||
BoolValue: v.Value.AsBool(),
|
|
||||||
}
|
|
||||||
case attribute.INT64:
|
|
||||||
result.Value.Value = &commonpb.AnyValue_IntValue{
|
|
||||||
IntValue: v.Value.AsInt64(),
|
|
||||||
}
|
|
||||||
case attribute.FLOAT64:
|
|
||||||
result.Value.Value = &commonpb.AnyValue_DoubleValue{
|
|
||||||
DoubleValue: v.Value.AsFloat64(),
|
|
||||||
}
|
|
||||||
case attribute.STRING:
|
|
||||||
result.Value.Value = &commonpb.AnyValue_StringValue{
|
|
||||||
StringValue: v.Value.AsString(),
|
|
||||||
}
|
|
||||||
case attribute.ARRAY:
|
|
||||||
result.Value.Value = &commonpb.AnyValue_ArrayValue{
|
|
||||||
ArrayValue: &commonpb.ArrayValue{
|
|
||||||
Values: arrayValues(v),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
result.Value.Value = &commonpb.AnyValue_StringValue{
|
|
||||||
StringValue: "INVALID",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func arrayValues(kv attribute.KeyValue) []*commonpb.AnyValue {
|
|
||||||
a := kv.Value.AsArray()
|
|
||||||
aType := reflect.TypeOf(a)
|
|
||||||
var valueFunc func(reflect.Value) *commonpb.AnyValue
|
|
||||||
switch aType.Elem().Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
|
|
||||||
return &commonpb.AnyValue{
|
|
||||||
Value: &commonpb.AnyValue_BoolValue{
|
|
||||||
BoolValue: v.Bool(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case reflect.Int, reflect.Int64:
|
|
||||||
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
|
|
||||||
return &commonpb.AnyValue{
|
|
||||||
Value: &commonpb.AnyValue_IntValue{
|
|
||||||
IntValue: v.Int(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case reflect.Uintptr:
|
|
||||||
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
|
|
||||||
return &commonpb.AnyValue{
|
|
||||||
Value: &commonpb.AnyValue_IntValue{
|
|
||||||
IntValue: int64(v.Uint()),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case reflect.Float64:
|
|
||||||
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
|
|
||||||
return &commonpb.AnyValue{
|
|
||||||
Value: &commonpb.AnyValue_DoubleValue{
|
|
||||||
DoubleValue: v.Float(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case reflect.String:
|
|
||||||
valueFunc = func(v reflect.Value) *commonpb.AnyValue {
|
|
||||||
return &commonpb.AnyValue{
|
|
||||||
Value: &commonpb.AnyValue_StringValue{
|
|
||||||
StringValue: v.String(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results := make([]*commonpb.AnyValue, aType.Len())
|
|
||||||
for i, aValue := 0, reflect.ValueOf(a); i < aValue.Len(); i++ {
|
|
||||||
results[i] = valueFunc(aValue.Index(i))
|
|
||||||
}
|
|
||||||
return results
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
// Copyright The OpenTelemetry Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package tracetransform
|
|
||||||
|
|
||||||
import (
|
|
||||||
commonpb "go.opentelemetry.io/proto/otlp/common/v1"
|
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
|
||||||
)
|
|
||||||
|
|
||||||
func InstrumentationLibrary(il instrumentation.Library) *commonpb.InstrumentationLibrary {
|
|
||||||
if il == (instrumentation.Library{}) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &commonpb.InstrumentationLibrary{
|
|
||||||
Name: il.Name,
|
|
||||||
Version: il.Version,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
// Copyright The OpenTelemetry Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package tracetransform
|
|
||||||
|
|
||||||
import (
|
|
||||||
resourcepb "go.opentelemetry.io/proto/otlp/resource/v1"
|
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/sdk/resource"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Resource transforms a Resource into an OTLP Resource.
|
|
||||||
func Resource(r *resource.Resource) *resourcepb.Resource {
|
|
||||||
if r == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &resourcepb.Resource{Attributes: ResourceAttributes(r)}
|
|
||||||
}
|
|
|
@ -1,218 +0,0 @@
|
||||||
// Copyright The OpenTelemetry Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package tracetransform
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go.opentelemetry.io/otel/attribute"
|
|
||||||
"go.opentelemetry.io/otel/codes"
|
|
||||||
tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
|
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/sdk/instrumentation"
|
|
||||||
tracesdk "go.opentelemetry.io/otel/sdk/trace"
|
|
||||||
"go.opentelemetry.io/otel/trace"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
maxEventsPerSpan = 128
|
|
||||||
)
|
|
||||||
|
|
||||||
// Spans transforms a slice of OpenTelemetry spans into a slice of OTLP
|
|
||||||
// ResourceSpans.
|
|
||||||
func Spans(sdl []tracesdk.ReadOnlySpan) []*tracepb.ResourceSpans {
|
|
||||||
if len(sdl) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rsm := make(map[attribute.Distinct]*tracepb.ResourceSpans)
|
|
||||||
|
|
||||||
type ilsKey struct {
|
|
||||||
r attribute.Distinct
|
|
||||||
il instrumentation.Library
|
|
||||||
}
|
|
||||||
ilsm := make(map[ilsKey]*tracepb.InstrumentationLibrarySpans)
|
|
||||||
|
|
||||||
var resources int
|
|
||||||
for _, sd := range sdl {
|
|
||||||
if sd == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
rKey := sd.Resource().Equivalent()
|
|
||||||
iKey := ilsKey{
|
|
||||||
r: rKey,
|
|
||||||
il: sd.InstrumentationLibrary(),
|
|
||||||
}
|
|
||||||
ils, iOk := ilsm[iKey]
|
|
||||||
if !iOk {
|
|
||||||
// Either the resource or instrumentation library were unknown.
|
|
||||||
ils = &tracepb.InstrumentationLibrarySpans{
|
|
||||||
InstrumentationLibrary: InstrumentationLibrary(sd.InstrumentationLibrary()),
|
|
||||||
Spans: []*tracepb.Span{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ils.Spans = append(ils.Spans, span(sd))
|
|
||||||
ilsm[iKey] = ils
|
|
||||||
|
|
||||||
rs, rOk := rsm[rKey]
|
|
||||||
if !rOk {
|
|
||||||
resources++
|
|
||||||
// The resource was unknown.
|
|
||||||
rs = &tracepb.ResourceSpans{
|
|
||||||
Resource: Resource(sd.Resource()),
|
|
||||||
InstrumentationLibrarySpans: []*tracepb.InstrumentationLibrarySpans{ils},
|
|
||||||
}
|
|
||||||
rsm[rKey] = rs
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// The resource has been seen before. Check if the instrumentation
|
|
||||||
// library lookup was unknown because if so we need to add it to the
|
|
||||||
// ResourceSpans. Otherwise, the instrumentation library has already
|
|
||||||
// been seen and the append we did above will be included it in the
|
|
||||||
// InstrumentationLibrarySpans reference.
|
|
||||||
if !iOk {
|
|
||||||
rs.InstrumentationLibrarySpans = append(rs.InstrumentationLibrarySpans, ils)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform the categorized map into a slice
|
|
||||||
rss := make([]*tracepb.ResourceSpans, 0, resources)
|
|
||||||
for _, rs := range rsm {
|
|
||||||
rss = append(rss, rs)
|
|
||||||
}
|
|
||||||
return rss
|
|
||||||
}
|
|
||||||
|
|
||||||
// span transforms a Span into an OTLP span.
|
|
||||||
func span(sd tracesdk.ReadOnlySpan) *tracepb.Span {
|
|
||||||
if sd == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
tid := sd.SpanContext().TraceID()
|
|
||||||
sid := sd.SpanContext().SpanID()
|
|
||||||
|
|
||||||
s := &tracepb.Span{
|
|
||||||
TraceId: tid[:],
|
|
||||||
SpanId: sid[:],
|
|
||||||
TraceState: sd.SpanContext().TraceState().String(),
|
|
||||||
Status: status(sd.Status().Code, sd.Status().Description),
|
|
||||||
StartTimeUnixNano: uint64(sd.StartTime().UnixNano()),
|
|
||||||
EndTimeUnixNano: uint64(sd.EndTime().UnixNano()),
|
|
||||||
Links: links(sd.Links()),
|
|
||||||
Kind: spanKind(sd.SpanKind()),
|
|
||||||
Name: sd.Name(),
|
|
||||||
Attributes: Attributes(sd.Attributes()),
|
|
||||||
Events: spanEvents(sd.Events()),
|
|
||||||
DroppedAttributesCount: uint32(sd.DroppedAttributes()),
|
|
||||||
DroppedEventsCount: uint32(sd.DroppedEvents()),
|
|
||||||
DroppedLinksCount: uint32(sd.DroppedLinks()),
|
|
||||||
}
|
|
||||||
|
|
||||||
if psid := sd.Parent().SpanID(); psid.IsValid() {
|
|
||||||
s.ParentSpanId = psid[:]
|
|
||||||
}
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// status transform a span code and message into an OTLP span status.
|
|
||||||
func status(status codes.Code, message string) *tracepb.Status {
|
|
||||||
var c tracepb.Status_StatusCode
|
|
||||||
switch status {
|
|
||||||
case codes.Error:
|
|
||||||
c = tracepb.Status_STATUS_CODE_ERROR
|
|
||||||
default:
|
|
||||||
c = tracepb.Status_STATUS_CODE_OK
|
|
||||||
}
|
|
||||||
return &tracepb.Status{
|
|
||||||
Code: c,
|
|
||||||
Message: message,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// links transforms span Links to OTLP span links.
|
|
||||||
func links(links []trace.Link) []*tracepb.Span_Link {
|
|
||||||
if len(links) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
sl := make([]*tracepb.Span_Link, 0, len(links))
|
|
||||||
for _, otLink := range links {
|
|
||||||
// This redefinition is necessary to prevent otLink.*ID[:] copies
|
|
||||||
// being reused -- in short we need a new otLink per iteration.
|
|
||||||
otLink := otLink
|
|
||||||
|
|
||||||
tid := otLink.SpanContext.TraceID()
|
|
||||||
sid := otLink.SpanContext.SpanID()
|
|
||||||
|
|
||||||
sl = append(sl, &tracepb.Span_Link{
|
|
||||||
TraceId: tid[:],
|
|
||||||
SpanId: sid[:],
|
|
||||||
Attributes: Attributes(otLink.Attributes),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return sl
|
|
||||||
}
|
|
||||||
|
|
||||||
// spanEvents transforms span Events to an OTLP span events.
|
|
||||||
func spanEvents(es []tracesdk.Event) []*tracepb.Span_Event {
|
|
||||||
if len(es) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
evCount := len(es)
|
|
||||||
if evCount > maxEventsPerSpan {
|
|
||||||
evCount = maxEventsPerSpan
|
|
||||||
}
|
|
||||||
events := make([]*tracepb.Span_Event, 0, evCount)
|
|
||||||
nEvents := 0
|
|
||||||
|
|
||||||
// Transform message events
|
|
||||||
for _, e := range es {
|
|
||||||
if nEvents >= maxEventsPerSpan {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
nEvents++
|
|
||||||
events = append(events,
|
|
||||||
&tracepb.Span_Event{
|
|
||||||
Name: e.Name,
|
|
||||||
TimeUnixNano: uint64(e.Time.UnixNano()),
|
|
||||||
Attributes: Attributes(e.Attributes),
|
|
||||||
// TODO (rghetia) : Add Drop Counts when supported.
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return events
|
|
||||||
}
|
|
||||||
|
|
||||||
// spanKind transforms a SpanKind to an OTLP span kind.
|
|
||||||
func spanKind(kind trace.SpanKind) tracepb.Span_SpanKind {
|
|
||||||
switch kind {
|
|
||||||
case trace.SpanKindInternal:
|
|
||||||
return tracepb.Span_SPAN_KIND_INTERNAL
|
|
||||||
case trace.SpanKindClient:
|
|
||||||
return tracepb.Span_SPAN_KIND_CLIENT
|
|
||||||
case trace.SpanKindServer:
|
|
||||||
return tracepb.Span_SPAN_KIND_SERVER
|
|
||||||
case trace.SpanKindProducer:
|
|
||||||
return tracepb.Span_SPAN_KIND_PRODUCER
|
|
||||||
case trace.SpanKindConsumer:
|
|
||||||
return tracepb.Span_SPAN_KIND_CONSUMER
|
|
||||||
default:
|
|
||||||
return tracepb.Span_SPAN_KIND_UNSPECIFIED
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue