Skip to content
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

Extend Metrics Transform to be able to add a label to an existing metric #441

Merged
merged 3 commits into from
Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions processor/metricstransformprocessor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The metrics transform processor can be used to rename metrics, labels, or label
- Aggregation_type: sum, average, max
- Aggregate across label values (e.g. want `memory{slab}`, but don’t care about `memory{slab_reclaimable}` & `memory{slab_unreclaimable}`)
- Aggregation_type: sum, average, max
- Add label to an existing metric

## Configuration
```yaml
Expand Down Expand Up @@ -97,3 +98,16 @@ operations:
new_value: slab
aggregation_type: sum
```

### Add a label to an existing metric
```yaml
transforms:
...
# The following will append label {Key: `mylabel`, Description: `myvalue`} to the metric `some_name`.
- metric_name: some_name
action: update
operation:
- action: add_label
new_label: mylabel
new_value: myvalue
```
8 changes: 7 additions & 1 deletion processor/metricstransformprocessor/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ const (

// NewLabelFieldName is the mapstructure field name for NewLabel field
NewLabelFieldName = "new_label"

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

// Config defines configuration for Resource processor.
Expand Down Expand Up @@ -80,7 +83,7 @@ type Operation struct {
// AggregatedValues is a list of label values to aggregate away.
AggregatedValues []string `mapstructure:"aggregated_values"`

// NewValue indicates what is the value called when the AggregatedValues are aggregated into one.
// NewValue is used to set a new label value either when the operation is `AggregatedValues` or `AddLabel`.
NewValue string `mapstructure:"new_value"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NewValue field here used to mean the new label value for the label values being aggregated together, but it seems like in this action add_label, this field means the description for the new label. Please correct me if I am wrong, but this seems like a pretty big difference for this one field in two different actions. Maybe consider having a new field called newDescription or something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note: we probably need to break this struct up for different operation types at some point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just an error in setting the label values at the metric descriptor and not at the time series. Since the intent of hte pr is to update the label values they have the same goal (either in add a new label or when it gets aggregated). To make it cleared, i'll update the comment to say

// NewValue is used to set a new label value either when the operation is `AggregatedValues` or `AddLabel`.


// ValueActions is a list of renaming actions for label values.
Expand Down Expand Up @@ -115,6 +118,9 @@ const (
// ToggleScalarDataType changes the data type from int64 to double, or vice-versa
ToggleScalarDataType OperationAction = "toggle_scalar_data_type"

// AddLabel adds a new label to an existing metric.
AddLabel OperationAction = "add_label"

// UpdateLabel applies name changes to label and/or label values.
UpdateLabel OperationAction = "update_label"

Expand Down
22 changes: 22 additions & 0 deletions processor/metricstransformprocessor/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,28 @@ var (
},
},
},
{
filterName: "metricstransform/addlabel",
expCfg: &Config{
ProcessorSettings: configmodels.ProcessorSettings{
NameVal: "metricstransform/addlabel",
TypeVal: typeStr,
},
Transforms: []Transform{
{
MetricName: "some_name",
Action: Update,
Operations: []Operation{
{
Action: AddLabel,
NewLabel: "mylabel",
NewValue: "myvalue",
},
},
},
},
},
},
}
)

Expand Down
6 changes: 6 additions & 0 deletions processor/metricstransformprocessor/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ func validateConfiguration(config *Config) error {
if op.Action == UpdateLabel && op.Label == "" {
return fmt.Errorf("missing required field %q while %q is %v in the %vth operation", LabelFieldName, ActionFieldName, UpdateLabel, i)
}
if op.Action == AddLabel && op.NewLabel == "" {
return fmt.Errorf("missing required field %q while %q is %v in the %vth operation", NewLabelFieldName, ActionFieldName, AddLabel, i)
}
if op.Action == AddLabel && op.NewValue == "" {
return fmt.Errorf("missing required field %q while %q is %v in the %vth operation", NewValueFieldName, ActionFieldName, AddLabel, i)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ Duplicated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite duplicated but I can condense it to say that both NewLabel/NewValue are required. It would make the error message less precise as it won't say what is missing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad 🤦‍♂️

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries :)

}
}

Expand Down
38 changes: 38 additions & 0 deletions processor/metricstransformprocessor/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,41 @@ func TestCreateProcessors(t *testing.T) {
}
}
}

func TestFactory_validateConfiguration(t *testing.T) {
v1 := Config{
Transforms: []Transform{
{
MetricName: "mymetric",
Action: Update,
Operations: []Operation{
{
Action: AddLabel,
NewValue: "bar",
},
},
},
},
}
err := validateConfiguration(&v1)
assert.Equal(t, "missing required field \"new_label\" while \"action\" is add_label in the 0th operation", err.Error())

v2 := Config{
Transforms: []Transform{
{
MetricName: "mymetric",
Action: Update,
Operations: []Operation{
{
Action: AddLabel,
NewLabel: "foo",
},
},
},
},
}

err = validateConfiguration(&v2)
assert.Equal(t, "missing required field \"new_value\" while \"action\" is add_label in the 0th operation", err.Error())

}
16 changes: 16 additions & 0 deletions processor/metricstransformprocessor/metrics_transform_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,26 @@ func (mtp *metricsTransformProcessor) update(metric *metricspb.Metric, transform
mtp.updateLabelOp(metric, op)
} else if op.Action == ToggleScalarDataType {
mtp.ToggleScalarDataType(metric)
} else if op.Action == AddLabel {
mtp.addLabelOp(metric, op)
}
}
}

func (mtp *metricsTransformProcessor) addLabelOp(metric *metricspb.Metric, op Operation) {
var lb = metricspb.LabelKey{
Key: op.NewLabel,
}
metric.MetricDescriptor.LabelKeys = append(metric.MetricDescriptor.LabelKeys, &lb)
for _, ts := range metric.Timeseries {
lv := &metricspb.LabelValue{
Value: op.NewValue,
HasValue: true,
}
ts.LabelValues = append(ts.LabelValues, lv)
}
}

func (mtp *metricsTransformProcessor) updateLabelOp(metric *metricspb.Metric, op Operation) {
for _, label := range metric.MetricDescriptor.LabelKeys {
if label.Key != op.Label {
Expand Down