github.com/Jeffail/benthos/v3@v3.65.0/internal/component/input/span_reader.go (about)

     1  package input
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/Jeffail/benthos/v3/internal/bloblang/mapping"
     8  	"github.com/Jeffail/benthos/v3/internal/docs"
     9  	"github.com/Jeffail/benthos/v3/internal/interop"
    10  	"github.com/Jeffail/benthos/v3/internal/tracing"
    11  	"github.com/Jeffail/benthos/v3/lib/input/reader"
    12  	"github.com/Jeffail/benthos/v3/lib/log"
    13  	"github.com/Jeffail/benthos/v3/lib/types"
    14  )
    15  
    16  // ExtractTracingSpanMappingDocs returns a docs spec for a mapping field.
    17  var ExtractTracingSpanMappingDocs = docs.FieldBloblang(
    18  	"extract_tracing_map", "EXPERIMENTAL: A [Bloblang mapping](/docs/guides/bloblang/about) that attempts to extract an object containing tracing propagation information, which will then be used as the root tracing span for the message. The specification of the extracted fields must match the format used by the service wide tracer.",
    19  	`root = meta()`,
    20  	`root = this.meta.span`,
    21  ).AtVersion("3.45.0").Advanced()
    22  
    23  // SpanReader wraps an async reader with a mechanism for extracting tracing
    24  // spans from the consumed message using a Bloblang mapping.
    25  type SpanReader struct {
    26  	inputName string
    27  
    28  	mgr types.Manager
    29  	log log.Modular
    30  
    31  	mapping *mapping.Executor
    32  	rdr     reader.Async
    33  }
    34  
    35  // NewSpanReader wraps an async reader with a mechanism for extracting tracing
    36  // spans from the consumed message using a Bloblang mapping.
    37  func NewSpanReader(inputName, mapping string, rdr reader.Async, mgr types.Manager, logger log.Modular) (reader.Async, error) {
    38  	exe, err := interop.NewBloblangMapping(mgr, mapping)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	return &SpanReader{inputName, mgr, logger, exe, rdr}, nil
    43  }
    44  
    45  // ConnectWithContext attempts to establish a connection to the source, if
    46  // unsuccessful returns an error. If the attempt is successful (or not
    47  // necessary) returns nil.
    48  func (s *SpanReader) ConnectWithContext(ctx context.Context) error {
    49  	return s.rdr.ConnectWithContext(ctx)
    50  }
    51  
    52  // ReadWithContext attempts to read a new message from the source. If
    53  // successful a message is returned along with a function used to
    54  // acknowledge receipt of the returned message. It's safe to process the
    55  // returned message and read the next message asynchronously.
    56  func (s *SpanReader) ReadWithContext(ctx context.Context) (types.Message, reader.AsyncAckFn, error) {
    57  	m, afn, err := s.rdr.ReadWithContext(ctx)
    58  	if err != nil {
    59  		return nil, nil, err
    60  	}
    61  
    62  	spanPart, err := s.mapping.MapPart(0, m)
    63  	if err != nil {
    64  		s.log.Errorf("Mapping failed for tracing span: %v", err)
    65  		return m, afn, nil
    66  	}
    67  
    68  	structured, err := spanPart.JSON()
    69  	if err != nil {
    70  		s.log.Errorf("Mapping failed for tracing span: %v", err)
    71  		return m, afn, nil
    72  	}
    73  
    74  	spanMap, ok := structured.(map[string]interface{})
    75  	if !ok {
    76  		s.log.Errorf("Mapping failed for tracing span, expected an object, got: %T", structured)
    77  		return m, afn, nil
    78  	}
    79  
    80  	if err := tracing.InitSpansFromParentTextMap("input_"+s.inputName, spanMap, m); err != nil {
    81  		s.log.Errorf("Extraction of parent tracing span failed: %v", err)
    82  	}
    83  	return m, afn, nil
    84  }
    85  
    86  // CloseAsync triggers the shut down of this component but should not block
    87  // the calling goroutine.
    88  func (s *SpanReader) CloseAsync() {
    89  	s.rdr.CloseAsync()
    90  }
    91  
    92  // WaitForClose is a blocking call to wait until the component has finished
    93  // shutting down and cleaning up resources.
    94  func (s *SpanReader) WaitForClose(timeout time.Duration) error {
    95  	return s.rdr.WaitForClose(timeout)
    96  }