Skip to content

Commit 1aed17d

Browse files
authored
Add subtract_initial_point strategy skeleton (#38380)
#### Description Add a skeleton for the `subtract_initial_point` strategy. The implementation will follow in subsequent PRs. #### Link to tracking issue Part of #37186, and #38379 #### Testing Added config_test.go #### Documentation Updated the README.
1 parent fbf1c51 commit 1aed17d

File tree

9 files changed

+195
-4
lines changed

9 files changed

+195
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: metricstarttimeprocessor
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add the subtract_initial_point strategy skeleton
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [37186, 38379]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext: The subtract_initial_point strategy is not fully implemented
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

processor/metricstarttimeprocessor/README.md

+17
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,20 @@ Cons:
5050
* The True Reset point doesn't make sense semantically. It has a zero duration, but non-zero values.
5151
* Many backends reject points with equal start and end timestamps.
5252
* If the True Reset point is rejected, the next point will appear to have a very large rate.
53+
54+
### Strategy: Subtract Initial Point
55+
56+
The `subtract_initial_point` strategy handles missing start times for
57+
cumulative points by dropping the first point in a cumulative series,
58+
"subtracting" that point's value from subsequent points and using the initial
59+
point's timestamp as the start timestamp for subsequent points.
60+
61+
Pros:
62+
63+
* Cumulative semantics are preserved. This means that for a point with a given `[start, end]` interval, the cumulative value occurred in that interval.
64+
* Rates over resulting timeseries are correct, even if points are lost. This strategy is not stateful.
65+
66+
Cons:
67+
68+
* The absolute value of counters is modified. This is generally not an issue, since counters are usually used to compute rates.
69+
* The initial point is dropped, which loses information.

processor/metricstarttimeprocessor/config.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"go.opentelemetry.io/collector/component"
1111

12+
"github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricstarttimeprocessor/internal/subtractinitial"
1213
"github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricstarttimeprocessor/internal/truereset"
1314
)
1415

@@ -29,8 +30,11 @@ func createDefaultConfig() component.Config {
2930

3031
// Validate checks the configuration is valid
3132
func (cfg *Config) Validate() error {
32-
if cfg.Strategy != truereset.Type {
33-
return fmt.Errorf("%v is not a valid strategy", cfg.Strategy)
33+
switch cfg.Strategy {
34+
case truereset.Type:
35+
case subtractinitial.Type:
36+
default:
37+
return fmt.Errorf("%q is not a valid strategy", cfg.Strategy)
3438
}
3539
if cfg.GCInterval <= 0 {
3640
return fmt.Errorf("gc_interval must be positive")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package metricstarttimeprocessor
5+
6+
import (
7+
"path/filepath"
8+
"testing"
9+
"time"
10+
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
13+
"go.opentelemetry.io/collector/component"
14+
"go.opentelemetry.io/collector/confmap/confmaptest"
15+
"go.opentelemetry.io/collector/confmap/xconfmap"
16+
17+
"github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricstarttimeprocessor/internal/metadata"
18+
"github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricstarttimeprocessor/internal/subtractinitial"
19+
"github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricstarttimeprocessor/internal/truereset"
20+
)
21+
22+
func TestLoadConfig(t *testing.T) {
23+
t.Parallel()
24+
25+
tests := []struct {
26+
id component.ID
27+
expected component.Config
28+
errorMessage string
29+
}{
30+
{
31+
id: component.NewIDWithName(metadata.Type, ""),
32+
expected: &Config{
33+
Strategy: truereset.Type,
34+
GCInterval: 10 * time.Minute,
35+
},
36+
},
37+
{
38+
id: component.NewIDWithName(metadata.Type, "subtract_initial_point"),
39+
expected: &Config{
40+
Strategy: subtractinitial.Type,
41+
GCInterval: 10 * time.Minute,
42+
},
43+
},
44+
{
45+
id: component.NewIDWithName(metadata.Type, "gc_interval"),
46+
expected: &Config{
47+
Strategy: truereset.Type,
48+
GCInterval: 1 * time.Hour,
49+
},
50+
},
51+
{
52+
id: component.NewIDWithName(metadata.Type, "negative_interval"),
53+
errorMessage: "gc_interval must be positive",
54+
},
55+
{
56+
id: component.NewIDWithName(metadata.Type, "invalid_strategy"),
57+
errorMessage: "\"bad\" is not a valid strategy",
58+
},
59+
}
60+
61+
for _, tt := range tests {
62+
t.Run(tt.id.String(), func(t *testing.T) {
63+
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml"))
64+
require.NoError(t, err)
65+
66+
factory := NewFactory()
67+
cfg := factory.CreateDefaultConfig()
68+
sub, err := cm.Sub(tt.id.String())
69+
require.NoError(t, err)
70+
require.NoError(t, sub.Unmarshal(cfg))
71+
72+
if tt.expected == nil {
73+
assert.EqualError(t, xconfmap.Validate(cfg), tt.errorMessage)
74+
return
75+
}
76+
assert.NoError(t, xconfmap.Validate(cfg))
77+
assert.Equal(t, tt.expected, cfg)
78+
})
79+
}
80+
}

processor/metricstarttimeprocessor/factory.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"go.opentelemetry.io/collector/processor/processorhelper"
1313

1414
"github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricstarttimeprocessor/internal/metadata"
15+
"github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricstarttimeprocessor/internal/subtractinitial"
1516
"github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricstarttimeprocessor/internal/truereset"
1617
)
1718

@@ -32,13 +33,22 @@ func createMetricsProcessor(
3233
) (processor.Metrics, error) {
3334
rCfg := cfg.(*Config)
3435

35-
adjuster := truereset.NewAdjuster(set.TelemetrySettings, rCfg.GCInterval)
36+
var adjustMetrics processorhelper.ProcessMetricsFunc
37+
38+
switch rCfg.Strategy {
39+
case truereset.Type:
40+
adjuster := truereset.NewAdjuster(set.TelemetrySettings, rCfg.GCInterval)
41+
adjustMetrics = adjuster.AdjustMetrics
42+
case subtractinitial.Type:
43+
adjuster := subtractinitial.NewAdjuster(set.TelemetrySettings, rCfg.GCInterval)
44+
adjustMetrics = adjuster.AdjustMetrics
45+
}
3646

3747
return processorhelper.NewMetrics(
3848
ctx,
3949
set,
4050
cfg,
4151
nextConsumer,
42-
adjuster.AdjustMetrics,
52+
adjustMetrics,
4353
processorhelper.WithCapabilities(consumer.Capabilities{MutatesData: true}))
4454
}

processor/metricstarttimeprocessor/go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
go.opentelemetry.io/collector/component v1.27.0
99
go.opentelemetry.io/collector/component/componenttest v0.121.0
1010
go.opentelemetry.io/collector/confmap v1.27.0
11+
go.opentelemetry.io/collector/confmap/xconfmap v0.121.0
1112
go.opentelemetry.io/collector/consumer v1.27.0
1213
go.opentelemetry.io/collector/consumer/consumertest v0.121.0
1314
go.opentelemetry.io/collector/pdata v1.27.0

processor/metricstarttimeprocessor/go.sum

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package subtractinitial // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricstarttimeprocessor/internal/subtractinitial"
5+
6+
import (
7+
"context"
8+
"errors"
9+
"time"
10+
11+
"go.opentelemetry.io/collector/component"
12+
"go.opentelemetry.io/collector/pdata/pmetric"
13+
)
14+
15+
// Type is the value users can use to configure the subtract initial point adjuster.
16+
// The subtract initial point adjuster sets the start time of all points in a series by:
17+
// - Dropping the initial point, and recording its value and timestamp.
18+
// - Subtracting the initial point from all subsequent points, and using the timestamp of the initial point as the start timestamp.
19+
const Type = "subtract_initial_point"
20+
21+
type Adjuster struct {
22+
set component.TelemetrySettings
23+
}
24+
25+
// NewAdjuster returns a new Adjuster which adjust metrics' start times based on the initial received points.
26+
func NewAdjuster(set component.TelemetrySettings, _ time.Duration) *Adjuster {
27+
return &Adjuster{
28+
set: set,
29+
}
30+
}
31+
32+
// AdjustMetrics takes a sequence of metrics and adjust their start times based on the initial and
33+
// previous points in the timeseriesMap.
34+
func (a *Adjuster) AdjustMetrics(_ context.Context, metrics pmetric.Metrics) (pmetric.Metrics, error) {
35+
// TODO(#38379): Implement the subtract_initial_point adjuster
36+
return metrics, errors.New("not implemented")
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
metricstarttime:
2+
3+
metricstarttime/subtract_initial_point:
4+
strategy: subtract_initial_point
5+
6+
metricstarttime/gc_interval:
7+
gc_interval: 1h
8+
9+
metricstarttime/negative_interval:
10+
gc_interval: -1h
11+
12+
metricstarttime/invalid_strategy:
13+
strategy: bad

0 commit comments

Comments
 (0)