1 // Copyright 2018, OpenCensus Authors
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
21 "go.opencensus.io/trace"
22 "go.opencensus.io/trace/tracestate"
24 tracepb "github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1"
25 "github.com/golang/protobuf/ptypes/timestamp"
29 maxAnnotationEventsPerSpan = 32
30 maxMessageEventsPerSpan = 128
33 func ocSpanToProtoSpan(sd *trace.SpanData) *tracepb.Span {
37 var namePtr *tracepb.TruncatableString
39 namePtr = &tracepb.TruncatableString{Value: sd.Name}
42 TraceId: sd.TraceID[:],
44 ParentSpanId: sd.ParentSpanID[:],
45 Status: ocStatusToProtoStatus(sd.Status),
46 StartTime: timeToTimestamp(sd.StartTime),
47 EndTime: timeToTimestamp(sd.EndTime),
48 Links: ocLinksToProtoLinks(sd.Links),
49 Kind: ocSpanKindToProtoSpanKind(sd.SpanKind),
51 Attributes: ocAttributesToProtoAttributes(sd.Attributes),
52 TimeEvents: ocTimeEventsToProtoTimeEvents(sd.Annotations, sd.MessageEvents),
53 Tracestate: ocTracestateToProtoTracestate(sd.Tracestate),
57 var blankStatus trace.Status
59 func ocStatusToProtoStatus(status trace.Status) *tracepb.Status {
60 if status == blankStatus {
63 return &tracepb.Status{
65 Message: status.Message,
69 func ocLinksToProtoLinks(links []trace.Link) *tracepb.Span_Links {
74 sl := make([]*tracepb.Span_Link, 0, len(links))
75 for _, ocLink := range links {
76 // This redefinition is necessary to prevent ocLink.*ID[:] copies
77 // being reused -- in short we need a new ocLink per iteration.
80 sl = append(sl, &tracepb.Span_Link{
81 TraceId: ocLink.TraceID[:],
82 SpanId: ocLink.SpanID[:],
83 Type: ocLinkTypeToProtoLinkType(ocLink.Type),
87 return &tracepb.Span_Links{
92 func ocLinkTypeToProtoLinkType(oct trace.LinkType) tracepb.Span_Link_Type {
94 case trace.LinkTypeChild:
95 return tracepb.Span_Link_CHILD_LINKED_SPAN
96 case trace.LinkTypeParent:
97 return tracepb.Span_Link_PARENT_LINKED_SPAN
99 return tracepb.Span_Link_TYPE_UNSPECIFIED
103 func ocAttributesToProtoAttributes(attrs map[string]interface{}) *tracepb.Span_Attributes {
107 outMap := make(map[string]*tracepb.AttributeValue)
108 for k, v := range attrs {
109 switch v := v.(type) {
111 outMap[k] = &tracepb.AttributeValue{Value: &tracepb.AttributeValue_BoolValue{BoolValue: v}}
114 outMap[k] = &tracepb.AttributeValue{Value: &tracepb.AttributeValue_IntValue{IntValue: int64(v)}}
117 outMap[k] = &tracepb.AttributeValue{Value: &tracepb.AttributeValue_IntValue{IntValue: v}}
120 outMap[k] = &tracepb.AttributeValue{
121 Value: &tracepb.AttributeValue_StringValue{
122 StringValue: &tracepb.TruncatableString{Value: v},
127 return &tracepb.Span_Attributes{
128 AttributeMap: outMap,
132 // This code is mostly copied from
133 // https://github.com/census-ecosystem/opencensus-go-exporter-stackdriver/blob/master/trace_proto.go#L46
134 func ocTimeEventsToProtoTimeEvents(as []trace.Annotation, es []trace.MessageEvent) *tracepb.Span_TimeEvents {
135 if len(as) == 0 && len(es) == 0 {
139 timeEvents := &tracepb.Span_TimeEvents{}
140 var annotations, droppedAnnotationsCount int
141 var messageEvents, droppedMessageEventsCount int
143 // Transform annotations
144 for i, a := range as {
145 if annotations >= maxAnnotationEventsPerSpan {
146 droppedAnnotationsCount = len(as) - i
150 timeEvents.TimeEvent = append(timeEvents.TimeEvent,
151 &tracepb.Span_TimeEvent{
152 Time: timeToTimestamp(a.Time),
153 Value: transformAnnotationToTimeEvent(&a),
158 // Transform message events
159 for i, e := range es {
160 if messageEvents >= maxMessageEventsPerSpan {
161 droppedMessageEventsCount = len(es) - i
165 timeEvents.TimeEvent = append(timeEvents.TimeEvent,
166 &tracepb.Span_TimeEvent{
167 Time: timeToTimestamp(e.Time),
168 Value: transformMessageEventToTimeEvent(&e),
173 // Process dropped counter
174 timeEvents.DroppedAnnotationsCount = clip32(droppedAnnotationsCount)
175 timeEvents.DroppedMessageEventsCount = clip32(droppedMessageEventsCount)
180 func transformAnnotationToTimeEvent(a *trace.Annotation) *tracepb.Span_TimeEvent_Annotation_ {
181 return &tracepb.Span_TimeEvent_Annotation_{
182 Annotation: &tracepb.Span_TimeEvent_Annotation{
183 Description: &tracepb.TruncatableString{Value: a.Message},
184 Attributes: ocAttributesToProtoAttributes(a.Attributes),
189 func transformMessageEventToTimeEvent(e *trace.MessageEvent) *tracepb.Span_TimeEvent_MessageEvent_ {
190 return &tracepb.Span_TimeEvent_MessageEvent_{
191 MessageEvent: &tracepb.Span_TimeEvent_MessageEvent{
192 Type: tracepb.Span_TimeEvent_MessageEvent_Type(e.EventType),
193 Id: uint64(e.MessageID),
194 UncompressedSize: uint64(e.UncompressedByteSize),
195 CompressedSize: uint64(e.CompressedByteSize),
200 // clip32 clips an int to the range of an int32.
201 func clip32(x int) int32 {
202 if x < math.MinInt32 {
205 if x > math.MaxInt32 {
211 func timeToTimestamp(t time.Time) *timestamp.Timestamp {
212 nanoTime := t.UnixNano()
213 return ×tamp.Timestamp{
214 Seconds: nanoTime / 1e9,
215 Nanos: int32(nanoTime % 1e9),
219 func ocSpanKindToProtoSpanKind(kind int) tracepb.Span_SpanKind {
221 case trace.SpanKindClient:
222 return tracepb.Span_CLIENT
223 case trace.SpanKindServer:
224 return tracepb.Span_SERVER
226 return tracepb.Span_SPAN_KIND_UNSPECIFIED
230 func ocTracestateToProtoTracestate(ts *tracestate.Tracestate) *tracepb.Span_Tracestate {
234 return &tracepb.Span_Tracestate{
235 Entries: ocTracestateEntriesToProtoTracestateEntries(ts.Entries()),
239 func ocTracestateEntriesToProtoTracestateEntries(entries []tracestate.Entry) []*tracepb.Span_Tracestate_Entry {
240 protoEntries := make([]*tracepb.Span_Tracestate_Entry, 0, len(entries))
241 for _, entry := range entries {
242 protoEntries = append(protoEntries, &tracepb.Span_Tracestate_Entry{