in confgenerator/logging_modify_fields.go [254:429]
func (p LoggingProcessorModifyFields) statements(_ context.Context) (ottl.Statements, error) {
var statements ottl.Statements
var dests []string
for dest, field := range p.Fields {
if field == nil {
// Nothing to do for this field
continue
}
dests = append(dests, dest)
}
sort.Strings(dests)
// map of (dest field as OTTL expression) to (source field as OTTL expression)
fieldMappings := map[string]ottl.LValue{}
// slice of OTTL fields to delete
var moveFromFields []ottl.LValue
// map of (variable name) to (filter object)
var omitFilters []*filter.Filter
for i, dest := range dests {
field := p.Fields[dest]
if field.MoveFrom == "" && field.CopyFrom == "" && field.StaticValue == nil {
// Default to modifying field in place
field.CopyFrom = dest
}
for j, name := range []*string{&field.MoveFrom, &field.CopyFrom} {
if *name == "" {
continue
}
m, err := filter.NewMember(*name)
if err != nil {
return nil, fmt.Errorf("failed to parse field %q: %w", *name, err)
}
accessor, err := m.OTTLAccessor()
if err != nil {
return nil, fmt.Errorf("failed to convert field %q to OTTL: %w", *name, err)
}
key := accessor.String()
if _, ok := fieldMappings[key]; !ok {
new := ottl.LValue{
"cache",
fmt.Sprintf("__field_%d", i),
}
fieldMappings[key] = new
statements = statements.Append(
new.Delete(),
new.SetIf(accessor, accessor.IsPresent()),
)
}
field.sourceValue = fieldMappings[key]
if j == 0 { // MoveFrom
moveFromFields = append(moveFromFields, accessor)
}
}
if field.OmitIf != "" {
f, err := filter.NewFilter(field.OmitIf)
if err != nil {
return nil, fmt.Errorf("failed to parse filter %q: %w", field.OmitIf, err)
}
field.omitVar = fmt.Sprintf("__omit_%d", len(omitFilters))
omitFilters = append(omitFilters, f)
}
}
// Step 2: OmitIf conditions
for i, f := range omitFilters {
name := fmt.Sprintf("__omit_%d", i)
expr, err := f.OTTLExpression()
if err != nil {
return nil, fmt.Errorf("failed to parse omit_if condition %q: %w", f, err)
}
statements = statements.Append(
ottl.LValue{"cache", name}.Set(ottl.False()),
ottl.LValue{"cache", name}.SetIf(ottl.True(), expr),
)
}
// Step 3: Remove any MoveFrom fields
// Sort first to make the resulting configs deterministic
sort.Slice(moveFromFields, func(i, j int) bool {
return moveFromFields[i].String() < moveFromFields[j].String()
})
var last ottl.LValue
for _, v := range moveFromFields {
if !slices.Equal(last, v) {
statements = statements.Append(v.Delete())
}
last = v
}
if p.EmptyBody {
// With no keys, will clear out the body, leaving a copy at cache.body.
statements = statements.Append(
ottl.LValue{"cache", "body"}.Set(ottl.LValue{"body"}),
ottl.LValue{"body"}.KeepKeys(),
)
}
// Step 4: Assign values
for _, dest := range dests {
field := p.Fields[dest]
outM, err := filter.NewMember(dest)
if err != nil {
return nil, fmt.Errorf("failed to parse output field %q: %w", dest, err)
}
src := ottl.Nil()
if field.sourceValue != nil {
src = field.sourceValue
}
if field.StaticValue != nil {
src = ottl.StringLiteral(*field.StaticValue)
}
value := ottl.LValue{"cache", "value"}
statements = statements.Append(
// Set silently fails to set if the value is nil, so we delete first.
value.Delete(),
value.Set(src),
)
if field.DefaultValue != nil {
statements = statements.Append(
value.SetIfNil(ottl.StringLiteral(*field.DefaultValue)),
)
}
// Process MapValues
if len(field.MapValues) > 0 {
mapped_value := ottl.LValue{"cache", "mapped_value"}
statements = statements.Append(
mapped_value.Delete(),
)
if !field.MapValuesExclusive {
statements = statements.Append(
mapped_value.SetIf(value, value.IsPresent()),
)
}
var keys []string
for k := range field.MapValues {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
statements = statements.Append(
mapped_value.SetIf(ottl.StringLiteral(field.MapValues[k]), ottl.Equals(value, ottl.StringLiteral(k))),
)
}
value = mapped_value
}
switch field.Type {
case "integer":
statements = statements.Append(value.Set(ottl.ToInt(value)))
case "float":
statements = statements.Append(value.Set(ottl.ToFloat(value)))
case "YesNoBoolean":
// TODO
return nil, fmt.Errorf("YesNoBoolean unsupported")
}
if field.CustomConvertFunc != nil {
statements = statements.Append(field.CustomConvertFunc(value))
}
ra, err := outM.OTTLAccessor()
if err != nil {
return nil, fmt.Errorf("failed to convert %v to OTTL accessor: %w", outM, err)
}
statements = statements.Append(ra.SetIf(value, value.IsPresent()))
if field.omitVar != "" {
statements = statements.Append(ra.DeleteIf(ottl.Equals(ottl.LValue{"cache", field.omitVar}, ottl.True())))
}
}
return statements, nil
}