github.com/Jeffail/benthos/v3@v3.65.0/internal/tracing/opentracing.go (about) 1 package tracing 2 3 import ( 4 "github.com/Jeffail/benthos/v3/lib/message" 5 "github.com/Jeffail/benthos/v3/lib/types" 6 "github.com/opentracing/opentracing-go" 7 ) 8 9 // GetSpan returns a span attached to a message part. Returns nil if the part 10 // doesn't have a span attached. 11 func GetSpan(p types.Part) *Span { 12 return openTracingSpan(opentracing.SpanFromContext(message.GetContext(p))) 13 } 14 15 // CreateChildSpan takes a message part, extracts an existing span if there is 16 // one and returns child span. 17 func CreateChildSpan(operationName string, part types.Part) *Span { 18 span := GetSpan(part) 19 if span == nil { 20 span = openTracingSpan(opentracing.StartSpan(operationName)) 21 } else { 22 span = openTracingSpan(opentracing.StartSpan( 23 operationName, 24 opentracing.ChildOf(span.unwrap().Context()), 25 )) 26 } 27 return span 28 } 29 30 // CreateChildSpans takes a message, extracts spans per message part and returns 31 // a slice of child spans. The length of the returned slice is guaranteed to 32 // match the message size. 33 func CreateChildSpans(operationName string, msg types.Message) []*Span { 34 spans := make([]*Span, msg.Len()) 35 msg.Iter(func(i int, part types.Part) error { 36 spans[i] = CreateChildSpan(operationName, part) 37 return nil 38 }) 39 return spans 40 } 41 42 // PartsWithChildSpans takes a slice of message parts, extracts spans per part, 43 // creates new child spans, and returns a new slice of parts with those spans 44 // embedded. The original parts are unchanged. 45 func PartsWithChildSpans(operationName string, parts []types.Part) ([]types.Part, []*Span) { 46 spans := make([]*Span, 0, len(parts)) 47 newParts := make([]types.Part, len(parts)) 48 for i, part := range parts { 49 if part == nil { 50 continue 51 } 52 53 ctx := message.GetContext(part) 54 otSpan := opentracing.SpanFromContext(ctx) 55 if otSpan == nil { 56 otSpan = opentracing.StartSpan(operationName) 57 } else { 58 otSpan = opentracing.StartSpan( 59 operationName, 60 opentracing.ChildOf(otSpan.Context()), 61 ) 62 } 63 ctx = opentracing.ContextWithSpan(ctx, otSpan) 64 65 newParts[i] = message.WithContext(ctx, part) 66 spans = append(spans, openTracingSpan(otSpan)) 67 } 68 return newParts, spans 69 } 70 71 // WithChildSpans takes a message, extracts spans per message part, creates new 72 // child spans, and returns a new message with those spans embedded. The 73 // original message is unchanged. 74 func WithChildSpans(operationName string, msg types.Message) (types.Message, []*Span) { 75 parts := make([]types.Part, 0, msg.Len()) 76 msg.Iter(func(i int, p types.Part) error { 77 parts = append(parts, p) 78 return nil 79 }) 80 81 newParts, spans := PartsWithChildSpans(operationName, parts) 82 newMsg := message.New(nil) 83 newMsg.SetAll(newParts) 84 85 return newMsg, spans 86 } 87 88 // WithSiblingSpans takes a message, extracts spans per message part, creates 89 // new sibling spans, and returns a new message with those spans embedded. The 90 // original message is unchanged. 91 func WithSiblingSpans(operationName string, msg types.Message) types.Message { 92 parts := make([]types.Part, msg.Len()) 93 msg.Iter(func(i int, part types.Part) error { 94 ctx := message.GetContext(part) 95 otSpan := opentracing.SpanFromContext(ctx) 96 if otSpan == nil { 97 otSpan = opentracing.StartSpan(operationName) 98 } else { 99 otSpan = opentracing.StartSpan( 100 operationName, 101 opentracing.FollowsFrom(otSpan.Context()), 102 ) 103 } 104 ctx = opentracing.ContextWithSpan(ctx, otSpan) 105 parts[i] = message.WithContext(ctx, part) 106 return nil 107 }) 108 109 newMsg := message.New(nil) 110 newMsg.SetAll(parts) 111 return newMsg 112 } 113 114 //------------------------------------------------------------------------------ 115 116 // IterateWithChildSpans iterates all the parts of a message and, for each part, 117 // creates a new span from an existing span attached to the part and calls a 118 // func with that span before finishing the child span. 119 func IterateWithChildSpans(operationName string, msg types.Message, iter func(int, *Span, types.Part) error) error { 120 return msg.Iter(func(i int, p types.Part) error { 121 otSpan, _ := opentracing.StartSpanFromContext(message.GetContext(p), operationName) 122 err := iter(i, openTracingSpan(otSpan), p) 123 otSpan.Finish() 124 return err 125 }) 126 } 127 128 // InitSpans sets up OpenTracing spans on each message part if one does not 129 // already exist. 130 func InitSpans(operationName string, msg types.Message) { 131 tracedParts := make([]types.Part, msg.Len()) 132 msg.Iter(func(i int, p types.Part) error { 133 tracedParts[i] = InitSpan(operationName, p) 134 return nil 135 }) 136 msg.SetAll(tracedParts) 137 } 138 139 // InitSpan sets up an OpenTracing span on a message part if one does not 140 // already exist. 141 func InitSpan(operationName string, part types.Part) types.Part { 142 if GetSpan(part) != nil { 143 return part 144 } 145 otSpan := opentracing.StartSpan(operationName) 146 ctx := opentracing.ContextWithSpan(message.GetContext(part), otSpan) 147 return message.WithContext(ctx, part) 148 } 149 150 // InitSpansFromParent sets up OpenTracing spans as children of a parent span on 151 // each message part if one does not already exist. 152 func InitSpansFromParent(operationName string, parent *Span, msg types.Message) { 153 tracedParts := make([]types.Part, msg.Len()) 154 msg.Iter(func(i int, p types.Part) error { 155 tracedParts[i] = InitSpanFromParent(operationName, parent, p) 156 return nil 157 }) 158 msg.SetAll(tracedParts) 159 } 160 161 // InitSpanFromParent sets up an OpenTracing span as children of a parent 162 // span on a message part if one does not already exist. 163 func InitSpanFromParent(operationName string, parent *Span, part types.Part) types.Part { 164 if GetSpan(part) != nil { 165 return part 166 } 167 span := opentracing.StartSpan(operationName, opentracing.ChildOf(parent.unwrap().Context())) 168 ctx := opentracing.ContextWithSpan(message.GetContext(part), span) 169 return message.WithContext(ctx, part) 170 } 171 172 // InitSpansFromParentTextMap obtains a span parent reference from a text map 173 // and creates child spans for each message. 174 func InitSpansFromParentTextMap(operationName string, textMapGeneric map[string]interface{}, msg types.Message) error { 175 textMap := make(opentracing.TextMapCarrier, len(textMapGeneric)) 176 for k, v := range textMapGeneric { 177 if vStr, ok := v.(string); ok { 178 textMap[k] = vStr 179 } 180 } 181 182 parentCtx, err := opentracing.GlobalTracer().Extract(opentracing.TextMap, textMap) 183 if err != nil { 184 return err 185 } 186 187 tracedParts := make([]types.Part, msg.Len()) 188 msg.Iter(func(i int, p types.Part) error { 189 otSpan := opentracing.StartSpan( 190 operationName, 191 opentracing.ChildOf(parentCtx), 192 ) 193 ctx := opentracing.ContextWithSpan(message.GetContext(p), otSpan) 194 tracedParts[i] = message.WithContext(ctx, p) 195 return nil 196 }) 197 198 msg.SetAll(tracedParts) 199 return nil 200 } 201 202 // FinishSpans calls Finish on all message parts containing a span. 203 func FinishSpans(msg types.Message) { 204 msg.Iter(func(i int, p types.Part) error { 205 span := GetSpan(p) 206 if span == nil { 207 return nil 208 } 209 span.unwrap().Finish() 210 return nil 211 }) 212 }