github.com/Jeffail/benthos/v3@v3.65.0/lib/processor/select_parts.go (about) 1 package processor 2 3 import ( 4 "time" 5 6 "github.com/Jeffail/benthos/v3/internal/docs" 7 "github.com/Jeffail/benthos/v3/lib/log" 8 "github.com/Jeffail/benthos/v3/lib/message" 9 "github.com/Jeffail/benthos/v3/lib/metrics" 10 "github.com/Jeffail/benthos/v3/lib/response" 11 "github.com/Jeffail/benthos/v3/lib/types" 12 ) 13 14 //------------------------------------------------------------------------------ 15 16 func init() { 17 Constructors[TypeSelectParts] = TypeSpec{ 18 constructor: NewSelectParts, 19 Categories: []Category{ 20 CategoryUtility, 21 }, 22 Summary: ` 23 Cherry pick a set of messages from a batch by their index. Indexes larger than 24 the number of messages are simply ignored.`, 25 Description: ` 26 The selected parts are added to the new message batch in the same order as the 27 selection array. E.g. with 'parts' set to [ 2, 0, 1 ] and the message parts 28 [ '0', '1', '2', '3' ], the output will be [ '2', '0', '1' ]. 29 30 If none of the selected parts exist in the input batch (resulting in an empty 31 output message) the batch is dropped entirely. 32 33 Message indexes can be negative, and if so the part will be selected from the 34 end counting backwards starting from -1. E.g. if index = -1 then the selected 35 part will be the last part of the message, if index = -2 then the part before 36 the last element with be selected, and so on.`, 37 UsesBatches: true, 38 FieldSpecs: docs.FieldSpecs{ 39 PartsFieldSpec, 40 }, 41 } 42 } 43 44 //------------------------------------------------------------------------------ 45 46 // SelectPartsConfig contains configuration fields for the SelectParts 47 // processor. 48 type SelectPartsConfig struct { 49 Parts []int `json:"parts" yaml:"parts"` 50 } 51 52 // NewSelectPartsConfig returns a SelectPartsConfig with default values. 53 func NewSelectPartsConfig() SelectPartsConfig { 54 return SelectPartsConfig{ 55 Parts: []int{0}, 56 } 57 } 58 59 //------------------------------------------------------------------------------ 60 61 // SelectParts is a processor that selects parts from a message to append to a 62 // new message. 63 type SelectParts struct { 64 conf Config 65 log log.Modular 66 stats metrics.Type 67 68 mCount metrics.StatCounter 69 mSkipped metrics.StatCounter 70 mSelected metrics.StatCounter 71 mDropped metrics.StatCounter 72 mSent metrics.StatCounter 73 mBatchSent metrics.StatCounter 74 } 75 76 // NewSelectParts returns a SelectParts processor. 77 func NewSelectParts( 78 conf Config, mgr types.Manager, log log.Modular, stats metrics.Type, 79 ) (Type, error) { 80 return &SelectParts{ 81 conf: conf, 82 log: log, 83 stats: stats, 84 85 mCount: stats.GetCounter("count"), 86 mSkipped: stats.GetCounter("skipped"), 87 mSelected: stats.GetCounter("selected"), 88 mDropped: stats.GetCounter("dropped"), 89 mSent: stats.GetCounter("sent"), 90 mBatchSent: stats.GetCounter("batch.sent"), 91 }, nil 92 } 93 94 //------------------------------------------------------------------------------ 95 96 // ProcessMessage applies the processor to a message, either creating >0 97 // resulting messages or a response to be sent back to the message source. 98 func (m *SelectParts) ProcessMessage(msg types.Message) ([]types.Message, types.Response) { 99 m.mCount.Incr(1) 100 101 newMsg := message.New(nil) 102 103 lParts := msg.Len() 104 for _, index := range m.conf.SelectParts.Parts { 105 if index < 0 { 106 // Negative indexes count backwards from the end. 107 index = lParts + index 108 } 109 110 // Check boundary of part index. 111 if index < 0 || index >= lParts { 112 m.mSkipped.Incr(1) 113 } else { 114 m.mSelected.Incr(1) 115 newMsg.Append(msg.Get(index).Copy()) 116 } 117 } 118 119 if newMsg.Len() == 0 { 120 m.mDropped.Incr(1) 121 return nil, response.NewAck() 122 } 123 124 m.mBatchSent.Incr(1) 125 m.mSent.Incr(int64(newMsg.Len())) 126 msgs := [1]types.Message{newMsg} 127 return msgs[:], nil 128 } 129 130 // CloseAsync shuts down the processor and stops processing requests. 131 func (m *SelectParts) CloseAsync() { 132 } 133 134 // WaitForClose blocks until the processor has closed down. 135 func (m *SelectParts) WaitForClose(timeout time.Duration) error { 136 return nil 137 } 138 139 //------------------------------------------------------------------------------