func()

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
}