From ccfd8b1034c92d23fb7226e536813140c4178f96 Mon Sep 17 00:00:00 2001 From: Daniel Jaglowski Date: Thu, 21 Sep 2023 14:54:29 -0600 Subject: [PATCH] [pkg/stanza] Add 'overwrite_text' option to severity parser (#27004) Resolves #26671 Resolves #26718 --- .../pkg-stanza-severity-text-overwrite.yaml | 28 +++++ pkg/stanza/entry/severity.go | 50 ++++---- pkg/stanza/entry/severity_test.go | 50 ++++---- pkg/stanza/operator/helper/severity.go | 8 +- .../operator/helper/severity_builder.go | 12 +- pkg/stanza/operator/helper/severity_test.go | 110 +++++++++++++++--- 6 files changed, 183 insertions(+), 75 deletions(-) create mode 100755 .chloggen/pkg-stanza-severity-text-overwrite.yaml diff --git a/.chloggen/pkg-stanza-severity-text-overwrite.yaml b/.chloggen/pkg-stanza-severity-text-overwrite.yaml new file mode 100755 index 000000000000..62d566c21e2a --- /dev/null +++ b/.chloggen/pkg-stanza-severity-text-overwrite.yaml @@ -0,0 +1,28 @@ +# 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: pkg/stanza + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add 'overwrite_text' option to severity parser. + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [26671] + +# (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: | + Allows the user to overwrite the text of the severity parser with the official string representation of the severity level. + +# 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: [] diff --git a/pkg/stanza/entry/severity.go b/pkg/stanza/entry/severity.go index f11a71a84a85..71e5eeb958b6 100644 --- a/pkg/stanza/entry/severity.go +++ b/pkg/stanza/entry/severity.go @@ -52,31 +52,31 @@ const ( ) var sevText = map[Severity]string{ - Default: "default", - Trace: "trace", - Trace2: "trace2", - Trace3: "trace3", - Trace4: "trace4", - Debug: "debug", - Debug2: "debug2", - Debug3: "debug3", - Debug4: "debug4", - Info: "info", - Info2: "info2", - Info3: "info3", - Info4: "info4", - Warn: "warn", - Warn2: "warn2", - Warn3: "warn3", - Warn4: "warn4", - Error: "error", - Error2: "error2", - Error3: "error3", - Error4: "error4", - Fatal: "fatal", - Fatal2: "fatal2", - Fatal3: "fatal3", - Fatal4: "fatal4", + Default: "DEFAULT", + Trace: "TRACE", + Trace2: "TRACE2", + Trace3: "TRACE3", + Trace4: "TRACE4", + Debug: "DEBUG", + Debug2: "DEBUG2", + Debug3: "DEBUG3", + Debug4: "DEBUG4", + Info: "INFO", + Info2: "INFO2", + Info3: "INFO3", + Info4: "INFO4", + Warn: "WARN", + Warn2: "WARN2", + Warn3: "WARN3", + Warn4: "WARN4", + Error: "ERROR", + Error2: "ERROR2", + Error3: "ERROR3", + Error4: "ERROR4", + Fatal: "FATAL", + Fatal2: "FATAL2", + Fatal3: "FATAL3", + Fatal4: "FATAL4", } // ToString converts a severity to a string diff --git a/pkg/stanza/entry/severity_test.go b/pkg/stanza/entry/severity_test.go index 1d03abc33218..9435b9141958 100644 --- a/pkg/stanza/entry/severity_test.go +++ b/pkg/stanza/entry/severity_test.go @@ -10,29 +10,29 @@ import ( ) func TestStringer(t *testing.T) { - require.Equal(t, "default", Default.String()) - require.Equal(t, "trace", Trace.String()) - require.Equal(t, "trace2", Trace2.String()) - require.Equal(t, "trace3", Trace3.String()) - require.Equal(t, "trace4", Trace4.String()) - require.Equal(t, "debug", Debug.String()) - require.Equal(t, "debug2", Debug2.String()) - require.Equal(t, "debug3", Debug3.String()) - require.Equal(t, "debug4", Debug4.String()) - require.Equal(t, "info", Info.String()) - require.Equal(t, "info2", Info2.String()) - require.Equal(t, "info3", Info3.String()) - require.Equal(t, "info4", Info4.String()) - require.Equal(t, "warn", Warn.String()) - require.Equal(t, "warn2", Warn2.String()) - require.Equal(t, "warn3", Warn3.String()) - require.Equal(t, "warn4", Warn4.String()) - require.Equal(t, "error", Error.String()) - require.Equal(t, "error2", Error2.String()) - require.Equal(t, "error3", Error3.String()) - require.Equal(t, "error4", Error4.String()) - require.Equal(t, "fatal", Fatal.String()) - require.Equal(t, "fatal2", Fatal2.String()) - require.Equal(t, "fatal3", Fatal3.String()) - require.Equal(t, "fatal4", Fatal4.String()) + require.Equal(t, "DEFAULT", Default.String()) + require.Equal(t, "TRACE", Trace.String()) + require.Equal(t, "TRACE2", Trace2.String()) + require.Equal(t, "TRACE3", Trace3.String()) + require.Equal(t, "TRACE4", Trace4.String()) + require.Equal(t, "DEBUG", Debug.String()) + require.Equal(t, "DEBUG2", Debug2.String()) + require.Equal(t, "DEBUG3", Debug3.String()) + require.Equal(t, "DEBUG4", Debug4.String()) + require.Equal(t, "INFO", Info.String()) + require.Equal(t, "INFO2", Info2.String()) + require.Equal(t, "INFO3", Info3.String()) + require.Equal(t, "INFO4", Info4.String()) + require.Equal(t, "WARN", Warn.String()) + require.Equal(t, "WARN2", Warn2.String()) + require.Equal(t, "WARN3", Warn3.String()) + require.Equal(t, "WARN4", Warn4.String()) + require.Equal(t, "ERROR", Error.String()) + require.Equal(t, "ERROR2", Error2.String()) + require.Equal(t, "ERROR3", Error3.String()) + require.Equal(t, "ERROR4", Error4.String()) + require.Equal(t, "FATAL", Fatal.String()) + require.Equal(t, "FATAL2", Fatal2.String()) + require.Equal(t, "FATAL3", Fatal3.String()) + require.Equal(t, "FATAL4", Fatal4.String()) } diff --git a/pkg/stanza/operator/helper/severity.go b/pkg/stanza/operator/helper/severity.go index 54d8d0dc0534..3194e3622db1 100644 --- a/pkg/stanza/operator/helper/severity.go +++ b/pkg/stanza/operator/helper/severity.go @@ -14,8 +14,9 @@ import ( // SeverityParser is a helper that parses severity onto an entry. type SeverityParser struct { - ParseFrom entry.Field - Mapping severityMap + ParseFrom entry.Field + Mapping severityMap + overwriteText bool } // Parse will parse severity from a field and attach it to the entry @@ -33,6 +34,9 @@ func (p *SeverityParser) Parse(ent *entry.Entry) error { if err != nil { return errors.Wrap(err, "parse") } + if p.overwriteText && severity != entry.Default { + sevText = severity.String() + } ent.Severity = severity ent.SeverityText = sevText diff --git a/pkg/stanza/operator/helper/severity_builder.go b/pkg/stanza/operator/helper/severity_builder.go index 13c277ecd0d7..2f11e0d4db60 100644 --- a/pkg/stanza/operator/helper/severity_builder.go +++ b/pkg/stanza/operator/helper/severity_builder.go @@ -111,9 +111,10 @@ func NewSeverityConfig() SeverityConfig { // SeverityConfig allows users to specify how to parse a severity from a field. type SeverityConfig struct { - ParseFrom *entry.Field `mapstructure:"parse_from,omitempty"` - Preset string `mapstructure:"preset,omitempty"` - Mapping map[string]interface{} `mapstructure:"mapping,omitempty"` + ParseFrom *entry.Field `mapstructure:"parse_from,omitempty"` + Preset string `mapstructure:"preset,omitempty"` + Mapping map[string]interface{} `mapstructure:"mapping,omitempty"` + OverwriteText bool `mapstructure:"overwrite_text,omitempty"` } // Build builds a SeverityParser from a SeverityConfig @@ -149,8 +150,9 @@ func (c *SeverityConfig) Build(_ *zap.SugaredLogger) (SeverityParser, error) { } p := SeverityParser{ - ParseFrom: *c.ParseFrom, - Mapping: operatorMapping, + ParseFrom: *c.ParseFrom, + Mapping: operatorMapping, + overwriteText: c.OverwriteText, } return p, nil diff --git a/pkg/stanza/operator/helper/severity_test.go b/pkg/stanza/operator/helper/severity_test.go index e059445118fc..67cd0fdcf579 100644 --- a/pkg/stanza/operator/helper/severity_test.go +++ b/pkg/stanza/operator/helper/severity_test.go @@ -17,13 +17,15 @@ import ( ) type severityTestCase struct { - name string - sample interface{} - mappingSet string - mapping map[string]interface{} - buildErr bool - parseErr bool - expected entry.Severity + name string + sample interface{} + mappingSet string + mapping map[string]interface{} + buildErr bool + parseErr bool + expected entry.Severity + expectedText string + overwriteText bool } // These tests ensure that users may build a mapping that @@ -146,16 +148,26 @@ var allTheThingsMap = map[string]interface{}{ func TestSeverityParser(t *testing.T) { testCases := []severityTestCase{ { - name: "unknown", - sample: "blah", - mapping: nil, - expected: entry.Default, + name: "unknown", + sample: "blah", + mapping: nil, + expected: entry.Default, + expectedText: "blah", }, { - name: "error", - sample: "error", - mapping: nil, - expected: entry.Error, + name: "error", + sample: "error", + mapping: nil, + expected: entry.Error, + expectedText: "error", + }, + { + name: "error-overwrite-text", + sample: "error", + mapping: nil, + expected: entry.Error, + expectedText: "ERROR", + overwriteText: true, }, { name: "error2", @@ -181,6 +193,14 @@ func TestSeverityParser(t *testing.T) { mapping: nil, expected: entry.Error, }, + { + name: "error-capitalized-overwrite-text", + sample: "Error", + mapping: nil, + expected: entry.Error, + expectedText: "ERROR", + overwriteText: true, + }, { name: "error-all-caps", sample: "ERROR", @@ -193,6 +213,14 @@ func TestSeverityParser(t *testing.T) { mapping: map[string]interface{}{"error": "NOOOOOOO"}, expected: entry.Error, }, + { + name: "custom-string-overwrite-text", + sample: "NOOOOOOO", + mapping: map[string]interface{}{"error": "NOOOOOOO"}, + expected: entry.Error, + expectedText: "ERROR", + overwriteText: true, + }, { name: "custom-string-caps-key", sample: "NOOOOOOO", @@ -205,6 +233,14 @@ func TestSeverityParser(t *testing.T) { mapping: map[string]interface{}{"error": 1234}, expected: entry.Error, }, + { + name: "custom-int-overwrite-text", + sample: 1234, + mapping: map[string]interface{}{"error": 1234}, + expected: entry.Error, + expectedText: "ERROR", + overwriteText: true, + }, { name: "mixed-list-string", sample: "ThiS Is BaD", @@ -229,6 +265,14 @@ func TestSeverityParser(t *testing.T) { mapping: map[string]interface{}{"error2": "critical"}, expected: entry.Error2, }, + { + name: "numbered-level-overwrite-text", + sample: "critical", + mapping: map[string]interface{}{"error2": "critical"}, + expected: entry.Error2, + expectedText: "ERROR2", + overwriteText: true, + }, { name: "override-standard", sample: "error", @@ -247,6 +291,14 @@ func TestSeverityParser(t *testing.T) { mapping: map[string]interface{}{"error": map[string]interface{}{"min": 120, "max": 125}}, expected: entry.Error, }, + { + name: "in-range-overwrite-text", + sample: 123, + mapping: map[string]interface{}{"error": map[string]interface{}{"min": 120, "max": 125}}, + expected: entry.Error, + expectedText: "ERROR", + overwriteText: true, + }, { name: "in-range-min", sample: 120, @@ -313,6 +365,14 @@ func TestSeverityParser(t *testing.T) { mapping: map[string]interface{}{"debug": "2xx", "info": "3xx", "error": "4xx", "warn": "5xx"}, expected: entry.Info, }, + { + name: "Http-All-Overwrite-Text", + sample: "301", + mapping: map[string]interface{}{"debug": "2xx", "info": "3xx", "error": "4xx", "warn": "5xx"}, + expected: entry.Info, + expectedText: "INFO", + overwriteText: true, + }, { name: "all-the-things-midrange", sample: 1234, @@ -337,6 +397,14 @@ func TestSeverityParser(t *testing.T) { mapping: allTheThingsMap, expected: entry.Default, }, + { + name: "all-the-things-miss-never-overwrite-unknown", + sample: "miss", + mapping: allTheThingsMap, + expected: entry.Default, + expectedText: "miss", + overwriteText: true, + }, { name: "base-mapping-none", sample: "error", @@ -438,9 +506,10 @@ func (tc severityTestCase) run(parseFrom entry.Field) func(*testing.T) { t.Parallel() cfg := &SeverityConfig{ - ParseFrom: &parseFrom, - Preset: tc.mappingSet, - Mapping: tc.mapping, + ParseFrom: &parseFrom, + Preset: tc.mappingSet, + Mapping: tc.mapping, + OverwriteText: tc.overwriteText, } severityParser, err := cfg.Build(testutil.Logger(t)) @@ -460,6 +529,11 @@ func (tc severityTestCase) run(parseFrom entry.Field) func(*testing.T) { require.NoError(t, err) require.Equal(t, tc.expected, ent.Severity) + if tc.overwriteText { + require.Equal(t, tc.expectedText, ent.SeverityText) + } else { + require.Equal(t, fmt.Sprint(tc.sample), ent.SeverityText) + } } }