Skip to content

Commit

Permalink
Add option to use strict sanitization rules to wavefront output (#5664)
Browse files Browse the repository at this point in the history
  • Loading branch information
puckpuck authored and danielnelson committed Apr 2, 2019
1 parent fb01b8b commit ff81811
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 0 deletions.
4 changes: 4 additions & 0 deletions plugins/outputs/wavefront/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ This plugin writes to a [Wavefront](https://www.wavefront.com) proxy, in Wavefro
## When true will convert all _ (underscore) characters in final metric name. default is true
#convert_paths = true

## Use Strict rules to sanitize metric and tag names from invalid characters
## When enabled forward slash (/) and comma (,) will be accpeted
#use_strict = false

## Use Regex to sanitize metric and tag names from invalid characters
## Regex is more thorough, but significantly slower. default is false
#use_regex = false
Expand Down
17 changes: 17 additions & 0 deletions plugins/outputs/wavefront/wavefront.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Wavefront struct {
ConvertPaths bool
ConvertBool bool
UseRegex bool
UseStrict bool
SourceOverride []string
StringToNumber map[string][]map[string]float64

Expand All @@ -37,6 +38,14 @@ var sanitizedChars = strings.NewReplacer(
"=", "-",
)

// catch many of the invalid chars that could appear in a metric or tag name
var strictSanitizedChars = strings.NewReplacer(
"!", "-", "@", "-", "#", "-", "$", "-", "%", "-", "^", "-", "&", "-",
"*", "-", "(", "-", ")", "-", "+", "-", "`", "-", "'", "-", "\"", "-",
"[", "-", "]", "-", "{", "-", "}", "-", ":", "-", ";", "-", "<", "-",
">", "-", "?", "-", "\\", "-", "|", "-", " ", "-", "=", "-",
)

// instead of Replacer which may miss some special characters we can use a regex pattern, but this is significantly slower than Replacer
var sanitizedRegex = regexp.MustCompile("[^a-zA-Z\\d_.-]")

Expand Down Expand Up @@ -71,6 +80,10 @@ var sampleConfig = `
## When true will convert all _ (underscore) characters in final metric name. default is true
#convert_paths = true
## Use Strict rules to sanitize metric and tag names from invalid characters
## When enabled forward slash (/) and comma (,) will be accpeted
#use_strict = false
## Use Regex to sanitize metric and tag names from invalid characters
## Regex is more thorough, but significantly slower. default is false
#use_regex = false
Expand Down Expand Up @@ -163,6 +176,8 @@ func buildMetrics(m telegraf.Metric, w *Wavefront) []*MetricPoint {

if w.UseRegex {
name = sanitizedRegex.ReplaceAllLiteralString(name, "-")
} else if w.UseStrict {
name = strictSanitizedChars.Replace(name)
} else {
name = sanitizedChars.Replace(name)
}
Expand Down Expand Up @@ -238,6 +253,8 @@ func buildTags(mTags map[string]string, w *Wavefront) (string, map[string]string
var key string
if w.UseRegex {
key = sanitizedRegex.ReplaceAllLiteralString(k, "-")
} else if w.UseStrict {
key = strictSanitizedChars.Replace(k)
} else {
key = sanitizedChars.Replace(k)
}
Expand Down
47 changes: 47 additions & 0 deletions plugins/outputs/wavefront/wavefront_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ func TestBuildMetrics(t *testing.T) {
{Metric: w.Prefix + "testing.metric2", Value: 1, Timestamp: timestamp, Tags: map[string]string{"tag1": "value1"}},
},
},
{
testutil.TestMetric(float64(1), "testing_just/another,metric:float", "metric2"),
[]MetricPoint{
{Metric: w.Prefix + "testing.just-another-metric-float", Value: 1, Timestamp: timestamp, Tags: map[string]string{"tag1": "value1"}},
{Metric: w.Prefix + "testing.metric2", Value: 1, Timestamp: timestamp, Tags: map[string]string{"tag1": "value1"}},
},
},
{
testMetric1,
[]MetricPoint{{Metric: w.Prefix + "test.simple.metric", Value: 123, Timestamp: timestamp, Source: "testHost", Tags: map[string]string{"tag1": "value1"}}},
Expand All @@ -67,6 +74,46 @@ func TestBuildMetrics(t *testing.T) {

}

func TestBuildMetricsStrict(t *testing.T) {
w := defaultWavefront()
w.Prefix = "testthis."
w.UseStrict = true

pathReplacer = strings.NewReplacer("_", w.MetricSeparator)

var timestamp int64 = 1257894000

var metricTests = []struct {
metric telegraf.Metric
metricPoints []MetricPoint
}{
{
testutil.TestMetric(float64(1), "testing_just*a%metric:float", "metric2"),
[]MetricPoint{
{Metric: w.Prefix + "testing.just-a-metric-float", Value: 1, Timestamp: timestamp, Tags: map[string]string{"tag1": "value1"}},
{Metric: w.Prefix + "testing.metric2", Value: 1, Timestamp: timestamp, Tags: map[string]string{"tag1": "value1"}},
},
},
{
testutil.TestMetric(float64(1), "testing_just/another,metric:float", "metric2"),
[]MetricPoint{
{Metric: w.Prefix + "testing.just/another,metric-float", Value: 1, Timestamp: timestamp, Tags: map[string]string{"tag/1": "value1", "tag,2": "value2"}},
{Metric: w.Prefix + "testing.metric2", Value: 1, Timestamp: timestamp, Tags: map[string]string{"tag/1": "value1", "tag,2": "value2"}},
},
},
}

for _, mt := range metricTests {
ml := buildMetrics(mt.metric, w)
for i, line := range ml {
if mt.metricPoints[i].Metric != line.Metric || mt.metricPoints[i].Value != line.Value {
t.Errorf("\nexpected\t%+v %+v\nreceived\t%+v %+v\n", mt.metricPoints[i].Metric, mt.metricPoints[i].Value, line.Metric, line.Value)
}
}
}

}

func TestBuildMetricsWithSimpleFields(t *testing.T) {
w := defaultWavefront()
w.Prefix = "testthis."
Expand Down

0 comments on commit ff81811

Please sign in to comment.