-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parser processor #4551
Merged
Merged
Parser processor #4551
Changes from 14 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
c823023
Add fieldparser processor
danielnelson 683130a
Rename fieldparser to parser
ad54725
Add test for parsing one filed and multiple fields
f1373e6
Add test to parse one tag and to parse multiple tags
bc11ecc
WIP: Add test for parsing one and two tags
62c35f0
Remove duplicate files
60c0eb7
Fix test for parsing one and two tags
38733c1
Remove tests that handle parsing tags
c736252
Remove Parse Tag functionality
d805fc7
Add test that when a field fails to parse still parses other values
a0e2002
Fix test for parsing one and two fields
27c27b9
Rename fieldparser to parser
46173ee
Reformat
c04bc6a
WIP: README added
2a5da32
Add original measurement merge|replace|keep functionality
glinton 4b0c00b
Add printer back to processors/all
glinton 0938090
Update config in readme
glinton 74a1eab
Fix tests and bad field parsing
glinton 9e15fc6
Make config single level
glinton a0f1472
Update changelog
danielnelson 83a969b
Split original option into drop_original and merge options
danielnelson d5aec65
Merge branch 'master' into fieldparser
danielnelson 8ce4e98
Fixup merge issue with master CHANGELOG
danielnelson 52b3b23
Use code block for output example
danielnelson File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Parser Processor Plugin | ||
This plugin parses through fields in a pre-formatted string | ||
|
||
## Configuration | ||
```var SampleConfig = ` | ||
|
||
[processors.parser] | ||
## specify the name of the field[s] whose value will be parsed | ||
parse_fields = [] | ||
|
||
data_format = "logfmt" | ||
## additional configurations for parser go here | ||
` | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package parser | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
|
||
"github.com/influxdata/telegraf" | ||
"github.com/influxdata/telegraf/plugins/parsers" | ||
"github.com/influxdata/telegraf/plugins/processors" | ||
) | ||
|
||
type Parser struct { | ||
config parsers.Config | ||
parseFields []string `toml:"parse_fields"` | ||
Parser parsers.Parser | ||
} | ||
|
||
// holds a default sample config | ||
var SampleConfig = ` | ||
|
||
## specify the name of the field[s] whose value will be parsed | ||
parse_fields = [] | ||
|
||
[processors.parser.config] | ||
data_format = "logfmt" | ||
## additional configurations for parser go here | ||
` | ||
|
||
// returns the default config | ||
func (p *Parser) SampleConfig() string { | ||
return SampleConfig | ||
} | ||
|
||
// returns a brief description of the processor | ||
func (p *Parser) Description() string { | ||
return "Parse a value in a specified field/tag(s) and add the result in a new metric" | ||
} | ||
|
||
func (p *Parser) Apply(metrics ...telegraf.Metric) []telegraf.Metric { | ||
if p.Parser == nil { | ||
var err error | ||
p.Parser, err = parsers.NewParser(&p.config) | ||
if err != nil { | ||
log.Printf("E! [processors.parser] could not create parser: %v", err) | ||
return metrics | ||
} | ||
} | ||
|
||
for _, metric := range metrics { | ||
for _, key := range p.parseFields { | ||
value := metric.Fields()[key] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might not matter, but we could probably do |
||
strVal := fmt.Sprintf("%v", value) | ||
nMetrics, err := p.parseField(strVal) | ||
if err != nil { | ||
log.Printf("E! [processors.parser] could not parse field %v: %v", key, err) | ||
return metrics | ||
} | ||
metrics = append(metrics, nMetrics...) | ||
} | ||
} | ||
return metrics | ||
|
||
} | ||
|
||
func (p *Parser) parseField(value string) ([]telegraf.Metric, error) { | ||
return p.Parser.Parse([]byte(value)) | ||
} | ||
|
||
func init() { | ||
processors.Add("parser", func() telegraf.Processor { | ||
return &Parser{} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
package parser | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
"time" | ||
|
||
"github.com/influxdata/telegraf" | ||
"github.com/influxdata/telegraf/metric" | ||
"github.com/influxdata/telegraf/plugins/parsers" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
//compares metrics without comparing time | ||
func compareMetrics(t *testing.T, metrics1 []telegraf.Metric, metrics2 []telegraf.Metric) { | ||
for i, m1 := range metrics1 { | ||
m2 := metrics2[i] | ||
require.True(t, reflect.DeepEqual(m1.Tags(), m2.Tags())) | ||
require.True(t, reflect.DeepEqual(m1.Fields(), m2.Fields())) | ||
//require.True(t, m1.Name() == m2.Name()) | ||
} | ||
} | ||
|
||
func Metric(v telegraf.Metric, err error) telegraf.Metric { | ||
if err != nil { | ||
panic(err) | ||
} | ||
return v | ||
} | ||
|
||
func TestApply(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
parseFields []string | ||
config parsers.Config | ||
input telegraf.Metric | ||
expected []telegraf.Metric | ||
}{ | ||
{ | ||
name: "parse one field", | ||
parseFields: []string{"test_name"}, | ||
config: parsers.Config{ | ||
DataFormat: "logfmt", | ||
}, | ||
input: Metric( | ||
metric.New( | ||
"success", | ||
map[string]string{}, | ||
map[string]interface{}{ | ||
"test_name": `ts=2018-07-24T19:43:40.275Z lvl=info msg="http request" method=POST`, | ||
}, | ||
time.Unix(0, 0))), | ||
expected: []telegraf.Metric{ | ||
Metric(metric.New( | ||
"success", | ||
map[string]string{}, | ||
map[string]interface{}{ | ||
"test_name": `ts=2018-07-24T19:43:40.275Z lvl=info msg="http request" method=POST`, | ||
}, | ||
time.Unix(0, 0))), | ||
Metric(metric.New( | ||
"success", | ||
map[string]string{}, | ||
map[string]interface{}{ | ||
"ts": "2018-07-24T19:43:40.275Z", | ||
"lvl": "info", | ||
"msg": "http request", | ||
"method": "post", | ||
}, | ||
time.Unix(0, 0))), | ||
}, | ||
}, | ||
{ | ||
name: "parse two fields", | ||
parseFields: []string{"field_1", "field_2"}, | ||
config: parsers.Config{ | ||
DataFormat: "logfmt", | ||
}, | ||
input: Metric( | ||
metric.New( | ||
"success", | ||
map[string]string{}, | ||
map[string]interface{}{ | ||
"field_1": "ts=2018-07-24T19:43:40.275Z", | ||
"field_2": "lvl=info", | ||
}, | ||
time.Unix(0, 0))), | ||
expected: []telegraf.Metric{ | ||
Metric(metric.New( | ||
"success", | ||
map[string]string{}, | ||
map[string]interface{}{ | ||
"field_1": "ts=2018-07-24T19:43:40.275Z", | ||
"field_2": "lvl=info", | ||
}, | ||
time.Unix(0, 0))), | ||
Metric(metric.New( | ||
"success", | ||
map[string]string{}, | ||
map[string]interface{}{ | ||
"ts": "2018-07-24T19:43:40.275Z", | ||
"lvl": "info", | ||
}, | ||
time.Unix(0, 0))), | ||
}, | ||
}, | ||
{ | ||
name: "Fail to parse one field but parses other", | ||
parseFields: []string{"good", "bad"}, | ||
config: parsers.Config{ | ||
DataFormat: "logfmt", | ||
}, | ||
input: Metric( | ||
metric.New( | ||
"success", | ||
map[string]string{}, | ||
map[string]interface{}{ | ||
"good": "lvl=info", | ||
"bad": "why", | ||
}, | ||
time.Unix(0, 0))), | ||
expected: []telegraf.Metric{ | ||
Metric(metric.New( | ||
"success", | ||
map[string]string{}, | ||
map[string]interface{}{ | ||
"good": "lvl=info", | ||
"bad": "why", | ||
}, | ||
time.Unix(0, 0))), | ||
Metric(metric.New( | ||
"success", | ||
map[string]string{}, | ||
map[string]interface{}{ | ||
"lvl": "info", | ||
}, | ||
time.Unix(0, 0))), | ||
}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
parser := Parser{ | ||
config: tt.config, | ||
parseFields: tt.parseFields, | ||
} | ||
|
||
output := parser.Apply(tt.input) | ||
|
||
compareMetrics(t, output, tt.expected) | ||
} | ||
} | ||
|
||
func TestBadApply(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
parseFields []string | ||
config parsers.Config | ||
input telegraf.Metric | ||
expected []telegraf.Metric | ||
}{ | ||
{ | ||
name: "field not found", | ||
parseFields: []string{"bad_field"}, | ||
config: parsers.Config{ | ||
DataFormat: "logfmt", | ||
}, | ||
input: Metric( | ||
metric.New( | ||
"bad", | ||
map[string]string{}, | ||
map[string]interface{}{ | ||
"some_field": 5, | ||
}, | ||
time.Unix(0, 0))), | ||
expected: []telegraf.Metric{ | ||
Metric(metric.New( | ||
"bad", | ||
map[string]string{}, | ||
map[string]interface{}{ | ||
"some_field": 5, | ||
}, | ||
time.Unix(0, 0))), | ||
}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
parser := Parser{ | ||
config: tt.config, | ||
parseFields: tt.parseFields, | ||
} | ||
|
||
output := parser.Apply(tt.input) | ||
|
||
compareMetrics(t, output, tt.expected) | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double space the sample config and remove the empty line on line 20.