diff --git a/CHANGELOG.md b/CHANGELOG.md index e30476333fd7..0f13276303b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ ### 💡 Enhancements 💡 - `pkg/translator/prometheusremotewrite`: Allow to disable sanitize metric labels (#8270) +- `attributesprocessor`: Support filter by severity (#9132) + ### 🧰 Bug fixes 🧰 ## v0.49.0 diff --git a/internal/coreinternal/processor/filterconfig/config.go b/internal/coreinternal/processor/filterconfig/config.go index 04c4f1e86a58..abdefe5b28a5 100644 --- a/internal/coreinternal/processor/filterconfig/config.go +++ b/internal/coreinternal/processor/filterconfig/config.go @@ -94,6 +94,10 @@ type MatchProperties struct { // against. LogBodies []string `mapstructure:"log_bodies"` + // LogSeverityTexts is a list of strings that the LogRecord's severity text field must match + // against. + LogSeverityTexts []string `mapstructure:"log_severity_texts"` + // MetricNames is a list of strings to match metric name against. // A match occurs if metric name matches at least one item in the list. // This field is optional. @@ -122,6 +126,10 @@ func (mp *MatchProperties) ValidateForSpans() error { return errors.New("log_bodies should not be specified for trace spans") } + if len(mp.LogSeverityTexts) > 0 { + return errors.New("log_severity_texts should not be specified for trace spans") + } + if len(mp.Services) == 0 && len(mp.SpanNames) == 0 && len(mp.Attributes) == 0 && len(mp.Libraries) == 0 && len(mp.Resources) == 0 { return errors.New(`at least one of "services", "span_names", "attributes", "libraries" or "resources" field must be specified`) @@ -136,8 +144,8 @@ func (mp *MatchProperties) ValidateForLogs() error { return errors.New("neither services nor span_names should be specified for log records") } - if len(mp.Attributes) == 0 && len(mp.Libraries) == 0 && len(mp.Resources) == 0 && len(mp.LogBodies) == 0 { - return errors.New(`at least one of "attributes", "libraries", "resources" or "log_bodies" field must be specified`) + if len(mp.Attributes) == 0 && len(mp.Libraries) == 0 && len(mp.Resources) == 0 && len(mp.LogBodies) == 0 && len(mp.LogSeverityTexts) == 0 { + return errors.New(`at least one of "attributes", "libraries", "resources", "log_bodies" or "log_severity_texts" field must be specified`) } return nil diff --git a/internal/coreinternal/processor/filterlog/filterlog.go b/internal/coreinternal/processor/filterlog/filterlog.go index f63e551e9211..1e2a5716c834 100644 --- a/internal/coreinternal/processor/filterlog/filterlog.go +++ b/internal/coreinternal/processor/filterlog/filterlog.go @@ -39,6 +39,9 @@ type propertiesMatcher struct { // log bodies to compare to. bodyFilters filterset.FilterSet + + // log severity texts to compare to + severityTextFilters filterset.FilterSet } // NewMatcher creates a LogRecord Matcher that matches based on the given MatchProperties. @@ -63,10 +66,18 @@ func NewMatcher(mp *filterconfig.MatchProperties) (Matcher, error) { return nil, fmt.Errorf("error creating log record body filters: %v", 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: %v", err) + } + } return &propertiesMatcher{ - PropertiesMatcher: rm, - bodyFilters: bodyFS, + PropertiesMatcher: rm, + bodyFilters: bodyFS, + severityTextFilters: severitytextFS, }, nil } @@ -82,6 +93,9 @@ func (mp *propertiesMatcher) MatchLogRecord(lr plog.LogRecord, resource pcommon. if lr.Body().Type() == pcommon.ValueTypeString && mp.bodyFilters != nil && mp.bodyFilters.Matches(lr.Body().StringVal()) { return true } + if mp.severityTextFilters != nil && mp.severityTextFilters.Matches(lr.SeverityText()) { + return true + } return mp.PropertiesMatcher.Match(lr.Attributes(), resource, library) } diff --git a/internal/coreinternal/processor/filterlog/filterlog_test.go b/internal/coreinternal/processor/filterlog/filterlog_test.go index caf234f4e868..df2d7eb5f952 100644 --- a/internal/coreinternal/processor/filterlog/filterlog_test.go +++ b/internal/coreinternal/processor/filterlog/filterlog_test.go @@ -41,14 +41,15 @@ func TestLogRecord_validateMatchesConfiguration_InvalidConfig(t *testing.T) { { name: "empty_property", property: filterconfig.MatchProperties{}, - errorString: `at least one of "attributes", "libraries", "resources" or "log_bodies" field must be specified`, + errorString: `at least one of "attributes", "libraries", "resources", "log_bodies" or "log_severity_texts" field must be specified`, }, { name: "empty_log_bodies_and_attributes", property: filterconfig.MatchProperties{ - LogBodies: []string{}, + LogBodies: []string{}, + LogSeverityTexts: []string{}, }, - errorString: `at least one of "attributes", "libraries", "resources" or "log_bodies" field must be specified`, + errorString: `at least one of "attributes", "libraries", "resources", "log_bodies" or "log_severity_texts" field must be specified`, }, { name: "span_properties", @@ -157,11 +158,19 @@ func TestLogRecord_Matching_True(t *testing.T) { LogBodies: []string{"AUTH.*"}, }, }, + { + name: "log_severity_text_regexp_match", + properties: &filterconfig.MatchProperties{ + Config: *createConfig(filterset.Regexp), + LogSeverityTexts: []string{"debug.*"}, + }, + }, } lr := plog.NewLogRecord() lr.Attributes().InsertString("abc", "def") lr.Body().SetStringVal("AUTHENTICATION FAILED") + lr.SetSeverityText("debug") for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { diff --git a/processor/attributesprocessor/README.md b/processor/attributesprocessor/README.md index 74715aed1dd7..1d9ef756316d 100644 --- a/processor/attributesprocessor/README.md +++ b/processor/attributesprocessor/README.md @@ -166,13 +166,13 @@ if the input data should be included or excluded from the processor. To configur this option, under `include` and/or `exclude` at least `match_type` and one of the following is required: - For spans, one of `services`, `span_names`, `attributes`, `resources`, or `libraries` must be specified -with a non-empty value for a valid configuration. The `log_bodies`, `expressions`, `resource_attributes` and +with a non-empty value for a valid configuration. The `log_bodies`, `log_severity_texts`, `expressions`, `resource_attributes` and `metric_names` fields are invalid. -- For logs, one of `log_bodies`, `attributes`, `resources`, or `libraries` must be specified with a +- For logs, one of `log_bodies`, `log_severity_texts`, `attributes`, `resources`, or `libraries` must be specified with a non-empty value for a valid configuration. The `span_names`, `metric_names`, `expressions`, `resource_attributes`, and `services` fields are invalid. - For metrics, one of `metric_names`, `resources` must be specified -with a valid non-empty value for a valid configuration. The `span_names`, `log_bodies` and +with a valid non-empty value for a valid configuration. The `span_names`, `log_bodies`, `log_severity_texts` and `services` fields are invalid. @@ -219,6 +219,10 @@ attributes: # This is an optional field. log_bodies: [, ..., ] + # The log severity text must match at least one of the items. + # This is an optional field. + log_severity_texts: [, ..., ] + # The metric name must match at least one of the items. # This is an optional field. metric_names: [, ..., ] diff --git a/processor/attributesprocessor/testdata/config.yaml b/processor/attributesprocessor/testdata/config.yaml index 2c68eb918de6..2dfeee9bc0f1 100644 --- a/processor/attributesprocessor/testdata/config.yaml +++ b/processor/attributesprocessor/testdata/config.yaml @@ -325,6 +325,23 @@ processors: - key: token action: delete + # The following demonstrates how to process logs that have a severity text that match regexp + # patterns. This processor will remove "token" attribute and will obfuscate "password" + # attribute in spans where severity matches "debug". + attributes/log_severity_regexp: + # Specifies the span properties that must exist for the processor to be applied. + include: + # match_type defines that "services" is an array of regexp-es. + match_type: regexp + # The log severity text "debug.*" pattern. + log_severity_texts: [ "debug.*" ] + actions: + - key: password + action: update + value: "obfuscated" + - key: token + action: delete + receivers: nop: