-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[pkg/ottl] add duration converter function (#23659)
Description: Added a converter function that takes a string representation of a duration and converts it to a Golang duration. Link to tracking Issue: #22015 Testing: Unit tests for stringGetter to duration. Documentation: --------- Co-authored-by: Tyler Helmuth <[email protected]>
- Loading branch information
1 parent
0e4cb4a
commit 456849a
Showing
5 changed files
with
286 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Use this changelog template to create an entry for release notes. | ||
# If your change doesn't affect end users, such as a test fix or a tooling change, | ||
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. | ||
|
||
# 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 new `Duration` converter to convert string to a Golang time.duration" | ||
|
||
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. | ||
issues: [22015] | ||
|
||
# (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: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs" | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" | ||
) | ||
|
||
type DurationArguments[K any] struct { | ||
Duration ottl.StringGetter[K] `ottlarg:"0"` | ||
} | ||
|
||
func NewDurationFactory[K any]() ottl.Factory[K] { | ||
return ottl.NewFactory("Duration", &DurationArguments[K]{}, createDurationFunction[K]) | ||
} | ||
func createDurationFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) { | ||
args, ok := oArgs.(*DurationArguments[K]) | ||
|
||
if !ok { | ||
return nil, fmt.Errorf("DurationFactory args must be of type *DurationArguments[K]") | ||
} | ||
|
||
return Duration(args.Duration) | ||
} | ||
|
||
func Duration[K any](duration ottl.StringGetter[K]) (ottl.ExprFunc[K], error) { | ||
return func(ctx context.Context, tCtx K) (interface{}, error) { | ||
d, err := duration.Get(ctx, tCtx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
dur, err := time.ParseDuration(d) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return dur, nil | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package ottlfuncs | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" | ||
) | ||
|
||
func Test_Duration(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
duration ottl.StringGetter[interface{}] | ||
expected time.Duration | ||
}{ | ||
{ | ||
name: "100 milliseconds", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "100ms", nil | ||
}, | ||
}, | ||
expected: time.Duration(100000000), | ||
}, { | ||
name: "234 microseconds", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "234us", nil | ||
}, | ||
}, | ||
expected: time.Duration(234000), | ||
}, { | ||
name: "777 nanoseconds", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "777ns", nil | ||
}, | ||
}, | ||
expected: time.Duration(777), | ||
}, | ||
{ | ||
name: "one second", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "1s", nil | ||
}, | ||
}, | ||
expected: time.Duration(1000000000), | ||
}, | ||
{ | ||
name: "two hundred second", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "200s", nil | ||
}, | ||
}, | ||
expected: time.Duration(200000000000), | ||
}, | ||
{ | ||
name: "three minutes", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "3m", nil | ||
}, | ||
}, | ||
expected: time.Duration(180000000000), | ||
}, | ||
{ | ||
name: "45 minutes", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "45m", nil | ||
}, | ||
}, | ||
expected: time.Duration(2700000000000), | ||
}, | ||
{ | ||
name: "7 mins, 12 secs", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "7m12s", nil | ||
}, | ||
}, | ||
expected: time.Duration(432000000000), | ||
}, | ||
{ | ||
name: "4 hours", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "4h", nil | ||
}, | ||
}, | ||
expected: time.Duration(14400000000000), | ||
}, | ||
{ | ||
name: "5 hours, 23 mins, 59 secs", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "5h23m59s", nil | ||
}, | ||
}, | ||
expected: time.Duration(19439000000000), | ||
}, | ||
{ | ||
name: "5 hours, 59 secs", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "5h59s", nil | ||
}, | ||
}, | ||
expected: time.Duration(18059000000000), | ||
}, | ||
{ | ||
name: "5 hours, 23 mins", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "5h23m", nil | ||
}, | ||
}, | ||
expected: time.Duration(19380000000000), | ||
}, | ||
{ | ||
name: "2 mins, 1 sec, 64 microsecs", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "2m1s64us", nil | ||
}, | ||
}, | ||
expected: time.Duration(121000064000), | ||
}, | ||
{ | ||
name: "59 hours, 1 min, 78 millisecs", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "59h1m78ms", nil | ||
}, | ||
}, | ||
expected: time.Duration(212460078000000), | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
exprFunc, err := Duration(tt.duration) | ||
assert.NoError(t, err) | ||
result, err := exprFunc(nil, nil) | ||
assert.NoError(t, err) | ||
assert.Equal(t, tt.expected, result) | ||
}) | ||
} | ||
} | ||
|
||
func Test_DurationError(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
duration ottl.StringGetter[interface{}] | ||
expectedError string | ||
}{ | ||
{ | ||
name: "empty duration", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "", nil | ||
}, | ||
}, | ||
expectedError: "invalid duration", | ||
}, | ||
{ | ||
name: "empty duration", | ||
duration: &ottl.StandardStringGetter[interface{}]{ | ||
Getter: func(ctx context.Context, tCtx interface{}) (interface{}, error) { | ||
return "one second", nil | ||
}, | ||
}, | ||
expectedError: "invalid duration", | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
exprFunc, err := Duration[any](tt.duration) | ||
require.NoError(t, err) | ||
_, err = exprFunc(context.Background(), nil) | ||
assert.ErrorContains(t, err, tt.expectedError) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters