diff --git a/.chloggen/signaltometrics-config-validation.yaml b/.chloggen/signaltometrics-config-validation.yaml new file mode 100644 index 000000000000..73dbc3439327 --- /dev/null +++ b/.chloggen/signaltometrics-config-validation.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# 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: signaltometrics + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add config validation and custom OTTL functions + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [35930] + +# (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: Adds config validation for the signal to metrics connector. Also introduces `AdjustedCount` OTTL function. + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] diff --git a/connector/signaltometricsconnector/README.md b/connector/signaltometricsconnector/README.md index 9e0851209780..be38b041b716 100644 --- a/connector/signaltometricsconnector/README.md +++ b/connector/signaltometricsconnector/README.md @@ -103,9 +103,9 @@ histogram: - [**Optional**] `count` represents an OTTL expression to extract the count to be recorded in the histogram from the incoming data. If no expression is provided - then it defaults to the count of the signal i.e. [adjusted count](https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling-experimental/#adjusted-count) - for spans and count for others. [OTTL converters](https://pkg.go.dev/github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs#readme-converters) - can be used to transform the data. + then it defaults to the count of the signal. [OTTL converters](https://pkg.go.dev/github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs#readme-converters) + can be used to transform the data. For spans, a special converter [adjusted count](#custom-ottl-functions), + is provided to help calculte the span's [adjusted count](https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling-experimental/#adjusted-count). - [**Required**] `value` represents an OTTL expression to extract the value to be recorded in the histogram from the incoming data. [OTTL converters](https://pkg.go.dev/github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs#readme-converters) can be used to transform the data. @@ -124,13 +124,13 @@ exponential_histogram: - [**Optional**] `max_size` represents the maximum number of buckets per positive or negative number range. Defaults to `160`. - [**Optional**] `count` represents an OTTL expression to extract the count to be - recorded in the exponential histogram from the incoming data. If no expression - is provided then it defaults to the count of the signal i.e. [adjusted count](https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling-experimental/#adjusted-count) - for spans and count for others. - [OTTL converters](https://pkg.go.dev/github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs#readme-converters) can be used to transform the data. -- [**Required**] `value` represents an OTTL expression to extract the value to be recorded - in the exponential histogram from the incoming data. - [OTTL converters](https://pkg.go.dev/github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs#readme-converters) can be used to transform the data. + recorded in the expoential histogram from the incoming data. If no expression + is provided then it defaults to the count of the signal. [OTTL converters](https://pkg.go.dev/github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs#readme-converters) + can be used to transform the data. For spans, a special converter [adjusted count](#custom-ottl-functions), + is provided to help calculte the span's [adjusted count](https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling-experimental/#adjusted-count). +- [**Required**] `value` represents an OTTL expression to extract the value to be + recorded in the exponential histogram from the incoming data. [OTTL converters](https://pkg.go.dev/github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs#readme-converters) + can be used to transform the data. ### Attributes @@ -225,3 +225,12 @@ signaltometrics.service.name: signaltometrics.service.namespace: signaltometrics.service.instance.id: ``` + +### Custom OTTL functions + +The component implements a couple of custom OTTL functions: + +1. `AdjustedCount`: a converter capable of calculating [adjusted count for a span](https://github.com/open-telemetry/oteps/blob/main/text/trace/0235-sampling-threshold-in-trace-state.md). +2. `get`: a temporary solution to parse OTTL expressions with only values. This is +only for internal usage and MUST NOT be used explicitly as it is a stopgap measure +([see this for more details](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/35621)). diff --git a/connector/signaltometricsconnector/config/config.go b/connector/signaltometricsconnector/config/config.go index 7a2beb6787c8..582afd1b7a2f 100644 --- a/connector/signaltometricsconnector/config/config.go +++ b/connector/signaltometricsconnector/config/config.go @@ -3,7 +3,38 @@ package config // import "github.com/open-telemetry/opentelemetry-collector-contrib/connector/signaltometricsconnector/config" -import "fmt" +import ( + "errors" + "fmt" + + "github.com/lightstep/go-expohisto/structure" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/confmap" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.uber.org/zap" + + "github.com/open-telemetry/opentelemetry-collector-contrib/connector/signaltometricsconnector/internal/customottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottldatapoint" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottllog" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlspan" +) + +const ( + // defaultExponentialHistogramMaxSize is the default maximum number + // of buckets per positive or negative number range. 160 buckets + // default supports a high-resolution histogram able to cover a + // long-tail latency distribution from 1ms to 100s with a relative + // error of less than 5%. + // Ref: https://opentelemetry.io/docs/specs/otel/metrics/sdk/#base2-exponential-bucket-histogram-aggregation + defaultExponentialHistogramMaxSize = 160 +) + +var defaultHistogramBuckets = []float64{ + 2, 4, 6, 8, 10, 50, 100, 200, 400, 800, 1000, 1400, 2000, 5000, 10_000, 15_000, +} + +var _ confmap.Unmarshaler = (*Config)(nil) // Config for the connector. Each configuration field describes the metrics // to produce from a specific signal. @@ -17,9 +48,98 @@ func (c *Config) Validate() error { if len(c.Spans) == 0 && len(c.Datapoints) == 0 && len(c.Logs) == 0 { return fmt.Errorf("no configuration provided, at least one should be specified") } + var multiError error // collect all errors at once + if len(c.Spans) > 0 { + parser, err := ottlspan.NewParser( + customottl.SpanFuncs(), + component.TelemetrySettings{Logger: zap.NewNop()}, + ) + if err != nil { + return fmt.Errorf("failed to create parser for OTTL spans: %w", err) + } + for _, span := range c.Spans { + if err := validateMetricInfo(span, parser); err != nil { + multiError = errors.Join(multiError, fmt.Errorf("failed to validate spans configuration: %w", err)) + } + } + } + if len(c.Datapoints) > 0 { + parser, err := ottldatapoint.NewParser( + customottl.DatapointFuncs(), + component.TelemetrySettings{Logger: zap.NewNop()}, + ) + if err != nil { + return fmt.Errorf("failed to create parser for OTTL datapoints: %w", err) + } + for _, dp := range c.Datapoints { + if err := validateMetricInfo(dp, parser); err != nil { + multiError = errors.Join(multiError, fmt.Errorf("failed to validate datapoints configuration: %w", err)) + } + } + } + if len(c.Logs) > 0 { + parser, err := ottllog.NewParser( + customottl.LogFuncs(), + component.TelemetrySettings{Logger: zap.NewNop()}, + ) + if err != nil { + return fmt.Errorf("failed to create parser for OTTL logs: %w", err) + } + for _, log := range c.Logs { + if err := validateMetricInfo(log, parser); err != nil { + multiError = errors.Join(multiError, fmt.Errorf("failed to validate logs configuration: %w", err)) + } + } + } + return multiError +} + +// Unmarshal implements the confmap.Unmarshaler interface. It allows +// unmarshaling the config with a custom logic to allow setting +// default values when/if required. +func (c *Config) Unmarshal(collectorCfg *confmap.Conf) error { + if collectorCfg == nil { + return nil + } + if err := collectorCfg.Unmarshal(c, confmap.WithIgnoreUnused()); err != nil { + return err + } + for i, info := range c.Spans { + info.ensureDefaults() + c.Spans[i] = info + } + for i, info := range c.Datapoints { + info.ensureDefaults() + c.Datapoints[i] = info + } + for i, info := range c.Logs { + info.ensureDefaults() + c.Logs[i] = info + } return nil } +type Attribute struct { + Key string `mapstructure:"key"` + DefaultValue any `mapstructure:"default_value"` +} + +type Histogram struct { + Buckets []float64 `mapstructure:"buckets"` + Count string `mapstructure:"count"` + Value string `mapstructure:"value"` +} + +type ExponentialHistogram struct { + MaxSize int32 `mapstructure:"max_size"` + Count string `mapstructure:"count"` + Value string `mapstructure:"value"` +} + +type Sum struct { + Value string `mapstructure:"value"` +} + // MetricInfo defines the structure of the metric produced by the connector. type MetricInfo struct { Name string `mapstructure:"name"` @@ -40,23 +160,120 @@ type MetricInfo struct { Sum *Sum `mapstructure:"sum"` } -type Attribute struct { - Key string `mapstructure:"key"` - DefaultValue any `mapstructure:"default_value"` +func (mi *MetricInfo) ensureDefaults() { + if mi.Histogram != nil { + // Add default buckets if explicit histogram is defined + if len(mi.Histogram.Buckets) == 0 { + mi.Histogram.Buckets = defaultHistogramBuckets + } + } + if mi.ExponentialHistogram != nil { + if mi.ExponentialHistogram.MaxSize == 0 { + mi.ExponentialHistogram.MaxSize = defaultExponentialHistogramMaxSize + } + } } -type Histogram struct { - Buckets []float64 `mapstructure:"buckets"` - Count string `mapstructure:"count"` - Value string `mapstructure:"value"` +func (mi *MetricInfo) validateAttributes() error { + tmp := pcommon.NewValueEmpty() + duplicate := map[string]struct{}{} + for _, attr := range mi.Attributes { + if attr.Key == "" { + return fmt.Errorf("attribute key missing") + } + if _, ok := duplicate[attr.Key]; ok { + return fmt.Errorf("duplicate key found in attributes config: %s", attr.Key) + } + if err := tmp.FromRaw(attr.DefaultValue); err != nil { + return fmt.Errorf("invalid default value specified for attribute %s", attr.Key) + } + duplicate[attr.Key] = struct{}{} + } + return nil } -type ExponentialHistogram struct { - MaxSize int32 `mapstructure:"max_size"` - Count string `mapstructure:"count"` - Value string `mapstructure:"value"` +func (mi *MetricInfo) validateHistogram() error { + if mi.Histogram != nil { + if len(mi.Histogram.Buckets) == 0 { + return errors.New("histogram buckets missing") + } + if mi.Histogram.Value == "" { + return errors.New("value OTTL statement is required") + } + } + if mi.ExponentialHistogram != nil { + if _, err := structure.NewConfig( + structure.WithMaxSize(mi.ExponentialHistogram.MaxSize), + ).Validate(); err != nil { + return err + } + if mi.ExponentialHistogram.Value == "" { + return errors.New("value OTTL statement is required") + } + } + return nil } -type Sum struct { - Value string `mapstructure:"value"` +func (mi *MetricInfo) validateSum() error { + if mi.Sum != nil { + if mi.Sum.Value == "" { + return errors.New("value must be defined for sum metrics") + } + } + return nil +} + +// validateMetricInfo is an utility method validate all supported metric +// types defined for the metric info including any ottl expressions. +func validateMetricInfo[K any](mi MetricInfo, parser ottl.Parser[K]) error { + if mi.Name == "" { + return errors.New("missing required metric name configuration") + } + if err := mi.validateAttributes(); err != nil { + return fmt.Errorf("attributes validation failed: %w", err) + } + if err := mi.validateHistogram(); err != nil { + return fmt.Errorf("histogram validation failed: %w", err) + } + if err := mi.validateSum(); err != nil { + return fmt.Errorf("sum validation failed: %w", err) + } + + // Exactly one metric should be defined + var ( + metricsDefinedCount int + statements []string + ) + if mi.Histogram != nil { + metricsDefinedCount++ + if mi.Histogram.Count != "" { + statements = append(statements, customottl.ConvertToStatement(mi.Histogram.Count)) + } + statements = append(statements, customottl.ConvertToStatement(mi.Histogram.Value)) + } + if mi.ExponentialHistogram != nil { + metricsDefinedCount++ + if mi.ExponentialHistogram.Count != "" { + statements = append(statements, customottl.ConvertToStatement(mi.ExponentialHistogram.Count)) + } + statements = append(statements, customottl.ConvertToStatement(mi.ExponentialHistogram.Value)) + } + if mi.Sum != nil { + metricsDefinedCount++ + statements = append(statements, customottl.ConvertToStatement(mi.Sum.Value)) + } + if metricsDefinedCount != 1 { + return fmt.Errorf("exactly one of the metrics must be defined, %d found", metricsDefinedCount) + } + + // validate OTTL statements, note that, here we only evalaute if statements + // are valid. Check for required statements is left to the other validations. + if _, err := parser.ParseStatements(statements); err != nil { + return fmt.Errorf("failed to parse OTTL statements: %w", err) + } + // validate OTTL conditions + if _, err := parser.ParseConditions(mi.Conditions); err != nil { + return fmt.Errorf("failed to parse OTTL conditions: %w", err) + } + return nil } diff --git a/connector/signaltometricsconnector/config/config_test.go b/connector/signaltometricsconnector/config/config_test.go index a542a189df5e..202fa4f70a3b 100644 --- a/connector/signaltometricsconnector/config/config_test.go +++ b/connector/signaltometricsconnector/config/config_test.go @@ -4,6 +4,7 @@ package config import ( + "fmt" "path/filepath" "testing" @@ -25,6 +26,148 @@ func TestConfig(t *testing.T) { path: "empty", errorMsgs: []string{"no configuration provided"}, }, + { + path: "without_name", + errorMsgs: []string{ + fullErrorForSignal(t, "spans", "missing required metric name"), + fullErrorForSignal(t, "datapoints", "missing required metric name"), + fullErrorForSignal(t, "logs", "missing required metric name"), + }, + }, + { + path: "no_key_attributes", + errorMsgs: []string{ + fullErrorForSignal(t, "spans", "attributes validation failed"), + fullErrorForSignal(t, "datapoints", "attributes validation failed"), + fullErrorForSignal(t, "logs", "attributes validation failed"), + }, + }, + { + path: "duplicate_attributes", + errorMsgs: []string{ + fullErrorForSignal(t, "spans", "attributes validation failed"), + fullErrorForSignal(t, "datapoints", "attributes validation failed"), + fullErrorForSignal(t, "logs", "attributes validation failed"), + }, + }, + { + path: "invalid_histogram", + errorMsgs: []string{ + fullErrorForSignal(t, "spans", "histogram validation failed"), + fullErrorForSignal(t, "datapoints", "histogram validation failed"), + fullErrorForSignal(t, "logs", "histogram validation failed"), + }, + }, + { + path: "invalid_exponential_histogram", + errorMsgs: []string{ + fullErrorForSignal(t, "spans", "histogram validation failed"), + fullErrorForSignal(t, "datapoints", "histogram validation failed"), + fullErrorForSignal(t, "logs", "histogram validation failed"), + }, + }, + { + path: "invalid_sum", + errorMsgs: []string{ + fullErrorForSignal(t, "spans", "sum validation failed"), + fullErrorForSignal(t, "datapoints", "sum validation failed"), + fullErrorForSignal(t, "logs", "sum validation failed"), + }, + }, + { + path: "multiple_metric", + errorMsgs: []string{ + fullErrorForSignal(t, "spans", "exactly one of the metrics must be defined"), + fullErrorForSignal(t, "datapoints", "exactly one of the metrics must be defined"), + fullErrorForSignal(t, "logs", "exactly one of the metrics must be defined"), + }, + }, + { + path: "invalid_ottl_statements", + errorMsgs: []string{ + fullErrorForSignal(t, "spans", "failed to parse OTTL statements"), + fullErrorForSignal(t, "datapoints", "failed to parse OTTL statements"), + fullErrorForSignal(t, "logs", "failed to parse OTTL statements"), + }, + }, + { + path: "invalid_ottl_conditions", + errorMsgs: []string{ + fullErrorForSignal(t, "spans", "failed to parse OTTL conditions"), + fullErrorForSignal(t, "datapoints", "failed to parse OTTL conditions"), + fullErrorForSignal(t, "logs", "failed to parse OTTL conditions"), + }, + }, + { + path: "valid_full", + expected: &Config{ + Spans: []MetricInfo{ + { + Name: "span.exp_histogram", + Description: "Exponential histogram", + Unit: "us", + IncludeResourceAttributes: []Attribute{{Key: "key.1", DefaultValue: "foo"}}, + Attributes: []Attribute{{Key: "key.2", DefaultValue: "bar"}}, + Conditions: []string{ + `attributes["some.optional.1"] != nil`, + `resource.attributes["some.optional.2"] != nil`, + }, + ExponentialHistogram: &ExponentialHistogram{ + MaxSize: 10, + Count: "1", + Value: "Microseconds(end_time - start_time)", + }, + }, + { + Name: "span.histogram", + Description: "Histogram", + Unit: "us", + IncludeResourceAttributes: []Attribute{{Key: "key.1", DefaultValue: "foo"}}, + Attributes: []Attribute{{Key: "key.2", DefaultValue: "bar"}}, + Conditions: []string{ + `attributes["some.optional.1"] != nil`, + `resource.attributes["some.optional.2"] != nil`, + }, + Histogram: &Histogram{ + Buckets: []float64{1.1, 11.1, 111.1}, + Count: "1", + Value: "Microseconds(end_time - start_time)", + }, + }, + }, + Datapoints: []MetricInfo{ + { + Name: "dp.sum", + Description: "Sum", + Unit: "ms", + IncludeResourceAttributes: []Attribute{{Key: "key.1", DefaultValue: "foo"}}, + Attributes: []Attribute{{Key: "key.2", DefaultValue: "bar"}}, + Conditions: []string{ + `attributes["some.optional.1"] != nil`, + `IsDouble(attributes["some.optional.1"])`, + }, + Sum: &Sum{ + Value: `attributes["some.optional.1"]`, + }, + }, + }, + Logs: []MetricInfo{ + { + Name: "log.sum", + Description: "Sum", + Unit: "1", + IncludeResourceAttributes: []Attribute{{Key: "key.1", DefaultValue: "foo"}}, + Attributes: []Attribute{{Key: "key.2", DefaultValue: "bar"}}, + Conditions: []string{ + `attributes["some.optional.1"] != nil`, + }, + Sum: &Sum{ + Value: "1", + }, + }, + }, + }, + }, } { t.Run(tc.path, func(t *testing.T) { dir := filepath.Join("..", "testdata", "configs") @@ -49,3 +192,16 @@ func TestConfig(t *testing.T) { }) } } + +const validationMsgFormat = "failed to validate %s configuration: %s" + +func fullErrorForSignal(t *testing.T, signal, errMsg string) string { + t.Helper() + + switch signal { + case "spans", "datapoints", "logs": + return fmt.Sprintf(validationMsgFormat, signal, errMsg) + default: + panic("unhandled signal type") + } +} diff --git a/connector/signaltometricsconnector/go.mod b/connector/signaltometricsconnector/go.mod index aafb7d98f0ea..250acc98656f 100644 --- a/connector/signaltometricsconnector/go.mod +++ b/connector/signaltometricsconnector/go.mod @@ -3,6 +3,9 @@ module github.com/open-telemetry/opentelemetry-collector-contrib/connector/signa go 1.22.0 require ( + github.com/lightstep/go-expohisto v1.0.0 + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl v0.115.0 + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.115.0 github.com/stretchr/testify v1.10.0 go.opentelemetry.io/collector/component v0.115.1-0.20241206185113-3f3e208e71b8 go.opentelemetry.io/collector/component/componenttest v0.115.1-0.20241206185113-3f3e208e71b8 @@ -18,38 +21,66 @@ require ( ) require ( + github.com/alecthomas/participle/v2 v2.1.1 // indirect + github.com/antchfx/xmlquery v1.4.2 // indirect + github.com/antchfx/xpath v1.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/elastic/go-grok v0.3.1 // indirect + github.com/elastic/lunes v0.1.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/iancoleman/strcase v0.3.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/knadh/koanf/maps v0.1.1 // indirect github.com/knadh/koanf/providers/confmap v0.1.0 // indirect github.com/knadh/koanf/v2 v2.1.2 // indirect + github.com/magefile/mage v1.15.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.115.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/ua-parser/uap-go v0.0.0-20240611065828-3a4781585db6 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.115.1-0.20241206185113-3f3e208e71b8 // indirect go.opentelemetry.io/collector/connector/connectorprofiles v0.115.1-0.20241206185113-3f3e208e71b8 // indirect go.opentelemetry.io/collector/consumer/consumerprofiles v0.115.1-0.20241206185113-3f3e208e71b8 // indirect go.opentelemetry.io/collector/internal/fanoutconsumer v0.115.1-0.20241206185113-3f3e208e71b8 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.115.1-0.20241206185113-3f3e208e71b8 // indirect go.opentelemetry.io/collector/pipeline/pipelineprofiles v0.115.1-0.20241206185113-3f3e208e71b8 // indirect + go.opentelemetry.io/collector/semconv v0.115.1-0.20241206185113-3f3e208e71b8 // indirect go.opentelemetry.io/otel v1.32.0 // indirect go.opentelemetry.io/otel/metric v1.32.0 // indirect go.opentelemetry.io/otel/sdk v1.32.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect go.opentelemetry.io/otel/trace v1.32.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.18.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect - google.golang.org/grpc v1.67.1 // indirect + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/grpc v1.68.1 // indirect google.golang.org/protobuf v1.35.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl => ../../pkg/ottl + +replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal => ../../internal/coreinternal + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil => ../../pkg/pdatautil + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest => ../../pkg/pdatatest + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden => ../../pkg/golden + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling => ../../pkg/sampling diff --git a/connector/signaltometricsconnector/go.sum b/connector/signaltometricsconnector/go.sum index e4c10db098d8..87c044bc0c9e 100644 --- a/connector/signaltometricsconnector/go.sum +++ b/connector/signaltometricsconnector/go.sum @@ -1,6 +1,20 @@ +github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0= +github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= +github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= +github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= +github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= +github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/antchfx/xmlquery v1.4.2 h1:MZKd9+wblwxfQ1zd1AdrTsqVaMjMCwow3IqkCSe00KA= +github.com/antchfx/xmlquery v1.4.2/go.mod h1:QXhvf5ldTuGqhd1SHNvvtlhhdQLks4dD0awIVhXIDTA= +github.com/antchfx/xpath v1.3.2 h1:LNjzlsSjinu3bQpw9hWMY9ocB80oLOWuQqFvO6xt51U= +github.com/antchfx/xpath v1.3.2/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/elastic/go-grok v0.3.1 h1:WEhUxe2KrwycMnlvMimJXvzRa7DoByJB4PVUIE1ZD/U= +github.com/elastic/go-grok v0.3.1/go.mod h1:n38ls8ZgOboZRgKcjMY8eFeZFMmcL9n2lP0iHhIDk64= +github.com/elastic/lunes v0.1.0 h1:amRtLPjwkWtzDF/RKzcEPMvSsSseLDLW+bnhfNSLRe4= +github.com/elastic/lunes v0.1.0/go.mod h1:xGphYIt3XdZRtyWosHQTErsQTd4OP1p9wsbVoHelrd4= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -8,13 +22,27 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= +github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -29,6 +57,10 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lightstep/go-expohisto v1.0.0 h1:UPtTS1rGdtehbbAF7o/dhkWLTDI73UifG8LbfQI7cA4= +github.com/lightstep/go-expohisto v1.0.0/go.mod h1:xDXD0++Mu2FOaItXtdDfksfgxfV0z1TMPa+e/EUd0cs= +github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= +github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -46,8 +78,11 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/ua-parser/uap-go v0.0.0-20240611065828-3a4781585db6 h1:SIKIoA4e/5Y9ZOl0DCe3eVMLPOQzJxgZpfdHHeauNTM= +github.com/ua-parser/uap-go v0.0.0-20240611065828-3a4781585db6/go.mod h1:BUbeWZiieNxAuuADTBNb3/aeje6on3DhU3rpWsQSB1E= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/collector/component v0.115.1-0.20241206185113-3f3e208e71b8 h1:PtCINrFFDFi6aJRv8toOvLoKzu4qtz389PVcFlP7ydE= go.opentelemetry.io/collector/component v0.115.1-0.20241206185113-3f3e208e71b8/go.mod h1:oIUFiH7w1eOimdeYhFI+gAIxYSiLDocKVJ0PTvX7d6s= go.opentelemetry.io/collector/component/componenttest v0.115.1-0.20241206185113-3f3e208e71b8 h1:Bic9twYk1GtkTNvzlt9rPCJEavRc5QYdSTN6Ug3hi9Q= @@ -80,6 +115,8 @@ go.opentelemetry.io/collector/pipeline v0.115.1-0.20241206185113-3f3e208e71b8 h1 go.opentelemetry.io/collector/pipeline v0.115.1-0.20241206185113-3f3e208e71b8/go.mod h1:qE3DmoB05AW0C3lmPvdxZqd/H4po84NPzd5MrqgtL74= go.opentelemetry.io/collector/pipeline/pipelineprofiles v0.115.1-0.20241206185113-3f3e208e71b8 h1:tQ1srHl0/Y4yBL0LnJi9sRd6FDdonqdQNjrsBX/IY2w= go.opentelemetry.io/collector/pipeline/pipelineprofiles v0.115.1-0.20241206185113-3f3e208e71b8/go.mod h1:2Myg+law/5lcezo9PhhZ0wjCaLYdGK24s1jDWbSW9VY= +go.opentelemetry.io/collector/semconv v0.115.1-0.20241206185113-3f3e208e71b8 h1:+vUVC+FHqapool6OqgMQgc4oEjXrHyvDsvi4hEpBVLE= +go.opentelemetry.io/collector/semconv v0.115.1-0.20241206185113-3f3e208e71b8/go.mod h1:N6XE8Q0JKgBN2fAhkUQtqK9LT7rEGR6+Wu/Rtbal1iI= go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= @@ -99,42 +136,64 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0= +google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/connector/signaltometricsconnector/internal/customottl/adjustedcount.go b/connector/signaltometricsconnector/internal/customottl/adjustedcount.go new file mode 100644 index 000000000000..84c08441964d --- /dev/null +++ b/connector/signaltometricsconnector/internal/customottl/adjustedcount.go @@ -0,0 +1,41 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package customottl // import "github.com/open-telemetry/opentelemetry-collector-contrib/connector/signaltometricsconnector/internal/customottl" + +import ( + "context" + "fmt" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlspan" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling" +) + +func NewAdjustedCountFactory() ottl.Factory[ottlspan.TransformContext] { + return ottl.NewFactory("AdjustedCount", nil, createAdjustedCountFunction) +} + +func createAdjustedCountFunction(_ ottl.FunctionContext, _ ottl.Arguments) (ottl.ExprFunc[ottlspan.TransformContext], error) { + return adjustedCount() +} + +func adjustedCount() (ottl.ExprFunc[ottlspan.TransformContext], error) { + return func(_ context.Context, tCtx ottlspan.TransformContext) (any, error) { + tracestate := tCtx.GetSpan().TraceState().AsRaw() + w3cTraceState, err := sampling.NewW3CTraceState(tracestate) + if err != nil { + return float64(0), fmt.Errorf("failed to parse w3c tracestate: %w", err) + } + otTraceState := w3cTraceState.OTelValue() + if otTraceState == nil { + // If otel trace state is missing, default to 1 + return float64(1), nil + } + if len(otTraceState.TValue()) == 0 { + // For non-probabilistic sampler OR always sampling threshold, default to 1 + return float64(1), nil + } + return otTraceState.AdjustedCount(), nil + }, nil +} diff --git a/connector/signaltometricsconnector/internal/customottl/adjustedcount_test.go b/connector/signaltometricsconnector/internal/customottl/adjustedcount_test.go new file mode 100644 index 000000000000..63cb778564db --- /dev/null +++ b/connector/signaltometricsconnector/internal/customottl/adjustedcount_test.go @@ -0,0 +1,51 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package customottl + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/ptrace" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlspan" +) + +func Test_AdjustedCount(t *testing.T) { + for _, tc := range []struct { + tracestate string + want float64 + errMsg string + }{ + {tracestate: "", want: 1}, + {tracestate: "invalid=p:8;th:8", want: 1}, // otel trace state nil, default to 1 + {tracestate: "ot=notfound:8", want: 1}, // otel tvalue 0, default to 1 + {tracestate: "ot=404:0", errMsg: "failed to parse"}, // invalid syntax + {tracestate: "ot=th:0", want: 1}, // 100% sampling + {tracestate: "ot=th:8", want: 2}, // 50% sampling + {tracestate: "ot=th:c", want: 4}, // 25% sampling + } { + t.Run("tracestate/"+tc.tracestate, func(t *testing.T) { + exprFunc, err := adjustedCount() + require.NoError(t, err) + span := ptrace.NewSpan() + span.TraceState().FromRaw(tc.tracestate) + result, err := exprFunc(nil, ottlspan.NewTransformContext( + span, + pcommon.NewInstrumentationScope(), + pcommon.NewResource(), + ptrace.NewScopeSpans(), + ptrace.NewResourceSpans(), + )) + if tc.errMsg != "" { + require.ErrorContains(t, err, tc.errMsg) + return + } + require.NoError(t, err) + assert.Equal(t, tc.want, result) + }) + } +} diff --git a/connector/signaltometricsconnector/internal/customottl/funcs.go b/connector/signaltometricsconnector/internal/customottl/funcs.go new file mode 100644 index 000000000000..6e75edf7b94e --- /dev/null +++ b/connector/signaltometricsconnector/internal/customottl/funcs.go @@ -0,0 +1,34 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package customottl // import "github.com/open-telemetry/opentelemetry-collector-contrib/connector/signaltometricsconnector/internal/customottl" + +import ( + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottldatapoint" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottllog" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlspan" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs" +) + +func SpanFuncs() map[string]ottl.Factory[ottlspan.TransformContext] { + common := commonFuncs[ottlspan.TransformContext]() + adjustedCountFactory := NewAdjustedCountFactory() + common[adjustedCountFactory.Name()] = adjustedCountFactory + return common +} + +func DatapointFuncs() map[string]ottl.Factory[ottldatapoint.TransformContext] { + return commonFuncs[ottldatapoint.TransformContext]() +} + +func LogFuncs() map[string]ottl.Factory[ottllog.TransformContext] { + return commonFuncs[ottllog.TransformContext]() +} + +func commonFuncs[K any]() map[string]ottl.Factory[K] { + getFactory := NewGetFactory[K]() + standard := ottlfuncs.StandardFuncs[K]() + standard[getFactory.Name()] = getFactory + return standard +} diff --git a/connector/signaltometricsconnector/internal/customottl/get.go b/connector/signaltometricsconnector/internal/customottl/get.go new file mode 100644 index 000000000000..811196b7ba0d --- /dev/null +++ b/connector/signaltometricsconnector/internal/customottl/get.go @@ -0,0 +1,46 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package customottl // import "github.com/open-telemetry/opentelemetry-collector-contrib/connector/signaltometricsconnector/internal/customottl" + +import ( + "context" + "fmt" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" +) + +// Get is a temporary OTTL editor to allow statements to return values. This +// will be removed after OTTL can parse data retrival expressions: +// See: https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/35621 + +type GetArguments[K any] struct { + Value ottl.Getter[K] +} + +func NewGetFactory[K any]() ottl.Factory[K] { + return ottl.NewFactory("get", &GetArguments[K]{}, createGetFunction[K]) +} + +func createGetFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) { + args, ok := oArgs.(*GetArguments[K]) + + if !ok { + return nil, fmt.Errorf("GetFactory args must be of type *GetArguments[K]") + } + + return get(args.Value), nil +} + +func get[K any](value ottl.Getter[K]) ottl.ExprFunc[K] { + return func(ctx context.Context, tCtx K) (any, error) { + return value.Get(ctx, tCtx) + } +} + +// ConvertToStatement converts ottl.Value to an OTTL statement. To do +// this, it uses a custom `get` editor. This is expected to be a +// temporary measure until value parsing is allowed by the OTTL pkg. +func ConvertToStatement(s string) string { + return fmt.Sprintf("get(%s)", s) +} diff --git a/connector/signaltometricsconnector/testdata/configs/duplicate_attributes.yaml b/connector/signaltometricsconnector/testdata/configs/duplicate_attributes.yaml new file mode 100644 index 000000000000..567631081e85 --- /dev/null +++ b/connector/signaltometricsconnector/testdata/configs/duplicate_attributes.yaml @@ -0,0 +1,25 @@ +signaltometrics: + spans: + - name: span.sum + attributes: + - key: key.1 + - key: key.1 + - key: key.2 + sum: + value: "1" + datapoints: + - name: dp.sum + attributes: + - key: key.1 + - key: key.1 + - key: key.2 + sum: + value: "1" + logs: + - name: log.sum + attributes: + - key: key.1 + - key: key.1 + - key: key.2 + sum: + value: "1" diff --git a/connector/signaltometricsconnector/testdata/configs/invalid_exponential_histogram.yaml b/connector/signaltometricsconnector/testdata/configs/invalid_exponential_histogram.yaml new file mode 100644 index 000000000000..fdc5fba7b1bf --- /dev/null +++ b/connector/signaltometricsconnector/testdata/configs/invalid_exponential_histogram.yaml @@ -0,0 +1,16 @@ +signaltometrics: + spans: + - name: span.sum + attributes: + - key: key.1 + exponential_histogram: {} + datapoints: + - name: dp.sum + attributes: + - key: key.1 + exponential_histogram: {} + logs: + - name: log.sum + attributes: + - key: key.1 + exponential_histogram: {} diff --git a/connector/signaltometricsconnector/testdata/configs/invalid_histogram.yaml b/connector/signaltometricsconnector/testdata/configs/invalid_histogram.yaml new file mode 100644 index 000000000000..f4dbf6feca55 --- /dev/null +++ b/connector/signaltometricsconnector/testdata/configs/invalid_histogram.yaml @@ -0,0 +1,16 @@ +signaltometrics: + spans: + - name: span.sum + attributes: + - key: key.1 + histogram: {} + datapoints: + - name: dp.sum + attributes: + - key: key.1 + histogram: {} + logs: + - name: log.sum + attributes: + - key: key.1 + histogram: {} diff --git a/connector/signaltometricsconnector/testdata/configs/invalid_ottl_conditions.yaml b/connector/signaltometricsconnector/testdata/configs/invalid_ottl_conditions.yaml new file mode 100644 index 000000000000..8963f831a39b --- /dev/null +++ b/connector/signaltometricsconnector/testdata/configs/invalid_ottl_conditions.yaml @@ -0,0 +1,25 @@ +signaltometrics: + spans: + - name: span.sum + attributes: + - key: key.1 + conditions: + - bad_condition + sum: + value: "1" + datapoints: + - name: dp.sum + attributes: + - key: key.1 + conditions: + - bad_condition + sum: + value: "1" + logs: + - name: log.sum + attributes: + - key: key.1 + conditions: + - bad_condition + sum: + value: "1" diff --git a/connector/signaltometricsconnector/testdata/configs/invalid_ottl_statements.yaml b/connector/signaltometricsconnector/testdata/configs/invalid_ottl_statements.yaml new file mode 100644 index 000000000000..9be4e452c90c --- /dev/null +++ b/connector/signaltometricsconnector/testdata/configs/invalid_ottl_statements.yaml @@ -0,0 +1,19 @@ +signaltometrics: + spans: + - name: span.sum + attributes: + - key: key.1 + sum: + value: bad_statement(1) + datapoints: + - name: dp.sum + attributes: + - key: key.1 + sum: + value: bad_statement(1) + logs: + - name: log.sum + attributes: + - key: key.1 + sum: + value: bad_statement(1) diff --git a/connector/signaltometricsconnector/testdata/configs/invalid_sum.yaml b/connector/signaltometricsconnector/testdata/configs/invalid_sum.yaml new file mode 100644 index 000000000000..391aba74d883 --- /dev/null +++ b/connector/signaltometricsconnector/testdata/configs/invalid_sum.yaml @@ -0,0 +1,16 @@ +signaltometrics: + spans: + - name: span.sum + attributes: + - key: key.1 + sum: {} + datapoints: + - name: dp.sum + attributes: + - key: key.1 + sum: {} + logs: + - name: log.sum + attributes: + - key: key.1 + sum: {} diff --git a/connector/signaltometricsconnector/testdata/configs/multiple_metric.yaml b/connector/signaltometricsconnector/testdata/configs/multiple_metric.yaml new file mode 100644 index 000000000000..a030275ba2e9 --- /dev/null +++ b/connector/signaltometricsconnector/testdata/configs/multiple_metric.yaml @@ -0,0 +1,31 @@ +signaltometrics: + spans: + - name: span.sum + attributes: + - key: key.1 + sum: + value: "1" + histogram: + value: "1" + exponential_histogram: + value: "1" + datapoints: + - name: dp.sum + attributes: + - key: key.1 + sum: + value: "1" + histogram: + value: "1" + exponential_histogram: + value: "1" + logs: + - name: log.sum + attributes: + - key: key.1 + sum: + value: "1" + histogram: + value: "1" + exponential_histogram: + value: "1" diff --git a/connector/signaltometricsconnector/testdata/configs/no_key_attributes.yaml b/connector/signaltometricsconnector/testdata/configs/no_key_attributes.yaml new file mode 100644 index 000000000000..a6522505d3ae --- /dev/null +++ b/connector/signaltometricsconnector/testdata/configs/no_key_attributes.yaml @@ -0,0 +1,19 @@ +signaltometrics: + spans: + - name: span.sum + attributes: + - default_value: key.1 + sum: + value: "1" + datapoints: + - name: dp.sum + attributes: + - default_value: key.1 + sum: + value: "1" + logs: + - name: log.sum + attributes: + - default_value: key.1 + sum: + value: "1" diff --git a/connector/signaltometricsconnector/testdata/configs/valid_full.yaml b/connector/signaltometricsconnector/testdata/configs/valid_full.yaml new file mode 100644 index 000000000000..a200ab878b11 --- /dev/null +++ b/connector/signaltometricsconnector/testdata/configs/valid_full.yaml @@ -0,0 +1,63 @@ +signaltometrics: + spans: + - name: span.exp_histogram + description: Exponential histogram + unit: us + include_resource_attributes: + - key: key.1 + default_value: foo + attributes: + - key: key.2 + default_value: bar + conditions: + - attributes["some.optional.1"] != nil + - resource.attributes["some.optional.2"] != nil + exponential_histogram: + max_size: 10 + value: Microseconds(end_time - start_time) + count: "1" + - name: span.histogram + description: Histogram + unit: us + include_resource_attributes: + - key: key.1 + default_value: foo + attributes: + - key: key.2 + default_value: bar + conditions: + - attributes["some.optional.1"] != nil + - resource.attributes["some.optional.2"] != nil + histogram: + buckets: [1.1, 11.1, 111.1] + value: Microseconds(end_time - start_time) + count: "1" + datapoints: + - name: dp.sum + description: Sum + unit: ms + include_resource_attributes: + - key: key.1 + default_value: foo + attributes: + - key: key.2 + default_value: bar + conditions: + - attributes["some.optional.1"] != nil + - IsDouble(attributes["some.optional.1"]) + sum: + value: attributes["some.optional.1"] + logs: + - name: log.sum + description: Sum + unit: "1" + include_resource_attributes: + - key: key.1 + default_value: foo + attributes: + - key: key.2 + default_value: bar + conditions: + - attributes["some.optional.1"] != nil + sum: + value: "1" diff --git a/connector/signaltometricsconnector/testdata/configs/without_name.yaml b/connector/signaltometricsconnector/testdata/configs/without_name.yaml new file mode 100644 index 000000000000..92f92ede0864 --- /dev/null +++ b/connector/signaltometricsconnector/testdata/configs/without_name.yaml @@ -0,0 +1,10 @@ +signaltometrics: + spans: + - sum: + value: "1" + datapoints: + - sum: + value: "1" + logs: + - sum: + value: "1" diff --git a/connector/signaltometricsconnector/testdata/traces/traces.yaml b/connector/signaltometricsconnector/testdata/traces/traces.yaml new file mode 100644 index 000000000000..bbf84f43b5fd --- /dev/null +++ b/connector/signaltometricsconnector/testdata/traces/traces.yaml @@ -0,0 +1,96 @@ +resourceSpans: + - resource: + attributes: + - key: resource.foo + value: + stringValue: foo + - key: resource.bar + value: + stringValue: bar + scopeSpans: + - scope: {} + spans: + - attributes: + - key: db.name + value: + stringValue: main + - key: db.system + value: + stringValue: mysql + endTimeUnixNano: "1581452772500000789" + name: db-span + parentSpanId: "" + startTimeUnixNano: "1581452772000000321" + - attributes: + - key: http.request.method + value: + stringValue: POST + - key: url.full + value: + stringValue: https://www.foo.bar/search?q=OpenTelemetry#SemConv + - key: http.response.status_code + value: + intValue: 201 + endTimeUnixNano: "1581452772900000789" + name: http-span + parentSpanId: "" + startTimeUnixNano: "1581452772000000321" + - attributes: + - key: messaging.system + value: + stringValue: kafka + - key: messaging.destination.name + value: + stringValue: TestTopic + endTimeUnixNano: "1581452772002000789" + name: msg-span + parentSpanId: "" + startTimeUnixNano: "1581452772000000321" + - attributes: + - key: db.name + value: + stringValue: main + - key: db.system + value: + stringValue: mysql + endTimeUnixNano: "1581452773000000789" + name: db-span-2 + parentSpanId: "bcff497b5a47310f" + startTimeUnixNano: "1581452772000000321" + - attributes: + - key: http.request.method + value: + stringValue: POST + - key: url.full + value: + stringValue: https://www.foo.bar/search?q=OpenTelemetry#SemConv + - key: http.response.status_code + value: + intValue: 201 + endTimeUnixNano: "1581452783000000789" + name: http-span-2 + parentSpanId: "bcff497b5a47310f" + startTimeUnixNano: "1581452772000000321" + - attributes: + - key: messaging.system + value: + stringValue: kafka + - key: messaging.destination.name + value: + stringValue: TestTopic + endTimeUnixNano: "1581452789000000789" + name: msg-span-2 + parentSpanId: "bcff497b5a47310f" + startTimeUnixNano: "1581452772000000321" + - attributes: + - key: db.name + value: + stringValue: main + - key: db.system + value: + stringValue: mysql + endTimeUnixNano: "1581452772500000804" + name: th-value-8 # represents 2 sampled spans + parentSpanId: "" + startTimeUnixNano: "1581452772000000381" + traceState: "ot=th:8"