1// Copyright (c) 2017 Uber Technologies, Inc. 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 15package jaeger 16 17import ( 18 "time" 19 20 "github.com/opentracing/opentracing-go" 21 22 j "github.com/uber/jaeger-client-go/thrift-gen/jaeger" 23 "github.com/uber/jaeger-client-go/utils" 24) 25 26// BuildJaegerThrift builds jaeger span based on internal span. 27func BuildJaegerThrift(span *Span) *j.Span { 28 span.Lock() 29 defer span.Unlock() 30 startTime := utils.TimeToMicrosecondsSinceEpochInt64(span.startTime) 31 duration := span.duration.Nanoseconds() / int64(time.Microsecond) 32 jaegerSpan := &j.Span{ 33 TraceIdLow: int64(span.context.traceID.Low), 34 TraceIdHigh: int64(span.context.traceID.High), 35 SpanId: int64(span.context.spanID), 36 ParentSpanId: int64(span.context.parentID), 37 OperationName: span.operationName, 38 Flags: int32(span.context.samplingState.flags()), 39 StartTime: startTime, 40 Duration: duration, 41 Tags: buildTags(span.tags, span.tracer.options.maxTagValueLength), 42 Logs: buildLogs(span.logs), 43 References: buildReferences(span.references), 44 } 45 return jaegerSpan 46} 47 48// BuildJaegerProcessThrift creates a thrift Process type. 49func BuildJaegerProcessThrift(span *Span) *j.Process { 50 span.Lock() 51 defer span.Unlock() 52 return buildJaegerProcessThrift(span.tracer) 53} 54 55func buildJaegerProcessThrift(tracer *Tracer) *j.Process { 56 process := &j.Process{ 57 ServiceName: tracer.serviceName, 58 Tags: buildTags(tracer.tags, tracer.options.maxTagValueLength), 59 } 60 if tracer.process.UUID != "" { 61 process.Tags = append(process.Tags, &j.Tag{Key: TracerUUIDTagKey, VStr: &tracer.process.UUID, VType: j.TagType_STRING}) 62 } 63 return process 64} 65 66func buildTags(tags []Tag, maxTagValueLength int) []*j.Tag { 67 jTags := make([]*j.Tag, 0, len(tags)) 68 for _, tag := range tags { 69 jTag := buildTag(&tag, maxTagValueLength) 70 jTags = append(jTags, jTag) 71 } 72 return jTags 73} 74 75func buildLogs(logs []opentracing.LogRecord) []*j.Log { 76 jLogs := make([]*j.Log, 0, len(logs)) 77 for _, log := range logs { 78 jLog := &j.Log{ 79 Timestamp: utils.TimeToMicrosecondsSinceEpochInt64(log.Timestamp), 80 Fields: ConvertLogsToJaegerTags(log.Fields), 81 } 82 jLogs = append(jLogs, jLog) 83 } 84 return jLogs 85} 86 87func buildTag(tag *Tag, maxTagValueLength int) *j.Tag { 88 jTag := &j.Tag{Key: tag.key} 89 switch value := tag.value.(type) { 90 case string: 91 vStr := truncateString(value, maxTagValueLength) 92 jTag.VStr = &vStr 93 jTag.VType = j.TagType_STRING 94 case []byte: 95 if len(value) > maxTagValueLength { 96 value = value[:maxTagValueLength] 97 } 98 jTag.VBinary = value 99 jTag.VType = j.TagType_BINARY 100 case int: 101 vLong := int64(value) 102 jTag.VLong = &vLong 103 jTag.VType = j.TagType_LONG 104 case uint: 105 vLong := int64(value) 106 jTag.VLong = &vLong 107 jTag.VType = j.TagType_LONG 108 case int8: 109 vLong := int64(value) 110 jTag.VLong = &vLong 111 jTag.VType = j.TagType_LONG 112 case uint8: 113 vLong := int64(value) 114 jTag.VLong = &vLong 115 jTag.VType = j.TagType_LONG 116 case int16: 117 vLong := int64(value) 118 jTag.VLong = &vLong 119 jTag.VType = j.TagType_LONG 120 case uint16: 121 vLong := int64(value) 122 jTag.VLong = &vLong 123 jTag.VType = j.TagType_LONG 124 case int32: 125 vLong := int64(value) 126 jTag.VLong = &vLong 127 jTag.VType = j.TagType_LONG 128 case uint32: 129 vLong := int64(value) 130 jTag.VLong = &vLong 131 jTag.VType = j.TagType_LONG 132 case int64: 133 vLong := int64(value) 134 jTag.VLong = &vLong 135 jTag.VType = j.TagType_LONG 136 case uint64: 137 vLong := int64(value) 138 jTag.VLong = &vLong 139 jTag.VType = j.TagType_LONG 140 case float32: 141 vDouble := float64(value) 142 jTag.VDouble = &vDouble 143 jTag.VType = j.TagType_DOUBLE 144 case float64: 145 vDouble := float64(value) 146 jTag.VDouble = &vDouble 147 jTag.VType = j.TagType_DOUBLE 148 case bool: 149 vBool := value 150 jTag.VBool = &vBool 151 jTag.VType = j.TagType_BOOL 152 default: 153 vStr := truncateString(stringify(value), maxTagValueLength) 154 jTag.VStr = &vStr 155 jTag.VType = j.TagType_STRING 156 } 157 return jTag 158} 159 160func buildReferences(references []Reference) []*j.SpanRef { 161 retMe := make([]*j.SpanRef, 0, len(references)) 162 for _, ref := range references { 163 if ref.Type == opentracing.ChildOfRef { 164 retMe = append(retMe, spanRef(ref.Context, j.SpanRefType_CHILD_OF)) 165 } else if ref.Type == opentracing.FollowsFromRef { 166 retMe = append(retMe, spanRef(ref.Context, j.SpanRefType_FOLLOWS_FROM)) 167 } 168 } 169 return retMe 170} 171 172func spanRef(ctx SpanContext, refType j.SpanRefType) *j.SpanRef { 173 return &j.SpanRef{ 174 RefType: refType, 175 TraceIdLow: int64(ctx.traceID.Low), 176 TraceIdHigh: int64(ctx.traceID.High), 177 SpanId: int64(ctx.spanID), 178 } 179} 180