Skip to content

Commit

Permalink
Add option to specify case of label values added based on regexp subm…
Browse files Browse the repository at this point in the history
…atches when performing combine action (#1640)
  • Loading branch information
james-bebbington committed Nov 19, 2020
1 parent 911f6fa commit b44e9e4
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 11 deletions.
9 changes: 6 additions & 3 deletions processor/metricstransformprocessor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ transforms:
new_name: <new_metric_name_inserted>
# aggregation_type defines how combined data points will be aggregated; if action is combine, aggregation_type is required
aggregation_type: {sum, mean, min, max}
# submatch_case specifies the case that should be used when adding label values based on regexp submatches when performing a combine action; leave blank to use the submatch value as is
submatch_case: {lower, upper}
# operations contain a list of operations that will be performed on the selected metrics
operations:
# action defines the type of operation that will be performed, see examples below for more details
Expand Down Expand Up @@ -219,13 +221,14 @@ operations:
```yaml
# convert a set of metrics for each http_method into a single metric with an http_method label, i.e.
#
# Web Service (*)/Total DELETE Requests iis.requests{http_method=DELETE}
# Web Service (*)/Total GET Requests > iis.requests{http_method=GET}
# Web Service (*)/Total POST Requests iis.requests{http_method=POST}
# Web Service (*)/Total Delete Requests iis.requests{http_method=delete}
# Web Service (*)/Total Get Requests > iis.requests{http_method=get}
# Web Service (*)/Total Post Requests iis.requests{http_method=post}
metric_names: ^Web Service \(\*\)/Total (?P<http_method>.*) Requests$
match_type: regexp
action: combine
new_name: iis.requests
submatch_case: lower
operations:
...
```
31 changes: 30 additions & 1 deletion processor/metricstransformprocessor/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ const (

// NewValueFieldName is the mapstructure field name for NewValue field
NewValueFieldName = "new_value"

// SubmatchCaseFieldName is the mapstructure field name for SubmatchCase field
SubmatchCaseFieldName = "submatch_case"
)

// Config defines configuration for Resource processor.
Expand Down Expand Up @@ -77,6 +80,9 @@ type Transform struct {
// REQUIRED only if Action is COMBINE.
AggregationType AggregationType `mapstructure:"aggregation_type"`

// SubmatchCase specifies what case to use for label values created from regexp submatches.
SubmatchCase SubmatchCase `mapstructure:"submatch_case"`

// Operations contains a list of operations that will be performed on the selected metric.
Operations []Operation `mapstructure:"operations"`
}
Expand Down Expand Up @@ -129,7 +135,7 @@ type ValueAction struct {
NewValue string `mapstructure:"new_value"`
}

// ConfigAction is the enum to capture the two types of actions to perform on a metric.
// ConfigAction is the enum to capture the type of action to perform on a metric.
type ConfigAction string

const (
Expand Down Expand Up @@ -243,3 +249,26 @@ func (mt MatchType) isValid() bool {

return false
}

// SubmatchCase is the enum to capture the two types of case changes to apply to submatches.
type SubmatchCase string

const (
// Lower is the SubmatchCase for lower casing the submatch.
Lower SubmatchCase = "lower"

// Upper is the SubmatchCase for upper casing the submatch.
Upper SubmatchCase = "upper"
)

var SubmatchCases = []SubmatchCase{Lower, Upper}

func (sc SubmatchCase) isValid() bool {
for _, submatchCase := range SubmatchCases {
if sc == submatchCase {
return true
}
}

return false
}
5 changes: 3 additions & 2 deletions processor/metricstransformprocessor/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,9 @@ func TestLoadingFullConfig(t *testing.T) {
Include: "^regexp (?P<my_label>.*)$",
MatchType: "regexp",
},
Action: "combine",
NewName: "combined_metric_name",
Action: "combine",
NewName: "combined_metric_name",
SubmatchCase: "lower",
},
},
},
Expand Down
4 changes: 4 additions & 0 deletions processor/metricstransformprocessor/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ func validateConfiguration(config *Config) error {
return fmt.Errorf("%q must be in %q", AggregationTypeFieldName, AggregationTypes)
}

if transform.SubmatchCase != "" && !transform.SubmatchCase.isValid() {
return fmt.Errorf("%q must be in %q", SubmatchCaseFieldName, SubmatchCases)
}

for i, op := range transform.Operations {
if !op.Action.isValid() {
return fmt.Errorf("operation %v: %q must be in %q", i+1, ActionFieldName, OperationActions)
Expand Down
5 changes: 5 additions & 0 deletions processor/metricstransformprocessor/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ func TestCreateProcessors(t *testing.T) {
succeed: false,
errorMessage: fmt.Sprintf("operation %v: %q must be in %q", 1, AggregationTypeFieldName, AggregationTypes),
},
{
configName: "config_invalid_submatchcase.yaml",
succeed: false,
errorMessage: fmt.Sprintf("%q must be in %q", SubmatchCaseFieldName, SubmatchCases),
},
}

for _, test := range tests {
Expand Down
14 changes: 14 additions & 0 deletions processor/metricstransformprocessor/metrics_transform_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"fmt"
"regexp"
"strconv"
"strings"

metricspb "github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1"
"go.opentelemetry.io/collector/consumer/consumerdata"
Expand All @@ -42,6 +43,7 @@ type internalTransform struct {
Action ConfigAction
NewName string
AggregationType AggregationType
SubmatchCase SubmatchCase
Operations []internalOperation
}

Expand Down Expand Up @@ -245,6 +247,7 @@ func (mtp *metricsTransformProcessor) combine(matchedMetrics []*match, transform
// append label values based on regex submatches
for i := 1; i < len(match.submatches)/2; i++ {
submatch := match.metric.MetricDescriptor.Name[match.submatches[2*i]:match.submatches[2*i+1]]
submatch = replaceCaseOfSubmatch(transform.SubmatchCase, submatch)
ts.LabelValues = append(ts.LabelValues, &metricspb.LabelValue{Value: submatch, HasValue: (submatch != "")})
}

Expand All @@ -261,6 +264,17 @@ func (mtp *metricsTransformProcessor) combine(matchedMetrics []*match, transform
return combinedMetric
}

func replaceCaseOfSubmatch(replacement SubmatchCase, submatch string) string {
switch replacement {
case Lower:
return strings.ToLower(submatch)
case Upper:
return strings.ToUpper(submatch)
}

return submatch
}

// removeMatchedMetricsAndAppendCombined removes the set of matched metrics from metrics and appends the combined metric at the end.
func (mtp *metricsTransformProcessor) removeMatchedMetricsAndAppendCombined(metrics []*metricspb.Metric, matchedMetrics []*match, combined *metricspb.Metric) []*metricspb.Metric {
filteredMetrics := make([]*metricspb.Metric, 0, len(metrics)-len(matchedMetrics))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -856,13 +856,14 @@ var (
name: "combine",
transforms: []internalTransform{
{
MetricIncludeFilter: internalFilterRegexp{include: regexp.MustCompile("^(metric)(?P<namedsubmatch>[12])$")},
MetricIncludeFilter: internalFilterRegexp{include: regexp.MustCompile("^([mM]etric)(?P<namedsubmatch>[12])$")},
Action: Combine,
NewName: "new",
SubmatchCase: "lower",
},
},
in: []*metricspb.Metric{
metricBuilder().setName("metric1").
metricBuilder().setName("Metric1").
setDataType(metricspb.MetricDescriptor_GAUGE_INT64).
addTimeseries(1, nil).addInt64Point(0, 1, 1).
build(),
Expand Down Expand Up @@ -930,13 +931,14 @@ var (
name: "combine_single_match",
transforms: []internalTransform{
{
MetricIncludeFilter: internalFilterRegexp{include: regexp.MustCompile("^(metric)(?P<namedsubmatch>[1])$")},
MetricIncludeFilter: internalFilterRegexp{include: regexp.MustCompile("^([mM]etric)(?P<namedsubmatch>[1])$")},
Action: Combine,
NewName: "new",
SubmatchCase: "upper",
},
},
in: []*metricspb.Metric{
metricBuilder().setName("metric1").
metricBuilder().setName("Metric1").
setDataType(metricspb.MetricDescriptor_GAUGE_INT64).
addTimeseries(1, nil).addInt64Point(0, 1, 1).
build(),
Expand All @@ -961,7 +963,7 @@ var (
metricBuilder().setName("new").
setLabels([]string{"$1", "namedsubmatch"}).
setDataType(metricspb.MetricDescriptor_GAUGE_INT64).
addTimeseries(1, []string{"metric", "1"}).addInt64Point(0, 1, 1).
addTimeseries(1, []string{"METRIC", "1"}).addInt64Point(0, 1, 1).
build(),
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ processors:
match_type: regexp
action: combine
new_name: combined_metric_name
submatch_case: lower

exporters:
exampleexporter:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
receivers:
examplereceiver:

processors:
metricstransform:
transforms:
- include: old_name
action: combine
new_name: new_name
submatch_case: invalid

exporters:
exampleexporter:

service:
pipelines:
traces:
receivers: [examplereceiver]
processors: [metricstransform]
exporters: [exampleexporter]
metrics:
receivers: [examplereceiver]
processors: [metricstransform]
exporters: [exampleexporter]

0 comments on commit b44e9e4

Please sign in to comment.