Skip to content

Commit

Permalink
Add timer support for statsD receiver (#1335)
Browse files Browse the repository at this point in the history
  • Loading branch information
gavindoudou authored Oct 22, 2020
1 parent 7a23d76 commit c384e2f
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 4 deletions.
5 changes: 3 additions & 2 deletions receiver/statsdreceiver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ General format is:

`<name>:<value>|g|@<sample-rate>|#<tag1-key>:<tag1-value>`

<!-- ### Timer/Histogram
### Timer

`<name>:<value>|ms|@<sample-rate>|#<tag1-key>:<tag1-value>`

`<name>:<value>|<ms/h>|@<sample-rate>|#<tag1-key>:<tag1-value>` -->

## Testing

Expand Down
26 changes: 24 additions & 2 deletions receiver/statsdreceiver/protocol/statsd_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var (
)

func getSupportedTypes() []string {
return []string{"c", "g"}
return []string{"c", "g", "ms"}
}

// StatsDParser supports the Parse method for parsing StatsD messages with Tags.
Expand All @@ -41,6 +41,7 @@ type statsDMetric struct {
name string
value string
statsdMetricType string
unit string
metricType metricspb.MetricDescriptor_Type
sampleRate float64
labelKeys []*metricspb.LabelKey
Expand Down Expand Up @@ -128,7 +129,6 @@ func parseMessageToMetric(line string) (*statsDMetric, error) {
return nil, fmt.Errorf("unrecognized message part: %s", part)
}
}

return result, nil
}

Expand All @@ -147,6 +147,7 @@ func buildMetric(metric *statsDMetric, point *metricspb.Point) *metricspb.Metric
Name: metric.name,
Type: metric.metricType,
LabelKeys: metric.labelKeys,
Unit: metric.unit,
},
Timeseries: []*metricspb.TimeSeries{
{
Expand Down Expand Up @@ -181,6 +182,10 @@ func buildPoint(parsedMetric *statsDMetric) (*metricspb.Point, error) {
}
parsedMetric.metricType = metricspb.MetricDescriptor_GAUGE_INT64
})
case "ms":
return buildTimerPoint(parsedMetric, now, func(parsedMetric *statsDMetric) {
parsedMetric.metricType = metricspb.MetricDescriptor_GAUGE_DOUBLE
})
}

return nil, fmt.Errorf("unhandled metric type: %s", parsedMetric.statsdMetricType)
Expand Down Expand Up @@ -215,3 +220,20 @@ func buildGaugeOrCounterPoint(parsedMetric *statsDMetric, now *timestamppb.Times
metricTypeSetter(parsedMetric, isDouble)
return point, nil
}

func buildTimerPoint(parsedMetric *statsDMetric, now *timestamppb.Timestamp, metricTypeSetter func(parsedMetric *statsDMetric)) (*metricspb.Point, error) {
var point *metricspb.Point
parsedMetric.unit = "ms"
f, err := strconv.ParseFloat(parsedMetric.value, 64)
if err != nil {
return nil, fmt.Errorf("timer: failed to parse metric value to float: %s", parsedMetric.value)
}
point = &metricspb.Point{
Timestamp: now,
Value: &metricspb.Point_DoubleValue{
DoubleValue: f,
},
}
metricTypeSetter(parsedMetric)
return point, nil
}
55 changes: 55 additions & 0 deletions receiver/statsdreceiver/protocol/statsd_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func Test_StatsDParser_Parse(t *testing.T) {
metricspb.MetricDescriptor_CUMULATIVE_INT64,
nil,
nil,
"",
&metricspb.Point{
Timestamp: &timestamppb.Timestamp{
Seconds: 0,
Expand All @@ -83,6 +84,7 @@ func Test_StatsDParser_Parse(t *testing.T) {
metricspb.MetricDescriptor_CUMULATIVE_DOUBLE,
nil,
nil,
"",
&metricspb.Point{
Timestamp: &timestamppb.Timestamp{
Seconds: 0,
Expand Down Expand Up @@ -118,6 +120,7 @@ func Test_StatsDParser_Parse(t *testing.T) {
HasValue: true,
},
},
"",
&metricspb.Point{
Timestamp: &timestamppb.Timestamp{
Seconds: 0,
Expand All @@ -143,6 +146,7 @@ func Test_StatsDParser_Parse(t *testing.T) {
HasValue: true,
},
},
"",
&metricspb.Point{
Timestamp: &timestamppb.Timestamp{
Seconds: 0,
Expand All @@ -168,6 +172,7 @@ func Test_StatsDParser_Parse(t *testing.T) {
HasValue: true,
},
},
"",
&metricspb.Point{
Timestamp: &timestamppb.Timestamp{
Seconds: 0,
Expand All @@ -177,6 +182,54 @@ func Test_StatsDParser_Parse(t *testing.T) {
},
}),
},
{
name: "timer metric with sample rate",
input: "test.timer:42.3|ms|@0.1",
wantMetric: testMetric("test.timer",
metricspb.MetricDescriptor_GAUGE_DOUBLE,
nil,
nil,
"ms",
&metricspb.Point{
Timestamp: &timestamppb.Timestamp{
Seconds: 0,
},
Value: &metricspb.Point_DoubleValue{
DoubleValue: 42.3,
},
}),
},
{
name: "timer metric with sample rate and tag",
input: "test.timer:42|ms|@0.1|#key:value",
wantMetric: testMetric("test.timer",
metricspb.MetricDescriptor_GAUGE_DOUBLE,
[]*metricspb.LabelKey{
{
Key: "key",
},
},
[]*metricspb.LabelValue{
{
Value: "value",
HasValue: true,
},
},
"ms",
&metricspb.Point{
Timestamp: &timestamppb.Timestamp{
Seconds: 0,
},
Value: &metricspb.Point_DoubleValue{
DoubleValue: 42,
},
}),
},
{
name: "timer: invalid metric value",
input: "test.metric:invalidValue|ms",
err: errors.New("timer: failed to parse metric value to float: invalidValue"),
},
{
name: "invalid sample rate value",
input: "test.metric:42|c|@1.0a",
Expand Down Expand Up @@ -214,12 +267,14 @@ func testMetric(metricName string,
metricType metricspb.MetricDescriptor_Type,
lableKeys []*metricspb.LabelKey,
labelValues []*metricspb.LabelValue,
unit string,
point *metricspb.Point) *metricspb.Metric {
return &metricspb.Metric{
MetricDescriptor: &metricspb.MetricDescriptor{
Name: metricName,
Type: metricType,
LabelKeys: lableKeys,
Unit: unit,
},
Timeseries: []*metricspb.TimeSeries{
{
Expand Down

0 comments on commit c384e2f

Please sign in to comment.