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

[pkg/ottl] Add new FloatLikeGetter and FloatGetter #21896

Merged
merged 6 commits into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .chloggen/ottl-floatlikegetter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: pkg/ottl

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Add `FloatLikeGetter` and `FloatGetter` to facilitate float retrival for functions.

# One or more tracking issues related to the change
issues: [21896]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
69 changes: 69 additions & 0 deletions pkg/ottl/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"encoding/hex"
"fmt"
"strconv"

jsoniter "github.com/json-iterator/go"
"go.opentelemetry.io/collector/pdata/pcommon"
Expand Down Expand Up @@ -153,6 +154,10 @@ type IntGetter[K any] interface {
Get(ctx context.Context, tCtx K) (int64, error)
}

type FloatGetter[K any] interface {
Get(ctx context.Context, tCtx K) (float64, error)
}

type PMapGetter[K any] interface {
Get(ctx context.Context, tCtx K) (pcommon.Map, error)
}
Expand Down Expand Up @@ -225,6 +230,70 @@ func (g StandardStringLikeGetter[K]) Get(ctx context.Context, tCtx K) (*string,
return &result, nil
}

// FloatLikeGetter is a Getter that returns a float64 by converting the underlying value to a float64 if necessary.
type FloatLikeGetter[K any] interface {
// Get retrieves a float64 value.
// Unlike `FloatGetter`, the expectation is that the underlying value is converted to a float64 if possible.
// If the value cannot be converted to a float64, nil and an error are returned.
// If the value is nil, nil is returned without an error.
Get(ctx context.Context, tCtx K) (*float64, error)
}

type StandardFloatLikeGetter[K any] struct {
Getter func(ctx context.Context, tCtx K) (interface{}, error)
}

func (g StandardFloatLikeGetter[K]) Get(ctx context.Context, tCtx K) (*float64, error) {
val, err := g.Getter(ctx, tCtx)
if err != nil {
return nil, err
}
if val == nil {
return nil, nil
}
var result float64
switch v := val.(type) {
case float64:
result = v
case int64:
result = float64(v)
case string:
result, err = strconv.ParseFloat(v, 64)
if err != nil {
return nil, err
}
case bool:
if v {
result = float64(1)
} else {
result = float64(0)
}
case pcommon.Value:
switch v.Type() {
case pcommon.ValueTypeDouble:
result = v.Double()
case pcommon.ValueTypeInt:
result = float64(v.Int())
case pcommon.ValueTypeStr:
result, err = strconv.ParseFloat(v.Str(), 64)
if err != nil {
return nil, err
}
case pcommon.ValueTypeBool:
if v.Bool() {
result = float64(1)
} else {
result = float64(0)
}
default:
return nil, fmt.Errorf("unsupported value type: %v", v.Type())
}
default:
return nil, fmt.Errorf("unsupported type: %T", v)
}
return &result, nil
}

func (p *Parser[K]) newGetter(val value) (Getter[K], error) {
if val.IsNil != nil && *val.IsNil {
return &literal[K]{value: nil}, nil
Expand Down
163 changes: 163 additions & 0 deletions pkg/ottl/expression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -808,3 +808,166 @@ func Test_StandardStringLikeGetter(t *testing.T) {
})
}
}

func Test_StandardFloatLikeGetter(t *testing.T) {
tests := []struct {
name string
getter FloatLikeGetter[interface{}]
want interface{}
valid bool
expectedErrorMsg string
}{
{
name: "string type",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return "1.0", nil
},
},
want: 1.0,
valid: true,
},
{
name: "int64 type",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return int64(1), nil
},
},
want: float64(1),
valid: true,
},
{
name: "float64 type",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return 1.1, nil
},
},
want: 1.1,
valid: true,
},
{
name: "float64 bool true",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return true, nil
},
},
want: float64(1),
valid: true,
},
{
name: "float64 bool false",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return false, nil
},
},
want: float64(0),
valid: true,
},
{
name: "pcommon.value type int",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueInt(int64(100))
return v, nil
},
},
want: float64(100),
valid: true,
},
{
name: "pcommon.value type float",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueDouble(float64(1.1))
return v, nil
},
},
want: 1.1,
valid: true,
},
{
name: "pcommon.value type string",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueStr("1.1")
return v, nil
},
},
want: 1.1,
valid: true,
},
{
name: "pcommon.value type bool true",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueBool(true)
return v, nil
},
},
want: float64(1),
valid: true,
},
{
name: "pcommon.value type bool false",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueBool(false)
return v, nil
},
},
want: float64(0),
valid: true,
},
{
name: "nil",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return nil, nil
},
},
want: nil,
valid: true,
},
{
name: "invalid type",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
return []byte{}, nil
},
},
valid: false,
expectedErrorMsg: "unsupported type: []uint8",
},
{
name: "invalid pcommon.Value type",
getter: StandardFloatLikeGetter[interface{}]{
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) {
v := pcommon.NewValueMap()
return v, nil
},
},
valid: false,
expectedErrorMsg: "unsupported value type: Map",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
val, err := tt.getter.Get(context.Background(), nil)
if tt.valid {
assert.NoError(t, err)
if tt.want == nil {
assert.Nil(t, val)
} else {
assert.Equal(t, tt.want, *val)
}
} else {
assert.EqualError(t, err, tt.expectedErrorMsg)
}
})
}
}
18 changes: 18 additions & 0 deletions pkg/ottl/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ func (p *Parser[K]) buildSliceArg(argVal value, argType reflect.Type) (any, erro
return nil, err
}
return arg, nil
case strings.HasPrefix(name, "FloatLikeGetter"):
TylerHelmuth marked this conversation as resolved.
Show resolved Hide resolved
arg, err := buildSlice[FloatLikeGetter[K]](argVal, argType, p.buildArg, name)
if err != nil {
return nil, err
}
return arg, nil
default:
return nil, fmt.Errorf("unsupported slice type '%s' for function", argType.Elem().Name())
}
Expand Down Expand Up @@ -193,6 +199,18 @@ func (p *Parser[K]) buildArg(argVal value, argType reflect.Type) (any, error) {
return nil, err
}
return StandardStringLikeGetter[K]{Getter: arg.Get}, nil
case strings.HasPrefix(name, "FloatGetter"):
arg, err := p.newGetter(argVal)
if err != nil {
return nil, err
}
return StandardTypeGetter[K, float64]{Getter: arg.Get}, nil
case strings.HasPrefix(name, "FloatLikeGetter"):
arg, err := p.newGetter(argVal)
if err != nil {
return nil, err
}
return StandardFloatLikeGetter[K]{Getter: arg.Get}, nil
case strings.HasPrefix(name, "IntGetter"):
arg, err := p.newGetter(argVal)
if err != nil {
Expand Down
Loading
Loading