From 74d4df127ea616cc8105193c050437d8d4eb29ab Mon Sep 17 00:00:00 2001 From: odubajDT Date: Thu, 31 Oct 2024 11:05:16 +0100 Subject: [PATCH] [processor/attributes] support Profile signal type Signed-off-by: odubajDT --- .../filter/filterprofile/filterprofile.go | 114 ++ .../filterprofile/filterprofile_test.go | 1395 +++++++++++++++++ internal/filter/filterprofile/package_test.go | 14 + pkg/ottl/contexts/ottlprofile/README.md | 0 pkg/ottl/contexts/ottlprofile/package_test.go | 14 + pkg/ottl/contexts/ottlprofile/profile.go | 544 +++++++ pkg/ottl/contexts/ottlprofile/profile_test.go | 4 + .../attributesprocessor/attributes_profile.go | 61 + processor/attributesprocessor/factory.go | 40 +- processor/attributesprocessor/go.mod | 20 +- processor/attributesprocessor/go.sum | 12 - .../internal/metadata/generated_status.go | 1 + processor/attributesprocessor/metadata.yaml | 1 + 13 files changed, 2198 insertions(+), 22 deletions(-) create mode 100644 internal/filter/filterprofile/filterprofile.go create mode 100644 internal/filter/filterprofile/filterprofile_test.go create mode 100644 internal/filter/filterprofile/package_test.go create mode 100644 pkg/ottl/contexts/ottlprofile/README.md create mode 100644 pkg/ottl/contexts/ottlprofile/package_test.go create mode 100644 pkg/ottl/contexts/ottlprofile/profile.go create mode 100644 pkg/ottl/contexts/ottlprofile/profile_test.go create mode 100644 processor/attributesprocessor/attributes_profile.go diff --git a/internal/filter/filterprofile/filterprofile.go b/internal/filter/filterprofile/filterprofile.go new file mode 100644 index 000000000000..6dd6e4b033d0 --- /dev/null +++ b/internal/filter/filterprofile/filterprofile.go @@ -0,0 +1,114 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package filterprofile // import "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterprofile" + +import ( + "context" + "fmt" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/expr" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterconfig" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filtermatcher" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterset" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlprofile" +) + +// NewSkipExpr creates a BoolExpr that on evaluation returns true if a log should NOT be processed or kept. +// The logic determining if a log should be processed is based on include and exclude settings. +// Include properties are checked before exclude settings are checked. +func NewSkipExpr(mp *filterconfig.MatchConfig) (expr.BoolExpr[ottlprofile.TransformContext], error) { + + var matchers []expr.BoolExpr[ottlprofile.TransformContext] + inclExpr, err := newExpr(mp.Include) + if err != nil { + return nil, err + } + if inclExpr != nil { + matchers = append(matchers, expr.Not(inclExpr)) + } + exclExpr, err := newExpr(mp.Exclude) + if err != nil { + return nil, err + } + if exclExpr != nil { + matchers = append(matchers, exclExpr) + } + return expr.Or(matchers...), nil +} + +// propertiesMatcher allows matching a log record against various log record properties. +type propertiesMatcher struct { + filtermatcher.PropertiesMatcher + + // log bodies to compare to. + bodyFilters filterset.FilterSet + + // log severity texts to compare to + severityTextFilters filterset.FilterSet + + // matcher for severity number + severityNumberMatcher *severityNumberMatcher +} + +// NewMatcher creates a LogRecord Matcher that matches based on the given MatchProperties. +func newExpr(mp *filterconfig.MatchProperties) (expr.BoolExpr[ottlprofile.TransformContext], error) { + if mp == nil { + return nil, nil + } + + if err := mp.ValidateForLogs(); err != nil { + return nil, err + } + + rm, err := filtermatcher.NewMatcher(mp) + if err != nil { + return nil, err + } + + var bodyFS filterset.FilterSet + if len(mp.LogBodies) > 0 { + bodyFS, err = filterset.CreateFilterSet(mp.LogBodies, &mp.Config) + if err != nil { + return nil, fmt.Errorf("error creating log record body filters: %w", err) + } + } + var severitytextFS filterset.FilterSet + if len(mp.LogSeverityTexts) > 0 { + severitytextFS, err = filterset.CreateFilterSet(mp.LogSeverityTexts, &mp.Config) + if err != nil { + return nil, fmt.Errorf("error creating log record severity text filters: %w", err) + } + } + + pm := &propertiesMatcher{ + PropertiesMatcher: rm, + bodyFilters: bodyFS, + severityTextFilters: severitytextFS, + } + + return pm, nil +} + +// Eval matches a log record to a set of properties. +// There are 3 sets of properties to match against. +// The log record names are matched, if specified. +// The log record bodies are matched, if specified. +// The attributes are then checked, if specified. +// At least one of log record names or attributes must be specified. It is +// supported to have more than one of these specified, and all specified must +// evaluate to true for a match to occur. +func (mp *propertiesMatcher) Eval(_ context.Context, tCtx ottlprofile.TransformContext) (bool, error) { + lr := tCtx.GetLogRecord() + if mp.bodyFilters != nil && !mp.bodyFilters.Matches(lr.Body().AsString()) { + return false, nil + } + if mp.severityTextFilters != nil && !mp.severityTextFilters.Matches(lr.SeverityText()) { + return false, nil + } + if mp.severityNumberMatcher != nil && !mp.severityNumberMatcher.match(lr) { + return false, nil + } + + return mp.PropertiesMatcher.Match(lr.Attributes(), tCtx.GetResource(), tCtx.GetInstrumentationScope()), nil +} diff --git a/internal/filter/filterprofile/filterprofile_test.go b/internal/filter/filterprofile/filterprofile_test.go new file mode 100644 index 000000000000..84df21c6d5cd --- /dev/null +++ b/internal/filter/filterprofile/filterprofile_test.go @@ -0,0 +1,1395 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package filterprofile + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/featuregate" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + conventions "go.opentelemetry.io/collector/semconv/v1.27.0" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterconfig" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterset" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottllog" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottltest" +) + +func createConfig(matchType filterset.MatchType) *filterset.Config { + return &filterset.Config{ + MatchType: matchType, + } +} + +func TestLogRecord_validateMatchesConfiguration_InvalidConfig(t *testing.T) { + testcases := []struct { + name string + property *filterconfig.MatchProperties + errorString string + }{ + { + name: "empty_property", + property: &filterconfig.MatchProperties{}, + errorString: filterconfig.ErrMissingRequiredLogField.Error(), + }, + { + name: "empty_log_bodies_and_attributes", + property: &filterconfig.MatchProperties{ + LogBodies: []string{}, + LogSeverityTexts: []string{}, + }, + errorString: filterconfig.ErrMissingRequiredLogField.Error(), + }, + { + name: "span_properties", + property: &filterconfig.MatchProperties{ + SpanNames: []string{"span"}, + }, + errorString: filterconfig.ErrInvalidLogField.Error(), + }, + { + name: "invalid_match_type", + property: &filterconfig.MatchProperties{ + Config: *createConfig("wrong_match_type"), + Attributes: []filterconfig.Attribute{{Key: "abc", Value: "def"}}, + }, + errorString: "error creating attribute filters: unrecognized match_type: 'wrong_match_type', valid types are: [regexp strict]", + }, + { + name: "missing_match_type", + property: &filterconfig.MatchProperties{ + Attributes: []filterconfig.Attribute{{Key: "abc", Value: "def"}}, + }, + errorString: "error creating attribute filters: unrecognized match_type: '', valid types are: [regexp strict]", + }, + { + name: "invalid_regexp_pattern", + property: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + Attributes: []filterconfig.Attribute{{Key: "abc", Value: "["}}, + }, + errorString: "error creating attribute filters: error parsing regexp: missing closing ]: `[`", + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + expr, err := newExpr(tc.property) + assert.Nil(t, expr) + require.Error(t, err) + println(tc.name) + assert.Equal(t, tc.errorString, err.Error()) + }) + } +} + +func TestLogRecord_Matching_False(t *testing.T) { + testcases := []struct { + name string + properties *filterconfig.MatchProperties + }{ + { + name: "attributes_dont_match", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + Attributes: []filterconfig.Attribute{ + {Key: "abc", Value: "def"}, + }, + }, + }, + + { + name: "attributes_dont_match_regex", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + Attributes: []filterconfig.Attribute{ + {Key: "ab.*c", Value: "def"}, + }, + }, + }, + { + name: "log_severity_text_regexp_dont_match", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + LogSeverityTexts: []string{"debug.*"}, + }, + }, + { + name: "log_min_severity_trace_dont_match", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + Min: plog.SeverityNumberInfo, + }, + }, + }, + { + name: "log_body_doesnt_match", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + LogBodies: []string{".*TEST.*"}, + }, + }, + } + + lr := plog.NewLogRecord() + lr.SetSeverityNumber(plog.SeverityNumberTrace) + lr.Body().SetStr("AUTHENTICATION FAILED") + + lrm := plog.NewLogRecord() + lrm.Body().SetEmptyMap() + lrm.Body().Map().PutStr("message", "AUTHENTICATION FAILED") + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + expr, err := newExpr(tc.properties) + assert.NoError(t, err) + require.NotNil(t, expr) + + val, err := expr.Eval(context.Background(), ottllog.NewTransformContext(lr, pcommon.NewInstrumentationScope(), pcommon.NewResource(), plog.NewScopeLogs(), plog.NewResourceLogs())) + require.NoError(t, err) + assert.False(t, val) + + val, err = expr.Eval(context.Background(), ottllog.NewTransformContext(lrm, pcommon.NewInstrumentationScope(), pcommon.NewResource(), plog.NewScopeLogs(), plog.NewResourceLogs())) + require.NoError(t, err) + assert.False(t, val) + }) + } +} + +func TestLogRecord_Matching_True(t *testing.T) { + testcases := []struct { + name string + properties *filterconfig.MatchProperties + }{ + { + name: "attribute_strict_match", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Strict), + Attributes: []filterconfig.Attribute{{Key: "abc", Value: "def"}}, + }, + }, + { + name: "attribute_regex_match", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + Attributes: []filterconfig.Attribute{ + {Key: "abc", Value: "d.f"}, + }, + }, + }, + { + name: "log_body_regexp_match", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + LogBodies: []string{"AUTH.*"}, + }, + }, + { + name: "log_severity_text_regexp_match", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + LogSeverityTexts: []string{"debug.*"}, + }, + }, + { + name: "log_min_severity_match", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + Min: plog.SeverityNumberDebug, + }, + }, + }, + } + + lr := plog.NewLogRecord() + lr.Attributes().PutStr("abc", "def") + lr.Body().SetStr("AUTHENTICATION FAILED") + lr.SetSeverityText("debug") + lr.SetSeverityNumber(plog.SeverityNumberDebug) + + lrm := plog.NewLogRecord() + lrm.Attributes().PutStr("abc", "def") + lrm.Body().SetEmptyMap() + lrm.Body().Map().PutStr("message", "AUTHENTICATION FAILED") + lrm.SetSeverityText("debug") + lrm.SetSeverityNumber(plog.SeverityNumberDebug) + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + expr, err := newExpr(tc.properties) + assert.NoError(t, err) + require.NotNil(t, expr) + + assert.NotNil(t, lr) + val, err := expr.Eval(context.Background(), ottllog.NewTransformContext(lr, pcommon.NewInstrumentationScope(), pcommon.NewResource(), plog.NewScopeLogs(), plog.NewResourceLogs())) + require.NoError(t, err) + assert.True(t, val) + + assert.NotNil(t, lrm) + val, err = expr.Eval(context.Background(), ottllog.NewTransformContext(lrm, pcommon.NewInstrumentationScope(), pcommon.NewResource(), plog.NewScopeLogs(), plog.NewResourceLogs())) + require.NoError(t, err) + assert.True(t, val) + }) + } +} + +func Test_NewSkipExpr_With_Bridge(t *testing.T) { + tests := []struct { + name string + condition *filterconfig.MatchConfig + logSeverity plog.SeverityNumber + }{ + // Body + { + name: "single static body include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogBodies: []string{"body"}, + }, + }, + }, + { + name: "multiple static body include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogBodies: []string{"hand", "foot"}, + }, + }, + }, + { + name: "single regex body include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + LogBodies: []string{"bod.*"}, + }, + }, + }, + { + name: "multiple regex body include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + LogBodies: []string{"hand.*", "foot.*"}, + }, + }, + }, + { + name: "single static body exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogBodies: []string{"body"}, + }, + }, + }, + { + name: "multiple static body exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogBodies: []string{"hand", "foot"}, + }, + }, + }, + { + name: "single regex body exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + LogBodies: []string{"bod.*"}, + }, + }, + }, + { + name: "multiple regex body exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + LogBodies: []string{"hand.*", "foot.*"}, + }, + }, + }, + + // Severity text + { + name: "single static severity text include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityTexts: []string{"severity text"}, + }, + }, + }, + { + name: "multiple static severity text include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityTexts: []string{"not", "correct"}, + }, + }, + }, + { + name: "single regex severity text include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + LogSeverityTexts: []string{"severity.*"}, + }, + }, + }, + { + name: "multiple regex severity text include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + LogSeverityTexts: []string{"not.*", "correct.*"}, + }, + }, + }, + { + name: "single static severity text exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityTexts: []string{"severity text"}, + }, + }, + }, + { + name: "multiple static severity text exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityTexts: []string{"not", "correct"}, + }, + }, + }, + { + name: "single regex severity text exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + LogSeverityTexts: []string{"severity.*"}, + }, + }, + }, + { + name: "multiple regex severity text exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + LogSeverityTexts: []string{"not.*", "correct.*"}, + }, + }, + }, + + // Severity number + { + name: "severity number unspecified, match unspecified true, min unspecified, include", + logSeverity: plog.SeverityNumberUnspecified, + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: true, + Min: plog.SeverityNumberUnspecified, + }, + }, + }, + }, + { + name: "severity number unspecified, match unspecified true, min info, include", + logSeverity: plog.SeverityNumberUnspecified, + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: true, + Min: plog.SeverityNumberInfo, + }, + }, + }, + }, + { + name: "severity number unspecified, match unspecified false, min unspecified, include", + logSeverity: plog.SeverityNumberUnspecified, + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: false, + Min: plog.SeverityNumberUnspecified, + }, + }, + }, + }, + { + name: "severity number unspecified, match unspecified false, min info, include", + logSeverity: plog.SeverityNumberUnspecified, + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: false, + Min: plog.SeverityNumberInfo, + }, + }, + }, + }, + { + name: "severity number not unspecified, match unspecified true, min info, include", + logSeverity: plog.SeverityNumberInfo, + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: true, + Min: plog.SeverityNumberInfo, + }, + }, + }, + }, + { + name: "severity number not unspecified, match unspecified true, min fatal, include", + logSeverity: plog.SeverityNumberInfo, + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: true, + Min: plog.SeverityNumberFatal, + }, + }, + }, + }, + { + name: "severity number not unspecified, match unspecified false, min info, include", + logSeverity: plog.SeverityNumberInfo, + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: false, + Min: plog.SeverityNumberInfo, + }, + }, + }, + }, + { + name: "severity number not unspecified, match unspecified false, min fatal, include", + logSeverity: plog.SeverityNumberInfo, + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: false, + Min: plog.SeverityNumberFatal, + }, + }, + }, + }, + { + name: "severity number unspecified, match unspecified true, min unspecified, exclude", + logSeverity: plog.SeverityNumberUnspecified, + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: true, + Min: plog.SeverityNumberUnspecified, + }, + }, + }, + }, + { + name: "severity number unspecified, match unspecified true, min info, exclude", + logSeverity: plog.SeverityNumberUnspecified, + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: true, + Min: plog.SeverityNumberInfo, + }, + }, + }, + }, + { + name: "severity number unspecified, match unspecified false, min unspecified, exclude", + logSeverity: plog.SeverityNumberUnspecified, + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: false, + Min: plog.SeverityNumberUnspecified, + }, + }, + }, + }, + { + name: "severity number unspecified, match unspecified false, min info, exclude", + logSeverity: plog.SeverityNumberUnspecified, + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: false, + Min: plog.SeverityNumberInfo, + }, + }, + }, + }, + { + name: "severity number not unspecified, match unspecified true, min info, exclude", + logSeverity: plog.SeverityNumberInfo, + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: true, + Min: plog.SeverityNumberInfo, + }, + }, + }, + }, + { + name: "severity number not unspecified, match unspecified true, min fatal, exclude", + logSeverity: plog.SeverityNumberInfo, + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: true, + Min: plog.SeverityNumberFatal, + }, + }, + }, + }, + { + name: "severity number not unspecified, match unspecified false, min info, exclude", + logSeverity: plog.SeverityNumberInfo, + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: false, + Min: plog.SeverityNumberInfo, + }, + }, + }, + }, + { + name: "severity number not unspecified, match unspecified false, min fatal, exclude", + logSeverity: plog.SeverityNumberInfo, + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: false, + Min: plog.SeverityNumberFatal, + }, + }, + }, + }, + + // Scope name + { + name: "single static scope name include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + }, + }, + }, + }, + }, + { + name: "multiple static scope name include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "foo", + }, + { + Name: "bar", + }, + }, + }, + }, + }, + { + name: "single regex scope name include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + }, + }, + }, + }, + }, + { + name: "multiple regex scope name include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "foo.*", + }, + { + Name: "bar.*", + }, + }, + }, + }, + }, + { + name: "single static scope name exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + }, + }, + }, + }, + }, + { + name: "multiple static scope name exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "foo", + }, + { + Name: "bar", + }, + }, + }, + }, + }, + { + name: "single regex scope name exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + }, + }, + }, + }, + }, + { + name: "multiple regex scope name exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "foo.*", + }, + { + Name: "bar.*", + }, + }, + }, + }, + }, + + // Scope version + { + name: "single static scope version include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + Version: ottltest.Strp("0.1.0"), + }, + }, + }, + }, + }, + { + name: "multiple static scope version include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + Version: ottltest.Strp("2.0.0"), + }, + { + Name: "scope", + Version: ottltest.Strp(`1.1.0`), + }, + }, + }, + }, + }, + { + name: "single regex scope version include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + Version: ottltest.Strp("0.*"), + }, + }, + }, + }, + }, + { + name: "multiple regex scope version include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + Version: ottltest.Strp("2.*"), + }, + { + Name: "scope", + Version: ottltest.Strp("^1\\\\.1.*"), + }, + }, + }, + }, + }, + { + name: "single static scope version exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + Version: ottltest.Strp("0.1.0"), + }, + }, + }, + }, + }, + { + name: "multiple static scope version exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + Version: ottltest.Strp("2.0.0"), + }, + { + Name: "scope", + Version: ottltest.Strp(`1.1.0`), + }, + }, + }, + }, + }, + { + name: "single regex scope version exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + Version: ottltest.Strp("0.*"), + }, + }, + }, + }, + }, + { + name: "multiple regex scope version exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + Version: ottltest.Strp("2.*"), + }, + { + Name: "scope", + Version: ottltest.Strp(`1\\.1.*`), + }, + }, + }, + }, + }, + + // attributes + { + name: "single static attribute include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Attributes: []filterconfig.Attribute{ + { + Key: "attr1", + Value: "val1", + }, + }, + }, + }, + }, + { + name: "multiple static attribute include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + + Attributes: []filterconfig.Attribute{ + { + Key: "attr1", + Value: "val2", + }, + { + Key: "attr2", + Value: "val2", + }, + }, + }, + }, + }, + { + name: "single regex attribute include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Attributes: []filterconfig.Attribute{ + { + Key: "attr1", + Value: "val.*", + }, + }, + }, + }, + }, + { + name: "multiple regex attribute include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Attributes: []filterconfig.Attribute{ + { + Key: "attr1", + Value: "val", + }, + { + Key: "attr3", + Value: "val.*", + }, + }, + }, + }, + }, + { + name: "single static attribute exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Attributes: []filterconfig.Attribute{ + { + Key: "attr1", + Value: "val1", + }, + }, + }, + }, + }, + { + name: "multiple static attribute exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + + Attributes: []filterconfig.Attribute{ + { + Key: "attr1", + Value: "val2", + }, + { + Key: "attr2", + Value: "val2", + }, + }, + }, + }, + }, + { + name: "single regex attribute exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Attributes: []filterconfig.Attribute{ + { + Key: "attr1", + Value: "val.*", + }, + }, + }, + }, + }, + { + name: "multiple regex attribute exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Attributes: []filterconfig.Attribute{ + { + Key: "attr1", + Value: "val", + }, + { + Key: "attr3", + Value: "val.*", + }, + }, + }, + }, + }, + + // resource attributes + { + name: "single static resource attribute include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Resources: []filterconfig.Attribute{ + { + Key: "service.name", + Value: "svcA", + }, + }, + }, + }, + }, + { + name: "multiple static resource attribute include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + + Resources: []filterconfig.Attribute{ + { + Key: "service.name", + Value: "svc2", + }, + { + Key: "service.version", + Value: "v1", + }, + }, + }, + }, + }, + { + name: "single regex resource attribute include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Resources: []filterconfig.Attribute{ + { + Key: "service.name", + Value: "svc.*", + }, + }, + }, + }, + }, + { + name: "multiple regex resource attribute include", + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Resources: []filterconfig.Attribute{ + { + Key: "service.name", + Value: ".*2", + }, + { + Key: "service.name", + Value: ".*3", + }, + }, + }, + }, + }, + { + name: "single static resource attribute exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + Resources: []filterconfig.Attribute{ + { + Key: "service.name", + Value: "svcA", + }, + }, + }, + }, + }, + { + name: "multiple static resource attribute exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + + Resources: []filterconfig.Attribute{ + { + Key: "service.name", + Value: "svc2", + }, + { + Key: "service.version", + Value: "v1", + }, + }, + }, + }, + }, + { + name: "single regex resource attribute exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Resources: []filterconfig.Attribute{ + { + Key: "service.name", + Value: "svc.*", + }, + }, + }, + }, + }, + { + name: "multiple regex resource attribute exclude", + condition: &filterconfig.MatchConfig{ + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + Resources: []filterconfig.Attribute{ + { + Key: "service.name", + Value: ".*2", + }, + { + Key: "service.name", + Value: ".*3", + }, + }, + }, + }, + }, + + // complex + { + name: "complex", + logSeverity: plog.SeverityNumberDebug, + condition: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Regexp, + }, + LogBodies: []string{"body"}, + LogSeverityTexts: []string{"severity text"}, + Libraries: []filterconfig.InstrumentationLibrary{ + { + Name: "scope", + Version: ottltest.Strp("0.1.0"), + }, + }, + Resources: []filterconfig.Attribute{ + { + Key: "service.name", + Value: "svcA", + }, + }, + }, + Exclude: &filterconfig.MatchProperties{ + Config: filterset.Config{ + MatchType: filterset.Strict, + }, + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + MatchUndefined: false, + Min: plog.SeverityNumberInfo, + }, + Attributes: []filterconfig.Attribute{ + { + Key: "attr1", + Value: "val1", + }, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + log := plog.NewLogRecord() + log.Body().SetStr("body") + log.Attributes().PutStr("keyString", "arithmetic") + log.Attributes().PutInt("keyInt", 123) + log.Attributes().PutDouble("keyDouble", 3245.6) + log.Attributes().PutBool("keyBool", true) + log.Attributes().PutStr("keyExists", "present") + log.SetSeverityText("severity text") + log.SetSeverityNumber(tt.logSeverity) + + resource := pcommon.NewResource() + resource.Attributes().PutStr(conventions.AttributeServiceName, "svcA") + + scope := pcommon.NewInstrumentationScope() + + tCtx := ottllog.NewTransformContext(log, scope, resource, plog.NewScopeLogs(), plog.NewResourceLogs()) + + boolExpr, err := NewSkipExpr(tt.condition) + require.NoError(t, err) + expectedResult, err := boolExpr.Eval(context.Background(), tCtx) + assert.NoError(t, err) + + ottlBoolExpr, err := filterottl.NewLogSkipExprBridge(tt.condition) + assert.NoError(t, err) + ottlResult, err := ottlBoolExpr.Eval(context.Background(), tCtx) + assert.NoError(t, err) + + assert.Equal(t, expectedResult, ottlResult) + }) + } +} + +func BenchmarkFilterlog_NewSkipExpr(b *testing.B) { + testCases := []struct { + name string + mc *filterconfig.MatchConfig + skip bool + }{ + { + name: "body_match_regexp", + mc: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + LogBodies: []string{"body"}, + }, + }, + skip: false, + }, + { + name: "body_match_static", + mc: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Strict), + LogBodies: []string{"body"}, + }, + }, + skip: false, + }, + { + name: "severity_number_match", + mc: &filterconfig.MatchConfig{ + Include: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Strict), + LogSeverityNumber: &filterconfig.LogSeverityNumberMatchProperties{ + Min: plog.SeverityNumberInfo, + MatchUndefined: true, + }, + }, + }, + skip: false, + }, + } + + for _, tt := range testCases { + origVal := useOTTLBridge.IsEnabled() + err := featuregate.GlobalRegistry().Set("filter.filterlog.useOTTLBridge", true) + assert.NoError(b, err) + + skipExpr, err := NewSkipExpr(tt.mc) + assert.NoError(b, err) + + log := plog.NewLogRecord() + log.Body().SetStr("body") + log.SetSeverityNumber(plog.SeverityNumberUnspecified) + + resource := pcommon.NewResource() + + scope := pcommon.NewInstrumentationScope() + + tCtx := ottllog.NewTransformContext(log, scope, resource, plog.NewScopeLogs(), plog.NewResourceLogs()) + + b.Run(tt.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + var skip bool + skip, err = skipExpr.Eval(context.Background(), tCtx) + assert.NoError(b, err) + assert.Equal(b, tt.skip, skip) + } + }) + + err = featuregate.GlobalRegistry().Set("filter.filterlog.useOTTLBridge", origVal) + assert.NoError(b, err) + } +} diff --git a/internal/filter/filterprofile/package_test.go b/internal/filter/filterprofile/package_test.go new file mode 100644 index 000000000000..642849ed2bc4 --- /dev/null +++ b/internal/filter/filterprofile/package_test.go @@ -0,0 +1,14 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package filterprofile + +import ( + "testing" + + "go.uber.org/goleak" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/pkg/ottl/contexts/ottlprofile/README.md b/pkg/ottl/contexts/ottlprofile/README.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/pkg/ottl/contexts/ottlprofile/package_test.go b/pkg/ottl/contexts/ottlprofile/package_test.go new file mode 100644 index 000000000000..b0f4327b83c5 --- /dev/null +++ b/pkg/ottl/contexts/ottlprofile/package_test.go @@ -0,0 +1,14 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package ottlprofile + +import ( + "testing" + + "go.uber.org/goleak" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/pkg/ottl/contexts/ottlprofile/profile.go b/pkg/ottl/contexts/ottlprofile/profile.go new file mode 100644 index 000000000000..52d7485d952a --- /dev/null +++ b/pkg/ottl/contexts/ottlprofile/profile.go @@ -0,0 +1,544 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package ottlprofile // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlprofile" + +import ( + "context" + "encoding/hex" + "errors" + "fmt" + "time" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.uber.org/zap/zapcore" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/internal" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/internal/logging" + common "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/internal/ottlcommon" +) + +const ( + contextName = "Profile" +) + +var _ internal.ResourceContext = (*TransformContext)(nil) +var _ internal.InstrumentationScopeContext = (*TransformContext)(nil) +var _ zapcore.ObjectMarshaler = (*TransformContext)(nil) + +type TransformContext struct { + logRecord plog.LogRecord + instrumentationScope pcommon.InstrumentationScope + resource pcommon.Resource + cache pcommon.Map + scopeLogs plog.ScopeLogs + resourceLogs plog.ResourceLogs +} + +type logRecord plog.LogRecord + +func (l logRecord) MarshalLogObject(encoder zapcore.ObjectEncoder) error { + lr := plog.LogRecord(l) + spanID := lr.SpanID() + traceID := lr.TraceID() + err := encoder.AddObject("attributes", logging.Map(lr.Attributes())) + encoder.AddString("body", lr.Body().AsString()) + encoder.AddUint32("dropped_attribute_count", lr.DroppedAttributesCount()) + encoder.AddUint32("flags", uint32(lr.Flags())) + encoder.AddUint64("observed_time_unix_nano", uint64(lr.ObservedTimestamp())) + encoder.AddInt32("severity_number", int32(lr.SeverityNumber())) + encoder.AddString("severity_text", lr.SeverityText()) + encoder.AddString("span_id", hex.EncodeToString(spanID[:])) + encoder.AddUint64("time_unix_nano", uint64(lr.Timestamp())) + encoder.AddString("trace_id", hex.EncodeToString(traceID[:])) + return err +} + +func (tCtx TransformContext) MarshalLogObject(encoder zapcore.ObjectEncoder) error { + err := encoder.AddObject("resource", logging.Resource(tCtx.resource)) + err = errors.Join(err, encoder.AddObject("scope", logging.InstrumentationScope(tCtx.instrumentationScope))) + err = errors.Join(err, encoder.AddObject("log_record", logRecord(tCtx.logRecord))) + err = errors.Join(err, encoder.AddObject("cache", logging.Map(tCtx.cache))) + return err +} + +type Option func(*ottl.Parser[TransformContext]) + +func NewTransformContext(logRecord plog.LogRecord, instrumentationScope pcommon.InstrumentationScope, resource pcommon.Resource, scopeLogs plog.ScopeLogs, resourceLogs plog.ResourceLogs) TransformContext { + return TransformContext{ + logRecord: logRecord, + instrumentationScope: instrumentationScope, + resource: resource, + cache: pcommon.NewMap(), + scopeLogs: scopeLogs, + resourceLogs: resourceLogs, + } +} + +func (tCtx TransformContext) GetLogRecord() plog.LogRecord { + return tCtx.logRecord +} + +func (tCtx TransformContext) GetInstrumentationScope() pcommon.InstrumentationScope { + return tCtx.instrumentationScope +} + +func (tCtx TransformContext) GetResource() pcommon.Resource { + return tCtx.resource +} + +func (tCtx TransformContext) getCache() pcommon.Map { + return tCtx.cache +} + +func (tCtx TransformContext) GetScopeSchemaURLItem() internal.SchemaURLItem { + return tCtx.scopeLogs +} + +func (tCtx TransformContext) GetResourceSchemaURLItem() internal.SchemaURLItem { + return tCtx.resourceLogs +} + +func NewParser(functions map[string]ottl.Factory[TransformContext], telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) { + pep := pathExpressionParser{telemetrySettings} + p, err := ottl.NewParser[TransformContext]( + functions, + pep.parsePath, + telemetrySettings, + ottl.WithEnumParser[TransformContext](parseEnum), + ) + if err != nil { + return ottl.Parser[TransformContext]{}, err + } + for _, opt := range options { + opt(&p) + } + return p, nil +} + +type StatementSequenceOption func(*ottl.StatementSequence[TransformContext]) + +func WithStatementSequenceErrorMode(errorMode ottl.ErrorMode) StatementSequenceOption { + return func(s *ottl.StatementSequence[TransformContext]) { + ottl.WithStatementSequenceErrorMode[TransformContext](errorMode)(s) + } +} + +func NewStatementSequence(statements []*ottl.Statement[TransformContext], telemetrySettings component.TelemetrySettings, options ...StatementSequenceOption) ottl.StatementSequence[TransformContext] { + s := ottl.NewStatementSequence(statements, telemetrySettings) + for _, op := range options { + op(&s) + } + return s +} + +type ConditionSequenceOption func(*ottl.ConditionSequence[TransformContext]) + +func WithConditionSequenceErrorMode(errorMode ottl.ErrorMode) ConditionSequenceOption { + return func(c *ottl.ConditionSequence[TransformContext]) { + ottl.WithConditionSequenceErrorMode[TransformContext](errorMode)(c) + } +} + +func NewConditionSequence(conditions []*ottl.Condition[TransformContext], telemetrySettings component.TelemetrySettings, options ...ConditionSequenceOption) ottl.ConditionSequence[TransformContext] { + c := ottl.NewConditionSequence(conditions, telemetrySettings) + for _, op := range options { + op(&c) + } + return c +} + +var symbolTable = map[ottl.EnumSymbol]ottl.Enum{ + "SEVERITY_NUMBER_UNSPECIFIED": ottl.Enum(plog.SeverityNumberUnspecified), + "SEVERITY_NUMBER_TRACE": ottl.Enum(plog.SeverityNumberTrace), + "SEVERITY_NUMBER_TRACE2": ottl.Enum(plog.SeverityNumberTrace2), + "SEVERITY_NUMBER_TRACE3": ottl.Enum(plog.SeverityNumberTrace3), + "SEVERITY_NUMBER_TRACE4": ottl.Enum(plog.SeverityNumberTrace4), + "SEVERITY_NUMBER_DEBUG": ottl.Enum(plog.SeverityNumberDebug), + "SEVERITY_NUMBER_DEBUG2": ottl.Enum(plog.SeverityNumberDebug2), + "SEVERITY_NUMBER_DEBUG3": ottl.Enum(plog.SeverityNumberDebug3), + "SEVERITY_NUMBER_DEBUG4": ottl.Enum(plog.SeverityNumberDebug4), + "SEVERITY_NUMBER_INFO": ottl.Enum(plog.SeverityNumberInfo), + "SEVERITY_NUMBER_INFO2": ottl.Enum(plog.SeverityNumberInfo2), + "SEVERITY_NUMBER_INFO3": ottl.Enum(plog.SeverityNumberInfo3), + "SEVERITY_NUMBER_INFO4": ottl.Enum(plog.SeverityNumberInfo4), + "SEVERITY_NUMBER_WARN": ottl.Enum(plog.SeverityNumberWarn), + "SEVERITY_NUMBER_WARN2": ottl.Enum(plog.SeverityNumberWarn2), + "SEVERITY_NUMBER_WARN3": ottl.Enum(plog.SeverityNumberWarn3), + "SEVERITY_NUMBER_WARN4": ottl.Enum(plog.SeverityNumberWarn4), + "SEVERITY_NUMBER_ERROR": ottl.Enum(plog.SeverityNumberError), + "SEVERITY_NUMBER_ERROR2": ottl.Enum(plog.SeverityNumberError2), + "SEVERITY_NUMBER_ERROR3": ottl.Enum(plog.SeverityNumberError3), + "SEVERITY_NUMBER_ERROR4": ottl.Enum(plog.SeverityNumberError4), + "SEVERITY_NUMBER_FATAL": ottl.Enum(plog.SeverityNumberFatal), + "SEVERITY_NUMBER_FATAL2": ottl.Enum(plog.SeverityNumberFatal2), + "SEVERITY_NUMBER_FATAL3": ottl.Enum(plog.SeverityNumberFatal3), + "SEVERITY_NUMBER_FATAL4": ottl.Enum(plog.SeverityNumberFatal4), +} + +func parseEnum(val *ottl.EnumSymbol) (*ottl.Enum, error) { + if val != nil { + if enum, ok := symbolTable[*val]; ok { + return &enum, nil + } + return nil, fmt.Errorf("enum symbol, %s, not found", *val) + } + return nil, fmt.Errorf("enum symbol not provided") +} + +type pathExpressionParser struct { + telemetrySettings component.TelemetrySettings +} + +func (pep *pathExpressionParser) parsePath(path ottl.Path[TransformContext]) (ottl.GetSetter[TransformContext], error) { + if path == nil { + return nil, fmt.Errorf("path cannot be nil") + } + switch path.Name() { + case "cache": + if path.Keys() == nil { + return accessCache(), nil + } + return accessCacheKey(path.Keys()), nil + case "resource": + return internal.ResourcePathGetSetter[TransformContext](path.Next()) + case "instrumentation_scope": + return internal.ScopePathGetSetter[TransformContext](path.Next()) + case "time_unix_nano": + return accessTimeUnixNano(), nil + case "observed_time_unix_nano": + return accessObservedTimeUnixNano(), nil + case "time": + return accessTime(), nil + case "observed_time": + return accessObservedTime(), nil + case "severity_number": + return accessSeverityNumber(), nil + case "severity_text": + return accessSeverityText(), nil + case "body": + nextPath := path.Next() + if nextPath != nil { + if nextPath.Name() == "string" { + return accessStringBody(), nil + } + return nil, internal.FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), contextName, internal.LogRef) + } + if path.Keys() == nil { + return accessBody(), nil + } + return accessBodyKey(path.Keys()), nil + case "attributes": + if path.Keys() == nil { + return accessAttributes(), nil + } + return accessAttributesKey(path.Keys()), nil + case "dropped_attributes_count": + return accessDroppedAttributesCount(), nil + case "flags": + return accessFlags(), nil + case "trace_id": + nextPath := path.Next() + if nextPath != nil { + if nextPath.Name() == "string" { + return accessStringTraceID(), nil + } + return nil, internal.FormatDefaultErrorMessage(nextPath.Name(), nextPath.String(), contextName, internal.LogRef) + } + return accessTraceID(), nil + case "span_id": + nextPath := path.Next() + if nextPath != nil { + if nextPath.Name() == "string" { + return accessStringSpanID(), nil + } + return nil, internal.FormatDefaultErrorMessage(nextPath.Name(), path.String(), contextName, internal.LogRef) + } + return accessSpanID(), nil + default: + return nil, internal.FormatDefaultErrorMessage(path.Name(), path.String(), contextName, internal.LogRef) + } +} + +func accessCache() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return tCtx.getCache(), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if m, ok := val.(pcommon.Map); ok { + m.CopyTo(tCtx.getCache()) + } + return nil + }, + } +} + +func accessCacheKey(key []ottl.Key[TransformContext]) ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(ctx context.Context, tCtx TransformContext) (any, error) { + return internal.GetMapValue[TransformContext](ctx, tCtx, tCtx.getCache(), key) + }, + Setter: func(ctx context.Context, tCtx TransformContext, val any) error { + return internal.SetMapValue[TransformContext](ctx, tCtx, tCtx.getCache(), key, val) + }, + } +} + +func accessTimeUnixNano() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return tCtx.GetLogRecord().Timestamp().AsTime().UnixNano(), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if i, ok := val.(int64); ok { + tCtx.GetLogRecord().SetTimestamp(pcommon.NewTimestampFromTime(time.Unix(0, i))) + } + return nil + }, + } +} + +func accessObservedTimeUnixNano() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return tCtx.GetLogRecord().ObservedTimestamp().AsTime().UnixNano(), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if i, ok := val.(int64); ok { + tCtx.GetLogRecord().SetObservedTimestamp(pcommon.NewTimestampFromTime(time.Unix(0, i))) + } + return nil + }, + } +} + +func accessTime() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return tCtx.GetLogRecord().Timestamp().AsTime(), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if i, ok := val.(time.Time); ok { + tCtx.GetLogRecord().SetTimestamp(pcommon.NewTimestampFromTime(i)) + } + return nil + }, + } +} + +func accessObservedTime() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return tCtx.GetLogRecord().ObservedTimestamp().AsTime(), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if i, ok := val.(time.Time); ok { + tCtx.GetLogRecord().SetObservedTimestamp(pcommon.NewTimestampFromTime(i)) + } + return nil + }, + } +} + +func accessSeverityNumber() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return int64(tCtx.GetLogRecord().SeverityNumber()), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if i, ok := val.(int64); ok { + tCtx.GetLogRecord().SetSeverityNumber(plog.SeverityNumber(i)) + } + return nil + }, + } +} + +func accessSeverityText() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return tCtx.GetLogRecord().SeverityText(), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if s, ok := val.(string); ok { + tCtx.GetLogRecord().SetSeverityText(s) + } + return nil + }, + } +} + +func accessBody() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return common.GetValue(tCtx.GetLogRecord().Body()), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + return internal.SetValue(tCtx.GetLogRecord().Body(), val) + }, + } +} + +func accessBodyKey(key []ottl.Key[TransformContext]) ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(ctx context.Context, tCtx TransformContext) (any, error) { + body := tCtx.GetLogRecord().Body() + switch body.Type() { + case pcommon.ValueTypeMap: + return internal.GetMapValue[TransformContext](ctx, tCtx, tCtx.GetLogRecord().Body().Map(), key) + case pcommon.ValueTypeSlice: + return internal.GetSliceValue[TransformContext](ctx, tCtx, tCtx.GetLogRecord().Body().Slice(), key) + default: + return nil, fmt.Errorf("log bodies of type %s cannot be indexed", body.Type().String()) + } + }, + Setter: func(ctx context.Context, tCtx TransformContext, val any) error { + body := tCtx.GetLogRecord().Body() + switch body.Type() { + case pcommon.ValueTypeMap: + return internal.SetMapValue[TransformContext](ctx, tCtx, tCtx.GetLogRecord().Body().Map(), key, val) + case pcommon.ValueTypeSlice: + return internal.SetSliceValue[TransformContext](ctx, tCtx, tCtx.GetLogRecord().Body().Slice(), key, val) + default: + return fmt.Errorf("log bodies of type %s cannot be indexed", body.Type().String()) + } + }, + } +} + +func accessStringBody() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return tCtx.GetLogRecord().Body().AsString(), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if str, ok := val.(string); ok { + tCtx.GetLogRecord().Body().SetStr(str) + } + return nil + }, + } +} + +func accessAttributes() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return tCtx.GetLogRecord().Attributes(), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if attrs, ok := val.(pcommon.Map); ok { + attrs.CopyTo(tCtx.GetLogRecord().Attributes()) + } + return nil + }, + } +} + +func accessAttributesKey(key []ottl.Key[TransformContext]) ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(ctx context.Context, tCtx TransformContext) (any, error) { + return internal.GetMapValue[TransformContext](ctx, tCtx, tCtx.GetLogRecord().Attributes(), key) + }, + Setter: func(ctx context.Context, tCtx TransformContext, val any) error { + return internal.SetMapValue[TransformContext](ctx, tCtx, tCtx.GetLogRecord().Attributes(), key, val) + }, + } +} + +func accessDroppedAttributesCount() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return int64(tCtx.GetLogRecord().DroppedAttributesCount()), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if i, ok := val.(int64); ok { + tCtx.GetLogRecord().SetDroppedAttributesCount(uint32(i)) + } + return nil + }, + } +} + +func accessFlags() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return int64(tCtx.GetLogRecord().Flags()), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if i, ok := val.(int64); ok { + tCtx.GetLogRecord().SetFlags(plog.LogRecordFlags(i)) + } + return nil + }, + } +} + +func accessTraceID() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return tCtx.GetLogRecord().TraceID(), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if newTraceID, ok := val.(pcommon.TraceID); ok { + tCtx.GetLogRecord().SetTraceID(newTraceID) + } + return nil + }, + } +} + +func accessStringTraceID() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + id := tCtx.GetLogRecord().TraceID() + return hex.EncodeToString(id[:]), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if str, ok := val.(string); ok { + id, err := internal.ParseTraceID(str) + if err != nil { + return err + } + tCtx.GetLogRecord().SetTraceID(id) + } + return nil + }, + } +} + +func accessSpanID() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + return tCtx.GetLogRecord().SpanID(), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if newSpanID, ok := val.(pcommon.SpanID); ok { + tCtx.GetLogRecord().SetSpanID(newSpanID) + } + return nil + }, + } +} + +func accessStringSpanID() ottl.StandardGetSetter[TransformContext] { + return ottl.StandardGetSetter[TransformContext]{ + Getter: func(_ context.Context, tCtx TransformContext) (any, error) { + id := tCtx.GetLogRecord().SpanID() + return hex.EncodeToString(id[:]), nil + }, + Setter: func(_ context.Context, tCtx TransformContext, val any) error { + if str, ok := val.(string); ok { + id, err := internal.ParseSpanID(str) + if err != nil { + return err + } + tCtx.GetLogRecord().SetSpanID(id) + } + return nil + }, + } +} diff --git a/pkg/ottl/contexts/ottlprofile/profile_test.go b/pkg/ottl/contexts/ottlprofile/profile_test.go new file mode 100644 index 000000000000..28d641327288 --- /dev/null +++ b/pkg/ottl/contexts/ottlprofile/profile_test.go @@ -0,0 +1,4 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package ottlprofile diff --git a/processor/attributesprocessor/attributes_profile.go b/processor/attributesprocessor/attributes_profile.go new file mode 100644 index 000000000000..4185f58c9524 --- /dev/null +++ b/processor/attributesprocessor/attributes_profile.go @@ -0,0 +1,61 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package attributesprocessor // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor" + +import ( + "context" + + "go.opentelemetry.io/collector/pdata/pprofile" + "go.uber.org/zap" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/attraction" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/expr" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlprofile" +) + +type profileAttributesProcessor struct { + profileger *zap.Logger + attrProc *attraction.AttrProc + skipExpr expr.BoolExpr[ottlprofile.TransformContext] +} + +// newProfileAttributesProcessor returns a processor that modifies attributes of a +// profile record. To construct the attributes processors, the use of the factory +// methods are required in order to validate the inputs. +func newProfileAttributesProcessor(profileger *zap.Logger, attrProc *attraction.AttrProc, skipExpr expr.BoolExpr[ottlprofile.TransformContext]) *profileAttributesProcessor { + return &profileAttributesProcessor{ + profileger: profileger, + attrProc: attrProc, + skipExpr: skipExpr, + } +} + +func (a *profileAttributesProcessor) processProfiles(ctx context.Context, ld pprofile.Profiles) (pprofile.Profiles, error) { + rls := ld.ResourceProfiles() + for i := 0; i < rls.Len(); i++ { + rs := rls.At(i) + ilss := rs.ScopeProfiles() + resource := rs.Resource() + for j := 0; j < ilss.Len(); j++ { + ils := ilss.At(j) + profiles := ils.Profiles() + library := ils.Scope() + for k := 0; k < profiles.Len(); k++ { + lr := profiles.At(k) + if a.skipExpr != nil { + skip, err := a.skipExpr.Eval(ctx, ottlprofile.NewTransformContext(lr, library, resource, ils, rs)) + if err != nil { + return ld, err + } + if skip { + continue + } + } + + a.attrProc.Process(ctx, a.profileger, lr.Attributes()) + } + } + } + return ld, nil +} diff --git a/processor/attributesprocessor/factory.go b/processor/attributesprocessor/factory.go index 9a7a73dc75e7..26ab62104ddb 100644 --- a/processor/attributesprocessor/factory.go +++ b/processor/attributesprocessor/factory.go @@ -8,13 +8,17 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/consumer/consumerprofiles" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processorhelper" + "go.opentelemetry.io/collector/processor/processorhelper/processorhelperprofiles" + "go.opentelemetry.io/collector/processor/processorprofiles" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/attraction" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterconfig" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterlog" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filtermetric" + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterprofile" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterspan" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor/internal/metadata" ) @@ -23,12 +27,13 @@ var processorCapabilities = consumer.Capabilities{MutatesData: true} // NewFactory returns a new factory for the Attributes processor. func NewFactory() processor.Factory { - return processor.NewFactory( + return processorprofiles.NewFactory( metadata.Type, createDefaultConfig, - processor.WithTraces(createTracesProcessor, metadata.TracesStability), - processor.WithLogs(createLogsProcessor, metadata.LogsStability), - processor.WithMetrics(createMetricsProcessor, metadata.MetricsStability)) + processorprofiles.WithTraces(createTracesProcessor, metadata.TracesStability), + processorprofiles.WithLogs(createLogsProcessor, metadata.LogsStability), + processorprofiles.WithMetrics(createMetricsProcessor, metadata.MetricsStability), + processorprofiles.WithProfiles(createProfilesProcessor, metadata.ProfilesStability)) } // Note: This isn't a valid configuration because the processor would do no work. @@ -115,3 +120,30 @@ func createMetricsProcessor( newMetricAttributesProcessor(set.Logger, attrProc, skipExpr).processMetrics, processorhelper.WithCapabilities(processorCapabilities)) } + +func createProfilesProcessor( + ctx context.Context, + set processor.Settings, + cfg component.Config, + nextConsumer consumerprofiles.Profiles, +) (processorprofiles.Profiles, error) { + + oCfg := cfg.(*Config) + attrProc, err := attraction.NewAttrProc(&oCfg.Settings) + if err != nil { + return nil, err + } + + skipExpr, err := filterprofile.NewSkipExpr(&oCfg.MatchConfig) + if err != nil { + return nil, err + } + + return processorhelperprofiles.NewProfiles( + ctx, + set, + cfg, + nextConsumer, + newProfileAttributesProcessor(set.Logger, attrProc, skipExpr).processProfiles, + processorhelperprofiles.WithCapabilities(processorCapabilities)) +} diff --git a/processor/attributesprocessor/go.mod b/processor/attributesprocessor/go.mod index e4568a666054..8e7ac31c10cb 100644 --- a/processor/attributesprocessor/go.mod +++ b/processor/attributesprocessor/go.mod @@ -13,7 +13,9 @@ require ( go.opentelemetry.io/collector/consumer v0.112.0 go.opentelemetry.io/collector/consumer/consumertest v0.112.0 go.opentelemetry.io/collector/pdata v1.18.0 + go.opentelemetry.io/collector/pdata/pprofile v0.112.0 go.opentelemetry.io/collector/processor v0.112.0 + go.opentelemetry.io/collector/processor/processorhelper/processorhelperprofiles v0.0.0-20241030215746-b76b9f75b604 go.opentelemetry.io/collector/processor/processortest v0.112.0 go.opentelemetry.io/collector/semconv v0.112.0 go.uber.org/goleak v1.3.0 @@ -59,7 +61,6 @@ require ( go.opentelemetry.io/collector/config/configtelemetry v0.112.0 // indirect go.opentelemetry.io/collector/consumer/consumerprofiles v0.112.0 // indirect go.opentelemetry.io/collector/featuregate v1.18.0 // indirect - go.opentelemetry.io/collector/pdata/pprofile v0.112.0 // indirect go.opentelemetry.io/collector/pdata/testdata v0.112.0 // indirect go.opentelemetry.io/collector/pipeline v0.112.0 // indirect go.opentelemetry.io/collector/processor/processorprofiles v0.112.0 // indirect @@ -82,10 +83,6 @@ require ( replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal => ../../internal/coreinternal -replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter => ../../internal/filter - -replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl => ../../pkg/ottl - replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest => ../../pkg/pdatatest replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil => ../../pkg/pdatautil @@ -96,4 +93,15 @@ retract ( v0.65.0 ) -replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden => ../../pkg/golden +replace ( + github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter => ../../internal/filter + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden => ../../pkg/golden + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl => ../../pkg/ottl + go.opentelemetry.io/collector/component => ../../../opentelemetry-collector/component + go.opentelemetry.io/collector/confmap => ../../../opentelemetry-collector/confmap + go.opentelemetry.io/collector/consumer/consumertest => ../../../opentelemetry-collector/consumer/consumertest + go.opentelemetry.io/collector/pdata => ../../../opentelemetry-collector/pdata + go.opentelemetry.io/collector/processor/processorhelper/processorhelperprofiles => ../../../opentelemetry-collector/processor/processorhelper/processorhelperprofiles + go.opentelemetry.io/collector/processor/processortest => ../../../opentelemetry-collector/processor/processortest + go.opentelemetry.io/collector/semconv => ../../../opentelemetry-collector/semconv +) diff --git a/processor/attributesprocessor/go.sum b/processor/attributesprocessor/go.sum index a0512d26b0f5..375e16ebd05e 100644 --- a/processor/attributesprocessor/go.sum +++ b/processor/attributesprocessor/go.sum @@ -89,24 +89,16 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/collector/client v1.18.0 h1:wk+R3wpeleTIrk+xX85ICKBJ6GeZQ50Hk5DthRpOpUQ= go.opentelemetry.io/collector/client v1.18.0/go.mod h1:33ntN6gwIfa1JCnQfQDSImIBY8Gfe66kv+MjQ/C37Fk= -go.opentelemetry.io/collector/component v0.112.0 h1:Hw125Tdb427yKkzFx3U/OsfPATYXsbURkc27dn19he8= -go.opentelemetry.io/collector/component v0.112.0/go.mod h1:hV9PEgkNlVAySX+Oo/g7+NcLe234L04kRXw6uGj3VEw= go.opentelemetry.io/collector/component/componentstatus v0.112.0 h1:khR9QKMv1v5MPa4I3TcNxNzFYVdi1x/+1U/44clQdls= go.opentelemetry.io/collector/component/componentstatus v0.112.0/go.mod h1:cbpNsZrsOAt0/T9urCxMhbzOGs9ijgNDhyALQGs6H4A= go.opentelemetry.io/collector/config/configtelemetry v0.112.0 h1:MVBrWJUoqfKrORI38dY8OV0i5d1RRHR/ACIBu9TOcZ8= go.opentelemetry.io/collector/config/configtelemetry v0.112.0/go.mod h1:R0MBUxjSMVMIhljuDHWIygzzJWQyZHXXWIgQNxcFwhc= -go.opentelemetry.io/collector/confmap v1.18.0 h1:UEOeJY8RW8lZ1O4lzHSGqolS7uzkpXQi5fa8SidKqQg= -go.opentelemetry.io/collector/confmap v1.18.0/go.mod h1:GgNu1ElPGmLn9govqIfjaopvdspw4PJ9KeDtWC4E2Q4= go.opentelemetry.io/collector/consumer v0.112.0 h1:tfO4FpuQ8MsD7AxgslC3tRNVYjd9Xkus34BOExsG4fM= go.opentelemetry.io/collector/consumer v0.112.0/go.mod h1:ZKSeGvXvaofIlvPrWlARKQpONOmuw6R/yifgYCWHKRw= go.opentelemetry.io/collector/consumer/consumerprofiles v0.112.0 h1:ym+QxemlbWwfMSUto1hRTfcZeYbj2q8FpMzjk8O+X60= go.opentelemetry.io/collector/consumer/consumerprofiles v0.112.0/go.mod h1:4PjDUpURFh85R6NLEHrEf/uZjpk4LAYmmOrqu+iZsyE= -go.opentelemetry.io/collector/consumer/consumertest v0.112.0 h1:pGvNH+H4rMygUOql6ynVQim6UFdimTiJ0HRfQL6v0GE= -go.opentelemetry.io/collector/consumer/consumertest v0.112.0/go.mod h1:rfVo0tYt/BaLWw3IaQKVQafjUlMsA5qTkvsSOfFrr9c= go.opentelemetry.io/collector/featuregate v1.18.0 h1:1CvP1K3XmVs7WZCs/A1j8rsC7JQWu+y+vF8vxKjLaOU= go.opentelemetry.io/collector/featuregate v1.18.0/go.mod h1:47xrISO71vJ83LSMm8+yIDsUbKktUp48Ovt7RR6VbRs= -go.opentelemetry.io/collector/pdata v1.18.0 h1:/yg2rO2dxqDM2p6GutsMCxXN6sKlXwyIz/ZYyUPONBg= -go.opentelemetry.io/collector/pdata v1.18.0/go.mod h1:Ox1YVLe87cZDB/TL30i4SUz1cA5s6AM6SpFMfY61ICs= go.opentelemetry.io/collector/pdata/pprofile v0.112.0 h1:t+LYorcMqZ3sDz5/jp3xU2l5lIhIXuIOOGO4Ef9CG2c= go.opentelemetry.io/collector/pdata/pprofile v0.112.0/go.mod h1:F2aTCoDzIaxEUK1g92LZvMwradySFMo3ZsAnBIpOdUg= go.opentelemetry.io/collector/pdata/testdata v0.112.0 h1:7jJzNvRE+CpYrwHbAYwPiN9a/hqmVRlRADJNeDJTvYI= @@ -117,10 +109,6 @@ go.opentelemetry.io/collector/processor v0.112.0 h1:nMv9DOBYR9MB78ddUgY3A3ytwAwk go.opentelemetry.io/collector/processor v0.112.0/go.mod h1:AJ8EHq8Z/ev90f4gU6G5ULUncdpWmBRATYk8ioR3pvw= go.opentelemetry.io/collector/processor/processorprofiles v0.112.0 h1:Aef68SAbmBbhbsZZPuZb0ECwkV05vIcHIizGOGbWsbM= go.opentelemetry.io/collector/processor/processorprofiles v0.112.0/go.mod h1:OUS7GcPCvFAIERSUFJLMtj6MSUOTCuS2pGKB7B+OHXs= -go.opentelemetry.io/collector/processor/processortest v0.112.0 h1:kW7kZ6EC1YjBiOvdajxN/DxvVljr9MKMemHheoaYcFc= -go.opentelemetry.io/collector/processor/processortest v0.112.0/go.mod h1:idZ8tCMswGQ8VsPBLtPDL2N7+pvtiMYkz6vNFPPew2M= -go.opentelemetry.io/collector/semconv v0.112.0 h1:JPQyvZhlNLVSuVI+FScONaiFygB7h7NTZceUEKIQUEc= -go.opentelemetry.io/collector/semconv v0.112.0/go.mod h1:zCJ5njhWpejR+A40kiEoeFm1xq1uzyZwMnRNX6/D82A= go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= diff --git a/processor/attributesprocessor/internal/metadata/generated_status.go b/processor/attributesprocessor/internal/metadata/generated_status.go index 43a9445d0897..2d811ba625cc 100644 --- a/processor/attributesprocessor/internal/metadata/generated_status.go +++ b/processor/attributesprocessor/internal/metadata/generated_status.go @@ -15,4 +15,5 @@ const ( TracesStability = component.StabilityLevelBeta MetricsStability = component.StabilityLevelBeta LogsStability = component.StabilityLevelBeta + ProfilesStability = component.StabilityLevelDevelopment ) diff --git a/processor/attributesprocessor/metadata.yaml b/processor/attributesprocessor/metadata.yaml index 17aa06b27561..64171687b096 100644 --- a/processor/attributesprocessor/metadata.yaml +++ b/processor/attributesprocessor/metadata.yaml @@ -4,6 +4,7 @@ status: class: processor stability: beta: [traces, metrics, logs] + development: [profiles] distributions: [core, contrib, k8s] warnings: [Identity Conflict] codeowners: