github.com/Jeffail/benthos/v3@v3.65.0/internal/component/metrics/mapping.go (about) 1 package metrics 2 3 import ( 4 "fmt" 5 "sort" 6 7 "github.com/Jeffail/benthos/v3/internal/bloblang/mapping" 8 "github.com/Jeffail/benthos/v3/internal/bloblang/parser" 9 "github.com/Jeffail/benthos/v3/internal/bloblang/query" 10 "github.com/Jeffail/benthos/v3/internal/docs" 11 "github.com/Jeffail/benthos/v3/internal/interop" 12 "github.com/Jeffail/benthos/v3/lib/log" 13 "github.com/Jeffail/benthos/v3/lib/message" 14 "github.com/Jeffail/benthos/v3/lib/types" 15 ) 16 17 // MappingFieldSpec is a field spec that describes a Bloblang mapping for 18 // renaming metrics. 19 func MappingFieldSpec() docs.FieldSpec { 20 examples := []interface{}{ 21 `this.replace(".foo.count", ".count")`, 22 `if ![ "count", "error", "latency" ].contains(this) { deleted() }`, 23 } 24 summary := "An optional [Bloblang mapping](/docs/guides/bloblang/about) that allows you to rename or prevent certain metrics paths from being exported." 25 return docs.FieldBloblang("metrics_mapping", summary, examples...).HasDefault("") 26 } 27 28 // Mapping is a compiled Bloblang mapping used to rewrite metrics. 29 type Mapping struct { 30 m *mapping.Executor 31 logger log.Modular 32 } 33 34 // NewMapping parses a Bloblang mapping and returns a metrics mapping. 35 func NewMapping(mgr types.Manager, mapping string, logger log.Modular) (*Mapping, error) { 36 if mapping == "" { 37 return &Mapping{m: nil, logger: logger}, nil 38 } 39 m, err := interop.NewBloblangMapping(mgr, mapping) 40 if err != nil { 41 if perr, ok := err.(*parser.Error); ok { 42 return nil, fmt.Errorf("%v", perr.ErrorAtPosition([]rune(mapping))) 43 } 44 return nil, err 45 } 46 return &Mapping{m, logger}, nil 47 } 48 49 func (m *Mapping) mapPath(path string, labelNames, labelValues []string) (outPath string, outLabelNames, outLabelValues []string) { 50 if m == nil || m.m == nil { 51 return path, labelNames, labelValues 52 } 53 54 part := message.NewPart(nil) 55 if err := part.SetJSON(path); err != nil { 56 m.logger.Errorf("Failed to apply path mapping on '%v': %v\n", path, err) 57 return path, labelNames, labelValues 58 } 59 for i, v := range labelNames { 60 part.Metadata().Set(v, labelValues[i]) 61 } 62 msg := message.New(nil) 63 msg.Append(part) 64 65 outPart := part.Copy() 66 outMeta := outPart.Metadata() 67 68 var input interface{} = path 69 vars := map[string]interface{}{} 70 71 var v interface{} = query.Nothing(nil) 72 if err := m.m.ExecOnto(query.FunctionContext{ 73 Maps: m.m.Maps(), 74 Vars: vars, 75 MsgBatch: msg, 76 NewMsg: outPart, 77 }.WithValue(input), mapping.AssignmentContext{ 78 Vars: vars, 79 Meta: outMeta, 80 Value: &v, 81 }); err != nil { 82 m.logger.Errorf("Failed to apply path mapping on '%v': %v\n", path, err) 83 return path, nil, nil 84 } 85 86 outMeta.Iter(func(k, v string) error { 87 outLabelNames = append(outLabelNames, k) 88 return nil 89 }) 90 if len(outLabelNames) > 0 { 91 sort.Strings(outLabelNames) 92 for _, k := range outLabelNames { 93 v := outMeta.Get(k) 94 m.logger.Tracef("Metrics label '%v' created with static value '%v'.\n", k, v) 95 outLabelValues = append(outLabelValues, v) 96 } 97 } 98 99 switch t := v.(type) { 100 case query.Delete: 101 m.logger.Tracef("Deleting metrics path: %v\n", path) 102 return "", nil, nil 103 case query.Nothing: 104 m.logger.Tracef("Metrics path '%v' registered unchanged.\n", path) 105 outPath = path 106 return 107 case string: 108 m.logger.Tracef("Updated metrics path '%v' to: %v\n", path, t) 109 outPath = t 110 return 111 } 112 m.logger.Errorf("Path mapping returned invalid result, expected string, found %T\n", v) 113 return path, labelNames, labelValues 114 }