github.com/Jeffail/benthos/v3@v3.65.0/lib/processor/metadata.go (about)

     1  package processor
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"github.com/Jeffail/benthos/v3/internal/bloblang/field"
     9  	"github.com/Jeffail/benthos/v3/internal/docs"
    10  	"github.com/Jeffail/benthos/v3/internal/interop"
    11  	"github.com/Jeffail/benthos/v3/internal/tracing"
    12  	"github.com/Jeffail/benthos/v3/lib/log"
    13  	"github.com/Jeffail/benthos/v3/lib/metrics"
    14  	"github.com/Jeffail/benthos/v3/lib/types"
    15  )
    16  
    17  //------------------------------------------------------------------------------
    18  
    19  func init() {
    20  	Constructors[TypeMetadata] = TypeSpec{
    21  		constructor: NewMetadata,
    22  		Status:      docs.StatusDeprecated,
    23  		Footnotes: `
    24  ## Alternatives
    25  
    26  All functionality of this processor has been superseded by the
    27  [bloblang](/docs/components/processors/bloblang) processor.`,
    28  		FieldSpecs: docs.FieldSpecs{
    29  			docs.FieldCommon("operator", "The operator to apply to messages.").HasOptions("set", "delete", "delete_all", "delete_prefix"),
    30  			docs.FieldCommon("key", "The metadata key to target with the chosen operator.").IsInterpolated(),
    31  			docs.FieldCommon("value", "The metadata value to use with the chosen operator.").IsInterpolated(),
    32  			PartsFieldSpec,
    33  		},
    34  	}
    35  }
    36  
    37  //------------------------------------------------------------------------------
    38  
    39  // MetadataConfig contains configuration fields for the Metadata processor.
    40  type MetadataConfig struct {
    41  	Parts    []int  `json:"parts" yaml:"parts"`
    42  	Operator string `json:"operator" yaml:"operator"`
    43  	Key      string `json:"key" yaml:"key"`
    44  	Value    string `json:"value" yaml:"value"`
    45  }
    46  
    47  // NewMetadataConfig returns a MetadataConfig with default values.
    48  func NewMetadataConfig() MetadataConfig {
    49  	return MetadataConfig{
    50  		Parts:    []int{},
    51  		Operator: "set",
    52  		Key:      "example",
    53  		Value:    `${!hostname()}`,
    54  	}
    55  }
    56  
    57  //------------------------------------------------------------------------------
    58  
    59  type metadataOperator func(m types.Metadata, key, value string) error
    60  
    61  func newMetadataSetOperator() metadataOperator {
    62  	return func(m types.Metadata, key, value string) error {
    63  		m.Set(key, value)
    64  		return nil
    65  	}
    66  }
    67  
    68  func newMetadataDeleteAllOperator() metadataOperator {
    69  	return func(m types.Metadata, key, value string) error {
    70  		m.Iter(func(k, _ string) error {
    71  			m.Delete(k)
    72  			return nil
    73  		})
    74  		return nil
    75  	}
    76  }
    77  
    78  func newMetadataDeleteOperator() metadataOperator {
    79  	return func(m types.Metadata, key, value string) error {
    80  		target := value
    81  		if target == "" && len(key) > 0 {
    82  			target = key
    83  		}
    84  		m.Delete(target)
    85  		return nil
    86  	}
    87  }
    88  
    89  func newMetadataDeletePrefixOperator() metadataOperator {
    90  	return func(m types.Metadata, key, value string) error {
    91  		prefix := value
    92  		if prefix == "" && len(key) > 0 {
    93  			prefix = key
    94  		}
    95  		m.Iter(func(k, _ string) error {
    96  			if strings.HasPrefix(k, prefix) {
    97  				m.Delete(k)
    98  			}
    99  			return nil
   100  		})
   101  		return nil
   102  	}
   103  }
   104  
   105  func getMetadataOperator(opStr string) (metadataOperator, error) {
   106  	switch opStr {
   107  	case "set":
   108  		return newMetadataSetOperator(), nil
   109  	case "delete":
   110  		return newMetadataDeleteOperator(), nil
   111  	case "delete_all":
   112  		return newMetadataDeleteAllOperator(), nil
   113  	case "delete_prefix":
   114  		return newMetadataDeletePrefixOperator(), nil
   115  	}
   116  	return nil, fmt.Errorf("operator not recognised: %v", opStr)
   117  }
   118  
   119  //------------------------------------------------------------------------------
   120  
   121  // Metadata is a processor that performs an operation on the Metadata of a
   122  // message.
   123  type Metadata struct {
   124  	value *field.Expression
   125  	key   *field.Expression
   126  
   127  	operator metadataOperator
   128  
   129  	parts []int
   130  
   131  	conf  Config
   132  	log   log.Modular
   133  	stats metrics.Type
   134  
   135  	mCount     metrics.StatCounter
   136  	mErr       metrics.StatCounter
   137  	mSent      metrics.StatCounter
   138  	mBatchSent metrics.StatCounter
   139  }
   140  
   141  // NewMetadata returns a Metadata processor.
   142  func NewMetadata(
   143  	conf Config, mgr types.Manager, log log.Modular, stats metrics.Type,
   144  ) (Type, error) {
   145  	value, err := interop.NewBloblangField(mgr, conf.Metadata.Value)
   146  	if err != nil {
   147  		return nil, fmt.Errorf("failed to parse value expression: %v", err)
   148  	}
   149  	key, err := interop.NewBloblangField(mgr, conf.Metadata.Key)
   150  	if err != nil {
   151  		return nil, fmt.Errorf("failed to parse key expression: %v", err)
   152  	}
   153  	m := &Metadata{
   154  		conf:  conf,
   155  		log:   log,
   156  		stats: stats,
   157  
   158  		parts: conf.Metadata.Parts,
   159  
   160  		value: value,
   161  		key:   key,
   162  
   163  		mCount:     stats.GetCounter("count"),
   164  		mErr:       stats.GetCounter("error"),
   165  		mSent:      stats.GetCounter("sent"),
   166  		mBatchSent: stats.GetCounter("batch.sent"),
   167  	}
   168  
   169  	if m.operator, err = getMetadataOperator(conf.Metadata.Operator); err != nil {
   170  		return nil, err
   171  	}
   172  	return m, nil
   173  }
   174  
   175  //------------------------------------------------------------------------------
   176  
   177  // ProcessMessage applies the processor to a message, either creating >0
   178  // resulting messages or a response to be sent back to the message source.
   179  func (p *Metadata) ProcessMessage(msg types.Message) ([]types.Message, types.Response) {
   180  	p.mCount.Incr(1)
   181  	newMsg := msg.Copy()
   182  
   183  	proc := func(index int, span *tracing.Span, part types.Part) error {
   184  		key := p.key.StringLegacy(index, msg)
   185  		value := p.value.StringLegacy(index, msg)
   186  
   187  		if err := p.operator(part.Metadata(), key, value); err != nil {
   188  			p.mErr.Incr(1)
   189  			p.log.Debugf("Failed to apply operator: %v\n", err)
   190  			return err
   191  		}
   192  		return nil
   193  	}
   194  
   195  	IteratePartsWithSpanV2(TypeMetadata, p.parts, newMsg, proc)
   196  
   197  	msgs := [1]types.Message{newMsg}
   198  
   199  	p.mBatchSent.Incr(1)
   200  	p.mSent.Incr(int64(newMsg.Len()))
   201  	return msgs[:], nil
   202  }
   203  
   204  // CloseAsync shuts down the processor and stops processing requests.
   205  func (p *Metadata) CloseAsync() {
   206  }
   207  
   208  // WaitForClose blocks until the processor has closed down.
   209  func (p *Metadata) WaitForClose(timeout time.Duration) error {
   210  	return nil
   211  }
   212  
   213  //------------------------------------------------------------------------------