44 "errors"
55 "fmt"
66 "reflect"
7+ "regexp"
78
89 "github.com/go-kit/log"
910 "github.com/grafana/alloy/internal/runtime/logging/level"
@@ -13,32 +14,33 @@ import (
1314
1415// Config Errors
1516const (
16- ErrExpressionsRequired = "JMES expression is required"
17- ErrCouldNotCompileJMES = "could not compile JMES expression"
18- ErrEmptyJSONStageConfig = "empty json stage configuration"
19- ErrEmptyJSONStageSource = "empty source"
20- ErrMalformedJSON = "malformed json"
17+ ErrExpressionsOrRegexRequired = "JMES expressions or regex is required"
18+ ErrCouldNotCompileJMES = "could not compile JMES expression"
19+ ErrEmptyJSONStageConfig = "empty json stage configuration"
20+ ErrEmptyJSONStageSource = "empty source"
21+ ErrMalformedJSON = "malformed json"
2122)
2223
2324// JSONConfig represents a JSON Stage configuration
2425type JSONConfig struct {
25- Expressions map [string ]string `alloy:"expressions,attr"`
26+ Expressions map [string ]string `alloy:"expressions,attr,optional"`
27+ Regex string `alloy:"regex,attr,optional"`
2628 Source * string `alloy:"source,attr,optional"`
2729 DropMalformed bool `alloy:"drop_malformed,attr,optional"`
2830}
2931
3032// validateJSONConfig validates a json config and returns a map of necessary jmespath expressions.
31- func validateJSONConfig (c * JSONConfig ) (map [string ]jmespath.JMESPath , error ) {
33+ func validateJSONConfig (c * JSONConfig ) (map [string ]jmespath.JMESPath , * regexp. Regexp , error ) {
3234 if c == nil {
33- return nil , errors .New (ErrEmptyJSONStageConfig )
35+ return nil , nil , errors .New (ErrEmptyJSONStageConfig )
3436 }
3537
36- if len (c .Expressions ) == 0 {
37- return nil , errors .New (ErrExpressionsRequired )
38+ if len (c .Expressions ) == 0 && len ( c . Regex ) == 0 {
39+ return nil , nil , errors .New (ErrExpressionsOrRegexRequired )
3840 }
3941
4042 if c .Source != nil && * c .Source == "" {
41- return nil , errors .New (ErrEmptyJSONStageSource )
43+ return nil , nil , errors .New (ErrEmptyJSONStageSource )
4244 }
4345
4446 expressions := map [string ]jmespath.JMESPath {}
@@ -52,28 +54,36 @@ func validateJSONConfig(c *JSONConfig) (map[string]jmespath.JMESPath, error) {
5254 }
5355 expressions [n ], err = jmespath .Compile (jmes )
5456 if err != nil {
55- return nil , fmt .Errorf ("%s: %w" , ErrCouldNotCompileJMES , err )
57+ return nil , nil , fmt .Errorf ("%s: %w" , ErrCouldNotCompileJMES , err )
5658 }
5759 }
58- return expressions , nil
60+
61+ re , err := regexp .Compile (c .Regex )
62+ if err != nil {
63+ return nil , nil , err
64+ }
65+
66+ return expressions , re , nil
5967}
6068
6169// jsonStage sets extracted data using JMESPath expressions
6270type jsonStage struct {
6371 cfg * JSONConfig
6472 expressions map [string ]jmespath.JMESPath
73+ regex regexp.Regexp
6574 logger log.Logger
6675}
6776
6877// newJSONStage creates a new json pipeline stage from a config.
6978func newJSONStage (logger log.Logger , cfg JSONConfig ) (Stage , error ) {
70- expressions , err := validateJSONConfig (& cfg )
79+ expressions , regex , err := validateJSONConfig (& cfg )
7180 if err != nil {
7281 return nil , err
7382 }
7483 return & jsonStage {
7584 cfg : & cfg ,
7685 expressions : expressions ,
86+ regex : * regex ,
7787 logger : log .With (logger , "component" , "stage" , "type" , "json" ),
7888 }, nil
7989}
@@ -164,6 +174,31 @@ func (j *jsonStage) processEntry(extracted map[string]interface{}, entry *string
164174 extracted [n ] = string (jm )
165175 }
166176 }
177+ if j .regex .String () != "" {
178+ for key , value := range data {
179+ if j .regex .MatchString (key ) {
180+ switch value .(type ) {
181+ case float64 :
182+ extracted [key ] = value
183+ case string :
184+ extracted [key ] = value
185+ case bool :
186+ extracted [key ] = value
187+ case nil :
188+ extracted [key ] = nil
189+ default :
190+ jm , err := json .Marshal (value )
191+ if err != nil {
192+ if Debug {
193+ level .Debug (j .logger ).Log ("msg" , "failed to marshal complex type back to string" , "err" , err )
194+ }
195+ continue
196+ }
197+ extracted [key ] = string (jm )
198+ }
199+ }
200+ }
201+ }
167202 if Debug {
168203 level .Debug (j .logger ).Log ("msg" , "extracted data debug in json stage" , "extracted_data" , fmt .Sprintf ("%v" , extracted ))
169204 }
0 commit comments