Skip to content

Commit

Permalink
Export LabelsFromName func from CollectD receiver (open-telemetry#117)
Browse files Browse the repository at this point in the history
* Export LabelsFromName func from CollectD receiver

Exporting this function since it can be useful in other cases that parse
text metrics that embedded collectd tags.

* Gofmt modified file
  • Loading branch information
Paulo Janotti committed Feb 7, 2020
1 parent 1705096 commit a26c337
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 11 deletions.
25 changes: 14 additions & 11 deletions receiver/collectdreceiver/collectd.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func (r *collectDRecord) pointTypeInstance(attrs map[string]string, parts []byte
return parts
}

instanceName, extractedAttrs := labelsFromName(r.TypeInstance)
instanceName, extractedAttrs := LabelsFromName(r.TypeInstance)
if instanceName != "" {
if len(parts) > 0 {
parts = append(parts, '.')
Expand All @@ -210,13 +210,16 @@ func (r *collectDRecord) pointTypeInstance(attrs map[string]string, parts []byte
return parts
}

// labelsFromName tries to pull out dimensions out of name in the format name[k=v,f=x]-morename
// would return name-morename and extract dimensions (k,v) and (f,x)
// if we encounter something we don't expect use original name.
// This is a bit complicated to avoid allocations, string.split allocates, while slices
// inside same function, do not.
func labelsFromName(val *string) (instanceName string, toAddDims map[string]string) {
instanceName = *val
// LabelsFromName tries to pull out dimensions out of name in the format
// "name[k=v,f=x]-more_name".
// For the example above it would return "name-more_name" and extract dimensions
// (k,v) and (f,x).
// If something unexpected is encountered it returns the original metric name.
//
// The code tries to avoid allocation by using local slices and avoiding calls
// to functions like strings.Slice.
func LabelsFromName(val *string) (metricName string, labels map[string]string) {
metricName = *val
index := strings.Index(*val, "[")
if index > -1 {
left := (*val)[:index]
Expand Down Expand Up @@ -244,8 +247,8 @@ func labelsFromName(val *string) (instanceName string, toAddDims map[string]stri
prev = cindex + 1
cindex = strings.Index(dimensions[prev:], ",") + prev
}
toAddDims = working
instanceName = left + rest
labels = working
metricName = left + rest
}
}
return
Expand All @@ -267,7 +270,7 @@ func parseAndAddLabels(labels map[string]string, pluginInstance *string, host *s
}

func parseNameForLabels(labels map[string]string, key string, val *string) {
instanceName, toAddDims := labelsFromName(val)
instanceName, toAddDims := LabelsFromName(val)

for k, v := range toAddDims {
if _, exists := labels[k]; !exists {
Expand Down
49 changes: 49 additions & 0 deletions receiver/collectdreceiver/collectd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,52 @@ var wantMetricsData = []*metricspb.Metric{
},
},
}

func TestLabelsFromName(t *testing.T) {
tests := []struct {
name string
wantMetricName string
wantLabels map[string]string
}{
{
name: "simple",
wantMetricName: "simple",
},
{
name: "single[k=v]",
wantMetricName: "single",
wantLabels: map[string]string{
"k": "v",
},
},
{
name: "a.b.c.[k=v].d",
wantMetricName: "a.b.c..d",
wantLabels: map[string]string{
"k": "v",
},
},
{
name: "a.b[k0=v0,k1=v1,k2=v2].c",
wantMetricName: "a.b.c",
wantLabels: map[string]string{
"k0": "v0", "k1": "v1", "k2": "v2",
},
},
{
name: "empty[]",
wantMetricName: "empty[]",
},
{
name: "mal.formed[k_no_sep]",
wantMetricName: "mal.formed[k_no_sep]",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotMetricName, gotLabels := LabelsFromName(&tt.name)
assert.Equal(t, tt.wantMetricName, gotMetricName)
assert.Equal(t, tt.wantLabels, gotLabels)
})
}
}

0 comments on commit a26c337

Please sign in to comment.