-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
[transform] Implementation of transform processing #8252
Comments
Just tried this processor, is there a way to check whether an attribute exists? like |
@anuraaga does the transform processor support using wildcards for operations with attributes through queries? |
@pureklkl Thanks for the suggestion! @aunshc Wildcards in the path expressions is not currently supported. Could you describe your use case for wildcards? Is it to remove attributes for entire namespaces? |
@anuraaga The use case is to perform actions like insert, update, delete listed for the attributesprocessor https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/attributesprocessor for all attributes within a namespace with wildcards (eg. |
I need following features for the metric side, and I think they are already supported for the span(feel free to to correct me):
I am wondering what is the timeline to add support for metric side. If possible, I would also like to help the contribution to accelerate the progress. |
Hi @pureklkl - indeed I think they are supported or would only require some small tweaks. I am currently working on a change to make the core function handling logic generic, instead of only working with spans, which will enable adding the metrics data model. Should be able to send it out this week and it will hopefully be relatively mechanical to get metrics in after that. |
I can start working on adding the metrics data model |
Thanks @TylerHelmuth - just one point about metrics which you may have already realized is we would scope the transformations to a point so need to expose the metrics descriptor as well in the field expressions, this is briefly mentioned in the design doc. Let me know if anything's not clear about that |
That helps a lot. Where did |
@anuraaga what do you think will be the best way to do the access functions for the data points themselves since there are multiple? Unlike traces and logs, There is cleanup that should be done, but could look like this func accessAttributes() pathGetSetter {
return pathGetSetter{
getter: func(ctx common.TransformContext) interface{} {
metric := ctx.GetItem().(pmetric.Metric)
switch metric.DataType() {
case pmetric.MetricDataTypeGauge:
dps := metric.Gauge().DataPoints()
dataPointAttrs := make([]pcommon.Map, dps.Len())
for i := 0; i < dps.Len(); i++ {
dataPointAttrs[i] = dps.At(i).Attributes()
}
return dataPointAttrs
case pmetric.MetricDataTypeSum:
dps := metric.Sum().DataPoints()
dataPointAttrs := make([]pcommon.Map, dps.Len())
for i := 0; i < dps.Len(); i++ {
dataPointAttrs[i] = dps.At(i).Attributes()
}
return dataPointAttrs
case pmetric.MetricDataTypeHistogram:
dps := metric.Histogram().DataPoints()
dataPointAttrs := make([]pcommon.Map, dps.Len())
for i := 0; i < dps.Len(); i++ {
dataPointAttrs[i] = dps.At(i).Attributes()
}
return dataPointAttrs
case pmetric.MetricDataTypeExponentialHistogram:
dps := metric.ExponentialHistogram().DataPoints()
dataPointAttrs := make([]pcommon.Map, dps.Len())
for i := 0; i < dps.Len(); i++ {
dataPointAttrs[i] = dps.At(i).Attributes()
}
return dataPointAttrs
case pmetric.MetricDataTypeSummary:
dps := metric.Summary().DataPoints()
dataPointAttrs := make([]pcommon.Map, dps.Len())
for i := 0; i < dps.Len(); i++ {
dataPointAttrs[i] = dps.At(i).Attributes()
}
return dataPointAttrs
}
return nil
},
setter: func(ctx common.TransformContext, val interface{}) {
metric := ctx.GetItem().(pmetric.Metric)
switch metric.DataType() {
case pmetric.MetricDataTypeGauge:
if attrs, ok := val.([]pcommon.Map); ok {
dps := metric.Gauge().DataPoints()
for i := 0; i < len(attrs); i++ {
dps.At(i).Attributes().Clear()
attrs[i].CopyTo(dps.At(i).Attributes())
}
}
case pmetric.MetricDataTypeSum:
if attrs, ok := val.([]pcommon.Map); ok {
dps := metric.Sum().DataPoints()
for i := 0; i < len(attrs); i++ {
dps.At(i).Attributes().Clear()
attrs[i].CopyTo(dps.At(i).Attributes())
}
}
case pmetric.MetricDataTypeHistogram:
if attrs, ok := val.([]pcommon.Map); ok {
dps := metric.Histogram().DataPoints()
for i := 0; i < len(attrs); i++ {
dps.At(i).Attributes().Clear()
attrs[i].CopyTo(dps.At(i).Attributes())
}
}
case pmetric.MetricDataTypeExponentialHistogram:
if attrs, ok := val.([]pcommon.Map); ok {
dps := metric.ExponentialHistogram().DataPoints()
for i := 0; i < len(attrs); i++ {
dps.At(i).Attributes().Clear()
attrs[i].CopyTo(dps.At(i).Attributes())
}
}
case pmetric.MetricDataTypeSummary:
if attrs, ok := val.([]pcommon.Map); ok {
dps := metric.Summary().DataPoints()
for i := 0; i < len(attrs); i++ {
dps.At(i).Attributes().Clear()
attrs[i].CopyTo(dps.At(i).Attributes())
}
}
}
},
}
} Or would the func accessAttributes() pathGetSetter {
return pathGetSetter{
getter: func(ctx common.TransformContext) interface{} {
switch ctx.GetItem().(type) {
case pmetric.NumberDataPoint:
return ctx.GetItem().(pmetric.NumberDataPoint).Attributes()
case pmetric.HistogramDataPoint:
return ctx.GetItem().(pmetric.HistogramDataPoint).Attributes()
case pmetric.ExponentialHistogramDataPoint:
return ctx.GetItem().(pmetric.ExponentialHistogramDataPoint).Attributes()
case pmetric.SummaryDataPoint:
return ctx.GetItem().(pmetric.SummaryDataPoint).Attributes()
}
return nil
},
setter: func(ctx common.TransformContext, val interface{}) {
switch ctx.GetItem().(type) {
case pmetric.NumberDataPoint:
if attrs, ok := val.(pcommon.Map); ok {
ctx.GetItem().(pmetric.NumberDataPoint).Attributes().Clear()
attrs.CopyTo(ctx.GetItem().(pmetric.NumberDataPoint).Attributes())
}
case pmetric.HistogramDataPoint:
if attrs, ok := val.(pcommon.Map); ok {
ctx.GetItem().(pmetric.HistogramDataPoint).Attributes().Clear()
attrs.CopyTo(ctx.GetItem().(pmetric.HistogramDataPoint).Attributes())
}
case pmetric.ExponentialHistogramDataPoint:
if attrs, ok := val.(pcommon.Map); ok {
ctx.GetItem().(pmetric.ExponentialHistogramDataPoint).Attributes().Clear()
attrs.CopyTo(ctx.GetItem().(pmetric.ExponentialHistogramDataPoint).Attributes())
}
case pmetric.SummaryDataPoint:
if attrs, ok := val.(pcommon.Map); ok {
ctx.GetItem().(pmetric.SummaryDataPoint).Attributes().Clear()
attrs.CopyTo(ctx.GetItem().(pmetric.SummaryDataPoint).Attributes())
}
}
},
}
} |
Also, in the design doc the metrics are accessed by name:
In a situation like this, it looks like the read_gauge function needs access to the Gauge() of a metric with a name of "pod.cpu.usage". How would our switch statement handle a situation like this? |
I went forward with the |
The metrics data model has been merged, I will get started on wiring up the processor to the metrics pipeline. |
I think |
I'll get a PR out for |
All required PRs have been merged. Once 0.52.0 is released I'll update the processor's status table. |
The transform processor currently supports transformation of traces. This issue tracks next steps
The text was updated successfully, but these errors were encountered: