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  }