diff --git a/internal/coreinternal/processor/filterconfig/config.go b/internal/coreinternal/processor/filterconfig/config.go index d767b101f152..5410e3b0e230 100644 --- a/internal/coreinternal/processor/filterconfig/config.go +++ b/internal/coreinternal/processor/filterconfig/config.go @@ -95,6 +95,10 @@ type MatchProperties struct { // Deprecated: the Name field is removed from the log data model. LogNames []string `mapstructure:"log_names"` + // LogBodies is a list of strings that the LogRecord's body field must match + // against. + LogBodies []string `mapstructure:"log_bodies"` + // 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. @@ -123,6 +127,10 @@ func (mp *MatchProperties) ValidateForSpans() error { return errors.New("log_names should not be specified for trace spans") } + if len(mp.LogBodies) > 0 { + return errors.New("log_bodies 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`) @@ -137,8 +145,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 { - return errors.New(`at least one of "attributes", "libraries" or "resources" field must be specified`) + 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`) } return nil diff --git a/internal/coreinternal/processor/filterlog/filterlog.go b/internal/coreinternal/processor/filterlog/filterlog.go index c981fc18c655..4ee2343c0989 100644 --- a/internal/coreinternal/processor/filterlog/filterlog.go +++ b/internal/coreinternal/processor/filterlog/filterlog.go @@ -38,6 +38,9 @@ type propertiesMatcher struct { // log names to compare to. nameFilters filterset.FilterSet + + // log bodies to compare to. + bodyFilters filterset.FilterSet } // NewMatcher creates a LogRecord Matcher that matches based on the given MatchProperties. @@ -62,20 +65,33 @@ func NewMatcher(mp *filterconfig.MatchProperties) (Matcher, error) { return nil, fmt.Errorf("error creating log record name filters: %v", 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: %v", err) + } + } return &propertiesMatcher{ PropertiesMatcher: rm, nameFilters: nameFS, + bodyFilters: bodyFS, }, nil } // MatchLogRecord 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) MatchLogRecord(lr pdata.LogRecord, resource pdata.Resource, library pdata.InstrumentationScope) bool { + if lr.Body().Type() == pdata.ValueTypeString && mp.bodyFilters.Matches(lr.Body().StringVal()) { + 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 7fc38a285d33..9fc6c862e7a5 100644 --- a/internal/coreinternal/processor/filterlog/filterlog_test.go +++ b/internal/coreinternal/processor/filterlog/filterlog_test.go @@ -40,14 +40,15 @@ func TestLogRecord_validateMatchesConfiguration_InvalidConfig(t *testing.T) { { name: "empty_property", property: filterconfig.MatchProperties{}, - errorString: "at least one of \"attributes\", \"libraries\" or \"resources\" field must be specified", + errorString: `at least one of "attributes", "libraries", "resources" or "log_bodies" field must be specified`, }, { name: "empty_log_names_and_attributes", property: filterconfig.MatchProperties{ - LogNames: []string{}, + LogNames: []string{}, + LogBodies: []string{}, }, - errorString: "at least one of \"attributes\", \"libraries\" or \"resources\" field must be specified", + errorString: `at least one of "attributes", "libraries", "resources" or "log_bodies" field must be specified`, }, { name: "span_properties", diff --git a/processor/attributesprocessor/README.md b/processor/attributesprocessor/README.md index 301a1333edcc..1cdc5a89ecdf 100644 --- a/processor/attributesprocessor/README.md +++ b/processor/attributesprocessor/README.md @@ -218,6 +218,10 @@ attributes: # This is an optional field. log_names: [, ..., ] + # The log body must match at least one of the items. + # This is an optional field. + log_bodies: [, ..., ] + # The metric name must match at least one of the items. # This is an optional field. metric_names: [, ..., ]