Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / contrib.go.opencensus.io / exporter / ocagent / transform_spans.go
1 // Copyright 2018, OpenCensus 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 ocagent
16
17 import (
18         "math"
19         "time"
20
21         "go.opencensus.io/trace"
22         "go.opencensus.io/trace/tracestate"
23
24         tracepb "github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1"
25         "github.com/golang/protobuf/ptypes/timestamp"
26 )
27
28 const (
29         maxAnnotationEventsPerSpan = 32
30         maxMessageEventsPerSpan    = 128
31 )
32
33 func ocSpanToProtoSpan(sd *trace.SpanData) *tracepb.Span {
34         if sd == nil {
35                 return nil
36         }
37         var namePtr *tracepb.TruncatableString
38         if sd.Name != "" {
39                 namePtr = &tracepb.TruncatableString{Value: sd.Name}
40         }
41         return &tracepb.Span{
42                 TraceId:      sd.TraceID[:],
43                 SpanId:       sd.SpanID[:],
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),
50                 Name:         namePtr,
51                 Attributes:   ocAttributesToProtoAttributes(sd.Attributes),
52                 TimeEvents:   ocTimeEventsToProtoTimeEvents(sd.Annotations, sd.MessageEvents),
53                 Tracestate:   ocTracestateToProtoTracestate(sd.Tracestate),
54         }
55 }
56
57 var blankStatus trace.Status
58
59 func ocStatusToProtoStatus(status trace.Status) *tracepb.Status {
60         if status == blankStatus {
61                 return nil
62         }
63         return &tracepb.Status{
64                 Code:    status.Code,
65                 Message: status.Message,
66         }
67 }
68
69 func ocLinksToProtoLinks(links []trace.Link) *tracepb.Span_Links {
70         if len(links) == 0 {
71                 return nil
72         }
73
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.
78                 ocLink := ocLink
79
80                 sl = append(sl, &tracepb.Span_Link{
81                         TraceId: ocLink.TraceID[:],
82                         SpanId:  ocLink.SpanID[:],
83                         Type:    ocLinkTypeToProtoLinkType(ocLink.Type),
84                 })
85         }
86
87         return &tracepb.Span_Links{
88                 Link: sl,
89         }
90 }
91
92 func ocLinkTypeToProtoLinkType(oct trace.LinkType) tracepb.Span_Link_Type {
93         switch oct {
94         case trace.LinkTypeChild:
95                 return tracepb.Span_Link_CHILD_LINKED_SPAN
96         case trace.LinkTypeParent:
97                 return tracepb.Span_Link_PARENT_LINKED_SPAN
98         default:
99                 return tracepb.Span_Link_TYPE_UNSPECIFIED
100         }
101 }
102
103 func ocAttributesToProtoAttributes(attrs map[string]interface{}) *tracepb.Span_Attributes {
104         if len(attrs) == 0 {
105                 return nil
106         }
107         outMap := make(map[string]*tracepb.AttributeValue)
108         for k, v := range attrs {
109                 switch v := v.(type) {
110                 case bool:
111                         outMap[k] = &tracepb.AttributeValue{Value: &tracepb.AttributeValue_BoolValue{BoolValue: v}}
112
113                 case int:
114                         outMap[k] = &tracepb.AttributeValue{Value: &tracepb.AttributeValue_IntValue{IntValue: int64(v)}}
115
116                 case int64:
117                         outMap[k] = &tracepb.AttributeValue{Value: &tracepb.AttributeValue_IntValue{IntValue: v}}
118
119                 case string:
120                         outMap[k] = &tracepb.AttributeValue{
121                                 Value: &tracepb.AttributeValue_StringValue{
122                                         StringValue: &tracepb.TruncatableString{Value: v},
123                                 },
124                         }
125                 }
126         }
127         return &tracepb.Span_Attributes{
128                 AttributeMap: outMap,
129         }
130 }
131
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 {
136                 return nil
137         }
138
139         timeEvents := &tracepb.Span_TimeEvents{}
140         var annotations, droppedAnnotationsCount int
141         var messageEvents, droppedMessageEventsCount int
142
143         // Transform annotations
144         for i, a := range as {
145                 if annotations >= maxAnnotationEventsPerSpan {
146                         droppedAnnotationsCount = len(as) - i
147                         break
148                 }
149                 annotations++
150                 timeEvents.TimeEvent = append(timeEvents.TimeEvent,
151                         &tracepb.Span_TimeEvent{
152                                 Time:  timeToTimestamp(a.Time),
153                                 Value: transformAnnotationToTimeEvent(&a),
154                         },
155                 )
156         }
157
158         // Transform message events
159         for i, e := range es {
160                 if messageEvents >= maxMessageEventsPerSpan {
161                         droppedMessageEventsCount = len(es) - i
162                         break
163                 }
164                 messageEvents++
165                 timeEvents.TimeEvent = append(timeEvents.TimeEvent,
166                         &tracepb.Span_TimeEvent{
167                                 Time:  timeToTimestamp(e.Time),
168                                 Value: transformMessageEventToTimeEvent(&e),
169                         },
170                 )
171         }
172
173         // Process dropped counter
174         timeEvents.DroppedAnnotationsCount = clip32(droppedAnnotationsCount)
175         timeEvents.DroppedMessageEventsCount = clip32(droppedMessageEventsCount)
176
177         return timeEvents
178 }
179
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),
185                 },
186         }
187 }
188
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),
196                 },
197         }
198 }
199
200 // clip32 clips an int to the range of an int32.
201 func clip32(x int) int32 {
202         if x < math.MinInt32 {
203                 return math.MinInt32
204         }
205         if x > math.MaxInt32 {
206                 return math.MaxInt32
207         }
208         return int32(x)
209 }
210
211 func timeToTimestamp(t time.Time) *timestamp.Timestamp {
212         nanoTime := t.UnixNano()
213         return &timestamp.Timestamp{
214                 Seconds: nanoTime / 1e9,
215                 Nanos:   int32(nanoTime % 1e9),
216         }
217 }
218
219 func ocSpanKindToProtoSpanKind(kind int) tracepb.Span_SpanKind {
220         switch kind {
221         case trace.SpanKindClient:
222                 return tracepb.Span_CLIENT
223         case trace.SpanKindServer:
224                 return tracepb.Span_SERVER
225         default:
226                 return tracepb.Span_SPAN_KIND_UNSPECIFIED
227         }
228 }
229
230 func ocTracestateToProtoTracestate(ts *tracestate.Tracestate) *tracepb.Span_Tracestate {
231         if ts == nil {
232                 return nil
233         }
234         return &tracepb.Span_Tracestate{
235                 Entries: ocTracestateEntriesToProtoTracestateEntries(ts.Entries()),
236         }
237 }
238
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{
243                         Key:   entry.Key,
244                         Value: entry.Value,
245                 })
246         }
247         return protoEntries
248 }