pkg/ottl/contexts/internal/ctxutil/value.go (194 lines of code) (raw):

// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ctxutil // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/internal/ctxutil" import ( "context" "errors" "fmt" "go.opentelemetry.io/collector/pdata/pcommon" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/internal/ottlcommon" ) func SetValue(value pcommon.Value, val any) error { var err error switch v := val.(type) { case string: value.SetStr(v) case bool: value.SetBool(v) case int64: value.SetInt(v) case float64: value.SetDouble(v) case []byte: value.SetEmptyBytes().FromRaw(v) case []string: value.SetEmptySlice().EnsureCapacity(len(v)) for _, str := range v { value.Slice().AppendEmpty().SetStr(str) } case []bool: value.SetEmptySlice().EnsureCapacity(len(v)) for _, b := range v { value.Slice().AppendEmpty().SetBool(b) } case []int64: value.SetEmptySlice().EnsureCapacity(len(v)) for _, i := range v { value.Slice().AppendEmpty().SetInt(i) } case []float64: value.SetEmptySlice().EnsureCapacity(len(v)) for _, f := range v { value.Slice().AppendEmpty().SetDouble(f) } case [][]byte: value.SetEmptySlice().EnsureCapacity(len(v)) for _, b := range v { value.Slice().AppendEmpty().SetEmptyBytes().FromRaw(b) } case []any: value.SetEmptySlice().EnsureCapacity(len(v)) for _, a := range v { pval := value.Slice().AppendEmpty() err = SetValue(pval, a) } case pcommon.Slice: v.CopyTo(value.SetEmptySlice()) case pcommon.Map: v.CopyTo(value.SetEmptyMap()) case map[string]any: err = value.FromRaw(v) } return err } func getIndexableValue[K any](ctx context.Context, tCtx K, value pcommon.Value, keys []ottl.Key[K]) (any, error) { val := value var ok bool for index := 0; index < len(keys); index++ { switch val.Type() { case pcommon.ValueTypeMap: s, err := keys[index].String(ctx, tCtx) if err != nil { return nil, err } if s == nil { resString, err := FetchValueFromExpression[K, string](ctx, tCtx, keys[index]) if err != nil { return nil, fmt.Errorf("unable to resolve a string index in map: %w", err) } s = resString } val, ok = val.Map().Get(*s) if !ok { return nil, nil } case pcommon.ValueTypeSlice: i, err := keys[index].Int(ctx, tCtx) if err != nil { return nil, err } if i == nil { resInt, err := FetchValueFromExpression[K, int64](ctx, tCtx, keys[index]) if err != nil { return nil, fmt.Errorf("unable to resolve an integer index in slice: %w", err) } i = resInt } if int(*i) >= val.Slice().Len() || int(*i) < 0 { return nil, fmt.Errorf("index %v out of bounds", *i) } val = val.Slice().At(int(*i)) default: return nil, fmt.Errorf("type %v does not support string indexing", val.Type()) } } return ottlcommon.GetValue(val), nil } func SetIndexableValue[K any](ctx context.Context, tCtx K, currentValue pcommon.Value, val any, keys []ottl.Key[K]) error { var newValue pcommon.Value switch val.(type) { case []string, []bool, []int64, []float64, [][]byte, []any: newValue = pcommon.NewValueSlice() default: newValue = pcommon.NewValueEmpty() } err := SetValue(newValue, val) if err != nil { return err } for index := 0; index < len(keys); index++ { switch currentValue.Type() { case pcommon.ValueTypeMap: s, err := keys[index].String(ctx, tCtx) if err != nil { return err } if s == nil { resString, err := FetchValueFromExpression[K, string](ctx, tCtx, keys[index]) if err != nil { return fmt.Errorf("unable to resolve a string index in map: %w", err) } s = resString } potentialValue, ok := currentValue.Map().Get(*s) if !ok { currentValue = currentValue.Map().PutEmpty(*s) } else { currentValue = potentialValue } case pcommon.ValueTypeSlice: i, err := keys[index].Int(ctx, tCtx) if err != nil { return err } if i == nil { resInt, err := FetchValueFromExpression[K, int64](ctx, tCtx, keys[index]) if err != nil { return fmt.Errorf("unable to resolve an integer index in slice: %w", err) } i = resInt } if int(*i) >= currentValue.Slice().Len() || int(*i) < 0 { return fmt.Errorf("index %v out of bounds", *i) } currentValue = currentValue.Slice().At(int(*i)) case pcommon.ValueTypeEmpty: s, err := keys[index].String(ctx, tCtx) if err != nil { return err } i, err := keys[index].Int(ctx, tCtx) if err != nil { return err } switch { case s != nil: currentValue = currentValue.SetEmptyMap().PutEmpty(*s) case i != nil: currentValue.SetEmptySlice() for k := 0; k < int(*i); k++ { currentValue.Slice().AppendEmpty() } currentValue = currentValue.Slice().AppendEmpty() default: resString, errString := FetchValueFromExpression[K, string](ctx, tCtx, keys[index]) resInt, errInt := FetchValueFromExpression[K, int64](ctx, tCtx, keys[index]) switch { case errInt == nil: currentValue.SetEmptySlice() for k := 0; k < int(*resInt); k++ { currentValue.Slice().AppendEmpty() } currentValue = currentValue.Slice().AppendEmpty() case errString == nil: currentValue = currentValue.SetEmptyMap().PutEmpty(*resString) default: return errors.New("neither a string nor an int index was given, this is an error in the OTTL") } } default: return fmt.Errorf("type %v does not support string indexing", currentValue.Type()) } } newValue.CopyTo(currentValue) return nil }