From 7d4beeef0ef4afe5fa534ed205b1dceb9c6a03d6 Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Wed, 9 Sep 2026 10:49:09 +0200 Subject: [PATCH 01/13] fix whitelist monitor path --- .../receiver/monitorreceiver/receiver.go | 30 ++++- .../receiver/monitorreceiver/receiver_test.go | 113 ++++++++++++++++++ 2 files changed, 140 insertions(+), 3 deletions(-) diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver.go b/pkg/splunkta/receiver/monitorreceiver/receiver.go index b1450fc..124f528 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver.go @@ -5,6 +5,7 @@ package monitorreceiver import ( "path/filepath" + "strings" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/adapter" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/entry" @@ -79,12 +80,35 @@ func (t monitor) InputConfig(config component.Config) operator.Config { t.logger.Error("error reading command", zap.Error(err)) return operator.NewConfig(oc) } - allowlist := path - if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil { + // pathIsGlob reports whether the path already contains glob metacharacters + // (e.g. monitor:///home/*/.bash_history). In that case filelog can use it + // directly without further expansion. + pathIsGlob := strings.ContainsAny(path, "*?[") + + w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist") + var allowlist string + switch { + case pathIsGlob: + // Path is already a glob pattern — use it as-is; whitelist is ignored + // because there is no sensible directory to join it against. + allowlist = path + case w != nil && w.Value != "": + // whitelist is a glob pattern relative to the monitored directory + // (e.g. "*.log"). Splunk also supports regex here, but glob is the + // common case and what filelog's Include field accepts. allowlist = filepath.Join(path, w.Value) + case w != nil: + // whitelist param is present but empty: the stanza targets a directory + // and wants all files inside it. A bare directory is not a valid filelog + // glob — append /* to match files directly under the directory. + allowlist = filepath.Join(path, "*") + default: + // No whitelist param at all: path may be a specific file, a directory, + // or already a glob — use it as-is. + allowlist = path } oc.Include = []string{allowlist} - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil { + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && b.Value != "" { oc.Exclude = []string{filepath.Join(path, b.Value)} } if hostParam := rcfg.Input.Configuration.Stanza.Params.Get("host"); hostParam != nil { diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver_test.go b/pkg/splunkta/receiver/monitorreceiver/receiver_test.go index 6c49d92..b98f73e 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver_test.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver_test.go @@ -9,6 +9,7 @@ import ( "os" "path/filepath" "testing" + "time" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/entry" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator" @@ -25,6 +26,118 @@ import ( "github.com/splunk/tarunner/pkg/splunkta/conf" ) +// TestMonitorDirectoryWithSplunkRegexWhitelist tests the exact Splunk_TA_nix default stanza: +// +// [monitor:///var/log] +// whitelist=(\.log|log$|messages|secure|auth|mesg$|cron$|acpid$|\.out) +// blacklist=(lastlog|anaconda\.syslog) +// +// Splunk whitelist/blacklist values are regexes, not globs. Since filelog's Include/Exclude +// only accept glob patterns, the regex is used as a filepath.Join component which produces +// an invalid path (dir/(\.log|log$|...)) that never matches real files. +// This test documents the known limitation: the non-empty regex whitelist does NOT work. +// The fix is to set whitelist= (empty) in the TA overlay, tested by TestMonitorDirectoryEmptyWhitelist. +func TestMonitorDirectoryWithSplunkRegexWhitelist(t *testing.T) { + tempDir := t.TempDir() + + // Exact values from Splunk_TA_nix default/inputs.conf + const whitelist = `(\.log|log$|messages|secure|auth|mesg$|cron$|acpid$|\.out)` + const blacklist = `(lastlog|anaconda\.syslog)` + + cfg := Config{ + Input: conf.Input{ + Configuration: conf.Configuration{ + Stanza: conf.Stanza{ + Name: fmt.Sprintf("monitor://%s", tempDir), + Params: conf.Params{ + conf.Param{Name: "whitelist", Value: whitelist}, + conf.Param{Name: "blacklist", Value: blacklist}, + conf.Param{Name: "index", Value: "otel_nix"}, + }, + }, + }, + }, + } + logger, _ := zap.NewDevelopment() + c := monitor{logger: logger}.InputConfig(cfg) + o, err := c.Build(component.TelemetrySettings{ + Logger: logger, + TracerProvider: nooptrace.NewTracerProvider(), + MeterProvider: noopmetric.NewMeterProvider(), + Resource: pcommon.NewResource(), + }) + require.NoError(t, err) + output := testutil.NewFakeOutput(t) + o.SetOutputIDs([]string{"fake"}) + require.NoError(t, o.SetOutputs([]operator.Operator{output})) + require.NoError(t, o.Start(nil)) + defer func() { require.NoError(t, o.Stop()) }() + + // Write files that would match the Splunk whitelist regex. + require.NoError(t, os.WriteFile(filepath.Join(tempDir, "syslog.log"), []byte("line1\n"), 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(tempDir, "auth"), []byte("line2\n"), 0o644)) + + // The regex whitelist is not a valid glob, so no files are matched and nothing is ingested. + // This test asserts the known broken behaviour so any future fix is immediately visible: + // if a file IS received, regex whitelist handling has been improved and this test needs updating. + select { + case got := <-output.Received: + t.Logf("NOTE: regex whitelist now works — received body=%q from source=%q; update this test to assert correct filtering", got.Body, got.Attributes["source"]) + case <-time.After(400 * time.Millisecond): + // Expected: nothing received because the regex is not a valid glob pattern. + } +} + +// TestMonitorDirectoryEmptyWhitelist mirrors the real-life Splunk_TA_nix stanza after the +// overlay sets whitelist= (empty) to bypass the Splunk regex value that is not a valid glob: +// +// [monitor:///var/log] +// whitelist= +// blacklist= +// +// An empty whitelist on a plain directory path must expand to dir/* so that filelog +// can actually match files. Without this expansion the operator receives a bare directory +// path which never matches any file. +func TestMonitorDirectoryEmptyWhitelist(t *testing.T) { + tempDir := t.TempDir() + + cfg := Config{ + Input: conf.Input{ + Configuration: conf.Configuration{ + Stanza: conf.Stanza{ + Name: fmt.Sprintf("monitor://%s", tempDir), + Params: conf.Params{ + conf.Param{Name: "whitelist", Value: ""}, + conf.Param{Name: "blacklist", Value: ""}, + conf.Param{Name: "index", Value: "otel_nix"}, + }, + }, + }, + }, + } + logger, _ := zap.NewDevelopment() + c := monitor{logger: logger}.InputConfig(cfg) + o, err := c.Build(component.TelemetrySettings{ + Logger: logger, + TracerProvider: nooptrace.NewTracerProvider(), + MeterProvider: noopmetric.NewMeterProvider(), + Resource: pcommon.NewResource(), + }) + require.NoError(t, err) + output := testutil.NewFakeOutput(t) + o.SetOutputIDs([]string{"fake"}) + require.NoError(t, o.SetOutputs([]operator.Operator{output})) + require.NoError(t, o.Start(nil)) + defer func() { require.NoError(t, o.Stop()) }() + + require.NoError(t, os.WriteFile(filepath.Join(tempDir, "syslog"), []byte("hello log\n"), 0o644)) + received := <-output.Received + require.Equal(t, "hello log\n", received.Body) + // InputConfig sets the raw "index" attribute; renameMetadata (wired by the adapter) + // moves it to "com.splunk.index" in the full pipeline. + require.Equal(t, "otel_nix", received.Attributes["index"]) +} + func TestReadFile(t *testing.T) { tempDir := t.TempDir() From ff386de4d176d8f2a9e8bfdd25d1be001a00a5ab Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Wed, 9 Sep 2026 12:43:10 +0200 Subject: [PATCH 02/13] fix whitelist monitor path --- .../receiver/batchreceiver/receiver.go | 18 ++++++++- .../receiver/monitorreceiver/receiver.go | 21 +++++++---- .../receiver/monitorreceiver/receiver_test.go | 37 +++++++++++-------- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/pkg/splunkta/receiver/batchreceiver/receiver.go b/pkg/splunkta/receiver/batchreceiver/receiver.go index 07a92fd..49838aa 100644 --- a/pkg/splunkta/receiver/batchreceiver/receiver.go +++ b/pkg/splunkta/receiver/batchreceiver/receiver.go @@ -5,6 +5,7 @@ package batchreceiver import ( "path/filepath" + "strings" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/adapter" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/entry" @@ -82,10 +83,15 @@ func (t batch) InputConfig(config component.Config) operator.Config { } allowlist := path if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil { - allowlist = filepath.Join(path, w.Value) + if isGlobPattern(w.Value) { + allowlist = filepath.Join(path, w.Value) + } else { + // empty or Splunk regex — match all files under the directory + allowlist = filepath.Join(path, "*") + } } oc.Include = []string{allowlist} - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil { + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && isGlobPattern(b.Value) { oc.Exclude = []string{filepath.Join(path, b.Value)} } if hostParam := rcfg.Input.Configuration.Stanza.Params.Get("host"); hostParam != nil { @@ -119,6 +125,14 @@ func (t batch) InputConfig(config component.Config) operator.Config { return operator.NewConfig(oc) } +// isGlobPattern reports whether s is a glob pattern suitable for filelog's +// Include/Exclude fields. Splunk whitelist/blacklist values can be either +// glob patterns (containing *, ?, or [) or PCRE regexes (containing (, |, +// $, or \). The latter are not valid globs and must not be passed to filelog. +func isGlobPattern(s string) bool { + return s != "" && strings.ContainsAny(s, "*?[") && !strings.ContainsAny(s, "(|$\\") +} + func renameMetadata() []operator.Config { source := move.NewConfigWithID("end-source") source.From = entry.NewAttributeField("source") diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver.go b/pkg/splunkta/receiver/monitorreceiver/receiver.go index 124f528..cc5a45d 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver.go @@ -92,15 +92,14 @@ func (t monitor) InputConfig(config component.Config) operator.Config { // Path is already a glob pattern — use it as-is; whitelist is ignored // because there is no sensible directory to join it against. allowlist = path - case w != nil && w.Value != "": + case w != nil && isGlobPattern(w.Value): // whitelist is a glob pattern relative to the monitored directory - // (e.g. "*.log"). Splunk also supports regex here, but glob is the - // common case and what filelog's Include field accepts. + // (e.g. "*.log"). allowlist = filepath.Join(path, w.Value) case w != nil: - // whitelist param is present but empty: the stanza targets a directory - // and wants all files inside it. A bare directory is not a valid filelog - // glob — append /* to match files directly under the directory. + // whitelist param is present but either empty or a Splunk regex (which + // is not a valid filelog glob). In both cases match all files directly + // under the directory. allowlist = filepath.Join(path, "*") default: // No whitelist param at all: path may be a specific file, a directory, @@ -108,7 +107,7 @@ func (t monitor) InputConfig(config component.Config) operator.Config { allowlist = path } oc.Include = []string{allowlist} - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && b.Value != "" { + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && isGlobPattern(b.Value) { oc.Exclude = []string{filepath.Join(path, b.Value)} } if hostParam := rcfg.Input.Configuration.Stanza.Params.Get("host"); hostParam != nil { @@ -142,6 +141,14 @@ func (t monitor) InputConfig(config component.Config) operator.Config { return operator.NewConfig(oc) } +// isGlobPattern reports whether s is a glob pattern suitable for filelog's +// Include/Exclude fields. Splunk whitelist/blacklist values can be either +// glob patterns (containing *, ?, or [) or PCRE regexes (containing (, |, +// $, or \). The latter are not valid globs and must not be passed to filelog. +func isGlobPattern(s string) bool { + return s != "" && strings.ContainsAny(s, "*?[") && !strings.ContainsAny(s, "(|$\\") +} + func renameMetadata() []operator.Config { source := move.NewConfigWithID("end-source") source.From = entry.NewAttributeField("source") diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver_test.go b/pkg/splunkta/receiver/monitorreceiver/receiver_test.go index b98f73e..4e42b43 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver_test.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver_test.go @@ -26,17 +26,17 @@ import ( "github.com/splunk/tarunner/pkg/splunkta/conf" ) -// TestMonitorDirectoryWithSplunkRegexWhitelist tests the exact Splunk_TA_nix default stanza: +// TestMonitorDirectoryWithSplunkRegexWhitelist tests the exact Splunk_TA_nix default stanza +// merged with a local overlay that only sets disabled=0 and index: // -// [monitor:///var/log] +// [monitor:///var/log] # default TA layer // whitelist=(\.log|log$|messages|secure|auth|mesg$|cron$|acpid$|\.out) // blacklist=(lastlog|anaconda\.syslog) // -// Splunk whitelist/blacklist values are regexes, not globs. Since filelog's Include/Exclude -// only accept glob patterns, the regex is used as a filepath.Join component which produces -// an invalid path (dir/(\.log|log$|...)) that never matches real files. -// This test documents the known limitation: the non-empty regex whitelist does NOT work. -// The fix is to set whitelist= (empty) in the TA overlay, tested by TestMonitorDirectoryEmptyWhitelist. +// The whitelist/blacklist values are PCRE regexes, not globs. The receiver detects +// this and falls back to dir/* so that all files are ingested (the TA overlay is +// expected to narrow scope via a glob whitelist if needed, but must not break the +// common case where no overlay whitelist is set). func TestMonitorDirectoryWithSplunkRegexWhitelist(t *testing.T) { tempDir := t.TempDir() @@ -73,19 +73,24 @@ func TestMonitorDirectoryWithSplunkRegexWhitelist(t *testing.T) { require.NoError(t, o.Start(nil)) defer func() { require.NoError(t, o.Stop()) }() - // Write files that would match the Splunk whitelist regex. require.NoError(t, os.WriteFile(filepath.Join(tempDir, "syslog.log"), []byte("line1\n"), 0o644)) require.NoError(t, os.WriteFile(filepath.Join(tempDir, "auth"), []byte("line2\n"), 0o644)) - // The regex whitelist is not a valid glob, so no files are matched and nothing is ingested. - // This test asserts the known broken behaviour so any future fix is immediately visible: - // if a file IS received, regex whitelist handling has been improved and this test needs updating. - select { - case got := <-output.Received: - t.Logf("NOTE: regex whitelist now works — received body=%q from source=%q; update this test to assert correct filtering", got.Body, got.Attributes["source"]) - case <-time.After(400 * time.Millisecond): - // Expected: nothing received because the regex is not a valid glob pattern. + // The regex whitelist is not a valid glob; the receiver falls back to dir/* + // so both files must be ingested. + received := map[string]bool{} + deadline := time.After(3 * time.Second) + for len(received) < 2 { + select { + case got := <-output.Received: + name, _ := got.Attributes["log.file.name"].(string) + received[name] = true + case <-deadline: + t.Fatalf("timeout waiting for files; got: %v", received) + } } + require.True(t, received["syslog.log"], "expected syslog.log to be ingested") + require.True(t, received["auth"], "expected auth to be ingested") } // TestMonitorDirectoryEmptyWhitelist mirrors the real-life Splunk_TA_nix stanza after the From 1fefdaa98b8405fd30063711b104d9936e6f5b86 Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:25:56 +0200 Subject: [PATCH 03/13] fix whitelist monitor path --- .../receiver/monitorreceiver/receiver.go | 12 ++++-- .../receiver/monitorreceiver/receiver_test.go | 38 +++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver.go b/pkg/splunkta/receiver/monitorreceiver/receiver.go index cc5a45d..98dfa95 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver.go @@ -4,6 +4,7 @@ package monitorreceiver import ( + "os" "path/filepath" "strings" @@ -102,9 +103,14 @@ func (t monitor) InputConfig(config component.Config) operator.Config { // under the directory. allowlist = filepath.Join(path, "*") default: - // No whitelist param at all: path may be a specific file, a directory, - // or already a glob — use it as-is. - allowlist = path + // No whitelist param: if the path is a directory, expand to dir/* so + // filelog can match files inside it. If it's a specific file (or the + // path doesn't exist yet), use it as-is. + if info, err := os.Stat(path); err == nil && info.IsDir() { + allowlist = filepath.Join(path, "*") + } else { + allowlist = path + } } oc.Include = []string{allowlist} if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && isGlobPattern(b.Value) { diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver_test.go b/pkg/splunkta/receiver/monitorreceiver/receiver_test.go index 4e42b43..1f8553e 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver_test.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver_test.go @@ -143,6 +143,44 @@ func TestMonitorDirectoryEmptyWhitelist(t *testing.T) { require.Equal(t, "otel_nix", received.Attributes["index"]) } +// TestMonitorDirectoryNoWhitelist covers the case where the local overlay only +// sets disabled=0 and index, and the TA default has no whitelist param at all. +// The receiver must detect that the path is a directory and expand it to dir/*. +func TestMonitorDirectoryNoWhitelist(t *testing.T) { + tempDir := t.TempDir() + + cfg := Config{ + Input: conf.Input{ + Configuration: conf.Configuration{ + Stanza: conf.Stanza{ + Name: fmt.Sprintf("monitor://%s", tempDir), + Params: conf.Params{ + conf.Param{Name: "index", Value: "otel_nix"}, + }, + }, + }, + }, + } + logger, _ := zap.NewDevelopment() + c := monitor{logger: logger}.InputConfig(cfg) + o, err := c.Build(component.TelemetrySettings{ + Logger: logger, + TracerProvider: nooptrace.NewTracerProvider(), + MeterProvider: noopmetric.NewMeterProvider(), + Resource: pcommon.NewResource(), + }) + require.NoError(t, err) + output := testutil.NewFakeOutput(t) + o.SetOutputIDs([]string{"fake"}) + require.NoError(t, o.SetOutputs([]operator.Operator{output})) + require.NoError(t, o.Start(nil)) + defer func() { require.NoError(t, o.Stop()) }() + + require.NoError(t, os.WriteFile(filepath.Join(tempDir, "syslog"), []byte("hello log\n"), 0o644)) + received := <-output.Received + require.Equal(t, "hello log\n", received.Body) +} + func TestReadFile(t *testing.T) { tempDir := t.TempDir() From 98bfd9b67294c9f64102a77adda9fb2c5f669061 Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:29:02 +0200 Subject: [PATCH 04/13] fix whitelist monitor path --- pkg/splunkta/receiver/monitorreceiver/receiver.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver.go b/pkg/splunkta/receiver/monitorreceiver/receiver.go index 98dfa95..cf67f30 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver.go @@ -113,8 +113,17 @@ func (t monitor) InputConfig(config component.Config) operator.Config { } } oc.Include = []string{allowlist} + t.logger.Info("monitor receiver include pattern", + zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), + zap.String("path", path), + zap.String("include", allowlist), + ) if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && isGlobPattern(b.Value) { oc.Exclude = []string{filepath.Join(path, b.Value)} + t.logger.Info("monitor receiver exclude pattern", + zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), + zap.String("exclude", oc.Exclude[0]), + ) } if hostParam := rcfg.Input.Configuration.Stanza.Params.Get("host"); hostParam != nil { // TODO: find a way to run host detection when requested. From 9deaf079c2d53b9e9e5ca44abe43a56ec79be25c Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:48:01 +0200 Subject: [PATCH 05/13] fix disable/enable flag in Splunk TA --- pkg/splunkta/conf/inputs.go | 4 ++-- pkg/splunkta/conf/inputs_test.go | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/pkg/splunkta/conf/inputs.go b/pkg/splunkta/conf/inputs.go index 9e3374e..ee2b75e 100644 --- a/pkg/splunkta/conf/inputs.go +++ b/pkg/splunkta/conf/inputs.go @@ -24,10 +24,10 @@ type Input struct { Configuration Configuration `xml:"configuration"` } -// IsDisabled reports whether the stanza has disabled=1. +// IsDisabled reports whether the stanza has disabled=1 or disabled=true. func (s *Stanza) IsDisabled() bool { p := s.Params.Get("disabled") - return p != nil && p.Value == "1" + return p != nil && (p.Value == "1" || p.Value == "true") } func ReadInput(payload []byte, appDir string) ([]Input, error) { diff --git a/pkg/splunkta/conf/inputs_test.go b/pkg/splunkta/conf/inputs_test.go index 81c7ef5..8d9c510 100644 --- a/pkg/splunkta/conf/inputs_test.go +++ b/pkg/splunkta/conf/inputs_test.go @@ -144,6 +144,25 @@ func TestMergeInputsFullOverride(t *testing.T) { assert.Equal(t, "index_override", merged[0].Configuration.Stanza.Params.Get("index").Value) } +func TestIsDisabled(t *testing.T) { + cases := []struct { + value string + disabled bool + }{ + {"1", true}, + {"true", true}, + {"0", false}, + {"false", false}, + {"", false}, + } + for _, tc := range cases { + s := Stanza{Params: Params{{Name: "disabled", Value: tc.value}}} + assert.Equal(t, tc.disabled, s.IsDisabled(), "disabled=%q", tc.value) + } + // No disabled param at all. + assert.False(t, (&Stanza{}).IsDisabled()) +} + func TestToXML(t *testing.T) { testStr := ` From e379d3c72c510327e86769437fb2fdbedfb5de95 Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Thu, 10 Sep 2026 10:06:53 +0200 Subject: [PATCH 06/13] support regexes in whitelist and blacklist --- .../receiver/monitorreceiver/receiver.go | 34 +++++++ .../receiver/monitorreceiver/receiver_test.go | 88 ++++++++++++++++++- 2 files changed, 118 insertions(+), 4 deletions(-) diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver.go b/pkg/splunkta/receiver/monitorreceiver/receiver.go index cf67f30..1938b5e 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver.go @@ -4,6 +4,7 @@ package monitorreceiver import ( + "fmt" "os" "path/filepath" "strings" @@ -13,6 +14,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/helper" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/input/file" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/filter" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/move" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/noop" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/split" @@ -46,6 +48,16 @@ func createDefaultConfig() *Config { func (monitor) BaseConfig(cfg component.Config) adapter.BaseConfig { rcfg := cfg.(Config) var operators []operator.Config + + // Insert PCRE whitelist/blacklist filters before any other processing. + // The log.file.path attribute is set by filelog and available here. + if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && isPCREPattern(w.Value) { + operators = append(operators, createWhitelistFilterOperator(w.Value)) + } + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && isPCREPattern(b.Value) { + operators = append(operators, createBlacklistFilterOperator(b.Value)) + } + operators = append(operators, createSetSourceOperator()) for _, p := range rcfg.Props { @@ -65,6 +77,22 @@ func (monitor) BaseConfig(cfg component.Config) adapter.BaseConfig { } } +// createWhitelistFilterOperator drops entries whose log.file.path does NOT match the regex. +// filter drops entries when expression is true — drop if path does NOT match whitelist. +func createWhitelistFilterOperator(regex string) operator.Config { + c := filter.NewConfigWithID("whitelist-filter") + c.Expression = fmt.Sprintf(`!(attributes["log.file.path"] matches %q)`, regex) + return operator.NewConfig(c) +} + +// createBlacklistFilterOperator drops entries whose log.file.path matches the regex. +// filter drops entries when expression is true — drop if path matches blacklist. +func createBlacklistFilterOperator(regex string) operator.Config { + c := filter.NewConfigWithID("blacklist-filter") + c.Expression = fmt.Sprintf(`attributes["log.file.path"] matches %q`, regex) + return operator.NewConfig(c) +} + func createSetSourceOperator() operator.Config { c := move.NewConfigWithID("start") c.From = entry.NewAttributeField("log.file.path") @@ -164,6 +192,12 @@ func isGlobPattern(s string) bool { return s != "" && strings.ContainsAny(s, "*?[") && !strings.ContainsAny(s, "(|$\\") } +// isPCREPattern reports whether s looks like a PCRE regex — i.e. contains +// characters that are meaningful in PCRE but not in glob patterns. +func isPCREPattern(s string) bool { + return s != "" && strings.ContainsAny(s, "(|$\\.+?^") +} + func renameMetadata() []operator.Config { source := move.NewConfigWithID("end-source") source.From = entry.NewAttributeField("source") diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver_test.go b/pkg/splunkta/receiver/monitorreceiver/receiver_test.go index 1f8553e..e3018e8 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver_test.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver_test.go @@ -33,10 +33,9 @@ import ( // whitelist=(\.log|log$|messages|secure|auth|mesg$|cron$|acpid$|\.out) // blacklist=(lastlog|anaconda\.syslog) // -// The whitelist/blacklist values are PCRE regexes, not globs. The receiver detects -// this and falls back to dir/* so that all files are ingested (the TA overlay is -// expected to narrow scope via a glob whitelist if needed, but must not break the -// common case where no overlay whitelist is set). +// The whitelist/blacklist values are PCRE regexes. InputConfig sets include=dir/* and +// BaseConfig wires a filter operator to apply the regex against log.file.path. +// This test only exercises InputConfig (include path), not the full filter pipeline. func TestMonitorDirectoryWithSplunkRegexWhitelist(t *testing.T) { tempDir := t.TempDir() @@ -250,3 +249,84 @@ func TestRenameMetadata(t *testing.T) { require.Equal(t, "srctype", result.Attributes["com.splunk.sourcetype"]) require.Equal(t, "foo", result.Attributes["host.name"]) } + +// TestPCREWhitelistFilter verifies that createWhitelistFilterOperator passes entries +// whose log.file.path matches the regex and drops those that don't. +func TestPCREWhitelistFilter(t *testing.T) { + const regex = `(\.log|log$|messages|secure|auth)` + ops := []operator.Config{createWhitelistFilterOperator(regex)} + output := testutil.NewFakeOutput(t) + pipe, err := pipeline.Config{ + Operators: ops, + DefaultOutput: output, + }.Build(componenttest.NewNopTelemetrySettings()) + require.NoError(t, err) + require.NoError(t, pipe.Start(nil)) + defer func() { require.NoError(t, pipe.Stop()) }() + + send := func(path string) { + require.NoError(t, pipe.Operators()[0].Process(context.Background(), &entry.Entry{ + Attributes: map[string]any{"log.file.path": path}, + })) + } + + send("/var/log/syslog.log") // matches \.log — should pass + send("/var/log/auth") // matches auth — should pass + send("/var/log/wtmp") // does not match any alternative — should be dropped + + // Collect with timeout + received := map[string]bool{} + deadline := time.After(500 * time.Millisecond) + for { + select { + case e := <-output.Received: + received[e.Attributes["log.file.path"].(string)] = true + case <-deadline: + goto done + } + } +done: + require.True(t, received["/var/log/syslog.log"], "syslog.log should pass whitelist") + require.True(t, received["/var/log/auth"], "auth should pass whitelist") + require.False(t, received["/var/log/wtmp"], "wtmp should be dropped by whitelist") +} + +// TestPCREBlacklistFilter verifies that createBlacklistFilterOperator drops entries +// whose log.file.path matches the regex and passes those that don't. +func TestPCREBlacklistFilter(t *testing.T) { + const regex = `(lastlog|anaconda\.syslog)` + ops := []operator.Config{createBlacklistFilterOperator(regex)} + output := testutil.NewFakeOutput(t) + pipe, err := pipeline.Config{ + Operators: ops, + DefaultOutput: output, + }.Build(componenttest.NewNopTelemetrySettings()) + require.NoError(t, err) + require.NoError(t, pipe.Start(nil)) + defer func() { require.NoError(t, pipe.Stop()) }() + + send := func(path string) { + require.NoError(t, pipe.Operators()[0].Process(context.Background(), &entry.Entry{ + Attributes: map[string]any{"log.file.path": path}, + })) + } + + send("/var/log/syslog.log") // not in blacklist — should pass + send("/var/log/lastlog") // matches blacklist — should be dropped + send("/var/log/anaconda.syslog") // matches blacklist — should be dropped + + received := map[string]bool{} + deadline := time.After(500 * time.Millisecond) + for { + select { + case e := <-output.Received: + received[e.Attributes["log.file.path"].(string)] = true + case <-deadline: + goto done + } + } +done: + require.True(t, received["/var/log/syslog.log"], "syslog.log should pass blacklist") + require.False(t, received["/var/log/lastlog"], "lastlog should be dropped by blacklist") + require.False(t, received["/var/log/anaconda.syslog"], "anaconda.syslog should be dropped by blacklist") +} From 5a0fd30db6cb6ebb8be5f9ae06407fd8d720a38d Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Thu, 10 Sep 2026 10:52:28 +0200 Subject: [PATCH 07/13] share whitelist and blacklist between monitor and batch receiver --- .../receiver/batchreceiver/receiver.go | 52 +++++++++++++------ .../receiver/monitorreceiver/receiver.go | 49 ++++------------- .../receiver/monitorreceiver/receiver_test.go | 5 +- 3 files changed, 49 insertions(+), 57 deletions(-) diff --git a/pkg/splunkta/receiver/batchreceiver/receiver.go b/pkg/splunkta/receiver/batchreceiver/receiver.go index 49838aa..d35e0da 100644 --- a/pkg/splunkta/receiver/batchreceiver/receiver.go +++ b/pkg/splunkta/receiver/batchreceiver/receiver.go @@ -4,6 +4,7 @@ package batchreceiver import ( + "os" "path/filepath" "strings" @@ -20,6 +21,7 @@ import ( "go.uber.org/zap" "github.com/splunk/tarunner/pkg/splunkta/operator/prop" + "github.com/splunk/tarunner/pkg/splunkta/receiver/filter" "github.com/splunk/tarunner/pkg/splunkta/script" ) @@ -45,6 +47,16 @@ func createDefaultConfig() *Config { func (batch) BaseConfig(cfg component.Config) adapter.BaseConfig { rcfg := cfg.(Config) var operators []operator.Config + + // Insert PCRE whitelist/blacklist filters before any other processing. + // The log.file.path attribute is set by filelog and available here. + if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && filter.IsPCREPattern(w.Value) { + operators = append(operators, filter.NewWhitelistOperator(w.Value)) + } + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && filter.IsPCREPattern(b.Value) { + operators = append(operators, filter.NewBlacklistOperator(b.Value)) + } + operators = append(operators, createSetSourceOperator()) for _, p := range rcfg.Props { @@ -81,18 +93,36 @@ func (t batch) InputConfig(config component.Config) operator.Config { t.logger.Error("error reading command", zap.Error(err)) return operator.NewConfig(oc) } - allowlist := path - if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil { - if isGlobPattern(w.Value) { - allowlist = filepath.Join(path, w.Value) - } else { - // empty or Splunk regex — match all files under the directory + pathIsGlob := strings.ContainsAny(path, "*?[") + w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist") + var allowlist string + switch { + case pathIsGlob: + allowlist = path + case w != nil && filter.IsGlobPattern(w.Value): + allowlist = filepath.Join(path, w.Value) + case w != nil: + // empty or Splunk regex — match all files under the directory + allowlist = filepath.Join(path, "*") + default: + if info, err := os.Stat(path); err == nil && info.IsDir() { allowlist = filepath.Join(path, "*") + } else { + allowlist = path } } oc.Include = []string{allowlist} - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && isGlobPattern(b.Value) { + t.logger.Debug("batch receiver include pattern", + zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), + zap.String("path", path), + zap.String("include", allowlist), + ) + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && filter.IsGlobPattern(b.Value) { oc.Exclude = []string{filepath.Join(path, b.Value)} + t.logger.Debug("batch receiver exclude pattern", + zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), + zap.String("exclude", oc.Exclude[0]), + ) } if hostParam := rcfg.Input.Configuration.Stanza.Params.Get("host"); hostParam != nil { // TODO: find a way to run host detection when requested. @@ -125,14 +155,6 @@ func (t batch) InputConfig(config component.Config) operator.Config { return operator.NewConfig(oc) } -// isGlobPattern reports whether s is a glob pattern suitable for filelog's -// Include/Exclude fields. Splunk whitelist/blacklist values can be either -// glob patterns (containing *, ?, or [) or PCRE regexes (containing (, |, -// $, or \). The latter are not valid globs and must not be passed to filelog. -func isGlobPattern(s string) bool { - return s != "" && strings.ContainsAny(s, "*?[") && !strings.ContainsAny(s, "(|$\\") -} - func renameMetadata() []operator.Config { source := move.NewConfigWithID("end-source") source.From = entry.NewAttributeField("source") diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver.go b/pkg/splunkta/receiver/monitorreceiver/receiver.go index 1938b5e..6f816d2 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver.go @@ -4,7 +4,6 @@ package monitorreceiver import ( - "fmt" "os" "path/filepath" "strings" @@ -14,7 +13,6 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/helper" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/input/file" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/filter" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/move" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/noop" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/split" @@ -23,6 +21,7 @@ import ( "go.uber.org/zap" "github.com/splunk/tarunner/pkg/splunkta/operator/prop" + "github.com/splunk/tarunner/pkg/splunkta/receiver/filter" "github.com/splunk/tarunner/pkg/splunkta/script" ) @@ -51,11 +50,11 @@ func (monitor) BaseConfig(cfg component.Config) adapter.BaseConfig { // Insert PCRE whitelist/blacklist filters before any other processing. // The log.file.path attribute is set by filelog and available here. - if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && isPCREPattern(w.Value) { - operators = append(operators, createWhitelistFilterOperator(w.Value)) + if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && filter.IsPCREPattern(w.Value) { + operators = append(operators, filter.NewWhitelistOperator(w.Value)) } - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && isPCREPattern(b.Value) { - operators = append(operators, createBlacklistFilterOperator(b.Value)) + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && filter.IsPCREPattern(b.Value) { + operators = append(operators, filter.NewBlacklistOperator(b.Value)) } operators = append(operators, createSetSourceOperator()) @@ -77,22 +76,6 @@ func (monitor) BaseConfig(cfg component.Config) adapter.BaseConfig { } } -// createWhitelistFilterOperator drops entries whose log.file.path does NOT match the regex. -// filter drops entries when expression is true — drop if path does NOT match whitelist. -func createWhitelistFilterOperator(regex string) operator.Config { - c := filter.NewConfigWithID("whitelist-filter") - c.Expression = fmt.Sprintf(`!(attributes["log.file.path"] matches %q)`, regex) - return operator.NewConfig(c) -} - -// createBlacklistFilterOperator drops entries whose log.file.path matches the regex. -// filter drops entries when expression is true — drop if path matches blacklist. -func createBlacklistFilterOperator(regex string) operator.Config { - c := filter.NewConfigWithID("blacklist-filter") - c.Expression = fmt.Sprintf(`attributes["log.file.path"] matches %q`, regex) - return operator.NewConfig(c) -} - func createSetSourceOperator() operator.Config { c := move.NewConfigWithID("start") c.From = entry.NewAttributeField("log.file.path") @@ -121,7 +104,7 @@ func (t monitor) InputConfig(config component.Config) operator.Config { // Path is already a glob pattern — use it as-is; whitelist is ignored // because there is no sensible directory to join it against. allowlist = path - case w != nil && isGlobPattern(w.Value): + case w != nil && filter.IsGlobPattern(w.Value): // whitelist is a glob pattern relative to the monitored directory // (e.g. "*.log"). allowlist = filepath.Join(path, w.Value) @@ -141,14 +124,14 @@ func (t monitor) InputConfig(config component.Config) operator.Config { } } oc.Include = []string{allowlist} - t.logger.Info("monitor receiver include pattern", + t.logger.Debug("monitor receiver include pattern", zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), zap.String("path", path), zap.String("include", allowlist), ) - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && isGlobPattern(b.Value) { + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && filter.IsGlobPattern(b.Value) { oc.Exclude = []string{filepath.Join(path, b.Value)} - t.logger.Info("monitor receiver exclude pattern", + t.logger.Debug("monitor receiver exclude pattern", zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), zap.String("exclude", oc.Exclude[0]), ) @@ -184,20 +167,6 @@ func (t monitor) InputConfig(config component.Config) operator.Config { return operator.NewConfig(oc) } -// isGlobPattern reports whether s is a glob pattern suitable for filelog's -// Include/Exclude fields. Splunk whitelist/blacklist values can be either -// glob patterns (containing *, ?, or [) or PCRE regexes (containing (, |, -// $, or \). The latter are not valid globs and must not be passed to filelog. -func isGlobPattern(s string) bool { - return s != "" && strings.ContainsAny(s, "*?[") && !strings.ContainsAny(s, "(|$\\") -} - -// isPCREPattern reports whether s looks like a PCRE regex — i.e. contains -// characters that are meaningful in PCRE but not in glob patterns. -func isPCREPattern(s string) bool { - return s != "" && strings.ContainsAny(s, "(|$\\.+?^") -} - func renameMetadata() []operator.Config { source := move.NewConfigWithID("end-source") source.From = entry.NewAttributeField("source") diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver_test.go b/pkg/splunkta/receiver/monitorreceiver/receiver_test.go index e3018e8..43078af 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver_test.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver_test.go @@ -24,6 +24,7 @@ import ( "go.uber.org/zap" "github.com/splunk/tarunner/pkg/splunkta/conf" + "github.com/splunk/tarunner/pkg/splunkta/receiver/filter" ) // TestMonitorDirectoryWithSplunkRegexWhitelist tests the exact Splunk_TA_nix default stanza @@ -254,7 +255,7 @@ func TestRenameMetadata(t *testing.T) { // whose log.file.path matches the regex and drops those that don't. func TestPCREWhitelistFilter(t *testing.T) { const regex = `(\.log|log$|messages|secure|auth)` - ops := []operator.Config{createWhitelistFilterOperator(regex)} + ops := []operator.Config{filter.NewWhitelistOperator(regex)} output := testutil.NewFakeOutput(t) pipe, err := pipeline.Config{ Operators: ops, @@ -295,7 +296,7 @@ done: // whose log.file.path matches the regex and passes those that don't. func TestPCREBlacklistFilter(t *testing.T) { const regex = `(lastlog|anaconda\.syslog)` - ops := []operator.Config{createBlacklistFilterOperator(regex)} + ops := []operator.Config{filter.NewBlacklistOperator(regex)} output := testutil.NewFakeOutput(t) pipe, err := pipeline.Config{ Operators: ops, From 55b2f9d4528e636bc1c2b678385c54af48eb2b57 Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Thu, 10 Sep 2026 11:02:37 +0200 Subject: [PATCH 08/13] add missing filter file --- pkg/splunkta/receiver/filter/filter.go | 44 ++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 pkg/splunkta/receiver/filter/filter.go diff --git a/pkg/splunkta/receiver/filter/filter.go b/pkg/splunkta/receiver/filter/filter.go new file mode 100644 index 0000000..81e90f2 --- /dev/null +++ b/pkg/splunkta/receiver/filter/filter.go @@ -0,0 +1,44 @@ +// Copyright Splunk, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// Package filter provides helpers for translating Splunk whitelist/blacklist +// params into filelog Include/Exclude globs and stanza filter operators. +package filter + +import ( + "fmt" + "strings" + + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/filter" +) + +// IsGlobPattern reports whether s is a glob pattern suitable for filelog's +// Include/Exclude fields. Splunk whitelist/blacklist values can be either +// glob patterns (containing *, ?, or [) or PCRE regexes (containing (, |, +// $, or \). The latter are not valid globs and must not be passed to filelog. +func IsGlobPattern(s string) bool { + return s != "" && strings.ContainsAny(s, "*?[") && !strings.ContainsAny(s, "(|$\\") +} + +// IsPCREPattern reports whether s looks like a PCRE regex — i.e. contains +// characters that are meaningful in PCRE but not in glob patterns. +func IsPCREPattern(s string) bool { + return s != "" && strings.ContainsAny(s, "(|$\\.+?^") +} + +// NewWhitelistOperator returns a filter operator that drops entries whose +// log.file.path does NOT match the given PCRE regex. +func NewWhitelistOperator(regex string) operator.Config { + c := filter.NewConfigWithID("whitelist-filter") + c.Expression = fmt.Sprintf(`!(attributes["log.file.path"] matches %q)`, regex) + return operator.NewConfig(c) +} + +// NewBlacklistOperator returns a filter operator that drops entries whose +// log.file.path matches the given PCRE regex. +func NewBlacklistOperator(regex string) operator.Config { + c := filter.NewConfigWithID("blacklist-filter") + c.Expression = fmt.Sprintf(`attributes["log.file.path"] matches %q`, regex) + return operator.NewConfig(c) +} From 64fc2d1b3a2e710e49efbb91eb037e75c06a5ead Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Thu, 10 Sep 2026 11:05:18 +0200 Subject: [PATCH 09/13] run make fmt --- pkg/splunkta/receiver/batchreceiver/receiver.go | 6 ++++-- pkg/splunkta/receiver/monitorreceiver/receiver.go | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/splunkta/receiver/batchreceiver/receiver.go b/pkg/splunkta/receiver/batchreceiver/receiver.go index d35e0da..2ab9db0 100644 --- a/pkg/splunkta/receiver/batchreceiver/receiver.go +++ b/pkg/splunkta/receiver/batchreceiver/receiver.go @@ -112,14 +112,16 @@ func (t batch) InputConfig(config component.Config) operator.Config { } } oc.Include = []string{allowlist} - t.logger.Debug("batch receiver include pattern", + t.logger.Debug( + "batch receiver include pattern", zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), zap.String("path", path), zap.String("include", allowlist), ) if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && filter.IsGlobPattern(b.Value) { oc.Exclude = []string{filepath.Join(path, b.Value)} - t.logger.Debug("batch receiver exclude pattern", + t.logger.Debug( + "batch receiver exclude pattern", zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), zap.String("exclude", oc.Exclude[0]), ) diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver.go b/pkg/splunkta/receiver/monitorreceiver/receiver.go index 6f816d2..1de52a5 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver.go @@ -124,14 +124,16 @@ func (t monitor) InputConfig(config component.Config) operator.Config { } } oc.Include = []string{allowlist} - t.logger.Debug("monitor receiver include pattern", + t.logger.Debug( + "monitor receiver include pattern", zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), zap.String("path", path), zap.String("include", allowlist), ) if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && filter.IsGlobPattern(b.Value) { oc.Exclude = []string{filepath.Join(path, b.Value)} - t.logger.Debug("monitor receiver exclude pattern", + t.logger.Debug( + "monitor receiver exclude pattern", zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), zap.String("exclude", oc.Exclude[0]), ) From aec3cf90acc66981b5ef6ceb15441d91e981dee4 Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Thu, 10 Sep 2026 11:17:09 +0200 Subject: [PATCH 10/13] add changelog --- .chloggen/fix-monitor-batch-stanza.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .chloggen/fix-monitor-batch-stanza.yaml diff --git a/.chloggen/fix-monitor-batch-stanza.yaml b/.chloggen/fix-monitor-batch-stanza.yaml new file mode 100644 index 0000000..0272d3b --- /dev/null +++ b/.chloggen/fix-monitor-batch-stanza.yaml @@ -0,0 +1,19 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. crosslink) +component: monitorreceiver, batchreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Fix whitelist/blacklist handling for monitor and batch stanzas + +# One or more tracking issues related to the change +issues: [138] + +# (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: | + - PCRE whitelist/blacklist regexes are applied as filter operators on log.file.path + - Directory paths without whitelist expand to dir/* + - disabled=true is now honoured alongside disabled=1 \ No newline at end of file From 579bd4fbd8b2d6904bec5017225c992e104baa3d Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Thu, 10 Sep 2026 13:45:22 +0200 Subject: [PATCH 11/13] remove unnecessary functions and move duplications to one function --- .../receiver/batchreceiver/receiver.go | 74 +--------------- pkg/splunkta/receiver/filter/filter.go | 73 ++++++++++++++-- .../receiver/monitorreceiver/receiver.go | 87 +------------------ 3 files changed, 75 insertions(+), 159 deletions(-) diff --git a/pkg/splunkta/receiver/batchreceiver/receiver.go b/pkg/splunkta/receiver/batchreceiver/receiver.go index 2ab9db0..92d7346 100644 --- a/pkg/splunkta/receiver/batchreceiver/receiver.go +++ b/pkg/splunkta/receiver/batchreceiver/receiver.go @@ -4,19 +4,12 @@ package batchreceiver import ( - "os" - "path/filepath" - "strings" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/adapter" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/entry" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/helper" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/input/file" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/move" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/noop" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/split" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/trim" "go.opentelemetry.io/collector/component" "go.uber.org/zap" @@ -50,10 +43,10 @@ func (batch) BaseConfig(cfg component.Config) adapter.BaseConfig { // Insert PCRE whitelist/blacklist filters before any other processing. // The log.file.path attribute is set by filelog and available here. - if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && filter.IsPCREPattern(w.Value) { + if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && w.Value != "" && !filter.IsGlobPattern(w.Value) { operators = append(operators, filter.NewWhitelistOperator(w.Value)) } - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && filter.IsPCREPattern(b.Value) { + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && b.Value != "" && !filter.IsGlobPattern(b.Value) { operators = append(operators, filter.NewBlacklistOperator(b.Value)) } @@ -93,67 +86,8 @@ func (t batch) InputConfig(config component.Config) operator.Config { t.logger.Error("error reading command", zap.Error(err)) return operator.NewConfig(oc) } - pathIsGlob := strings.ContainsAny(path, "*?[") - w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist") - var allowlist string - switch { - case pathIsGlob: - allowlist = path - case w != nil && filter.IsGlobPattern(w.Value): - allowlist = filepath.Join(path, w.Value) - case w != nil: - // empty or Splunk regex — match all files under the directory - allowlist = filepath.Join(path, "*") - default: - if info, err := os.Stat(path); err == nil && info.IsDir() { - allowlist = filepath.Join(path, "*") - } else { - allowlist = path - } - } - oc.Include = []string{allowlist} - t.logger.Debug( - "batch receiver include pattern", - zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), - zap.String("path", path), - zap.String("include", allowlist), - ) - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && filter.IsGlobPattern(b.Value) { - oc.Exclude = []string{filepath.Join(path, b.Value)} - t.logger.Debug( - "batch receiver exclude pattern", - zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), - zap.String("exclude", oc.Exclude[0]), - ) - } - if hostParam := rcfg.Input.Configuration.Stanza.Params.Get("host"); hostParam != nil { - // TODO: find a way to run host detection when requested. - oc.Attributes["host"] = helper.ExprStringConfig(hostParam.Value) - } - - if indexParam := rcfg.Input.Configuration.Stanza.Params.Get("index"); indexParam != nil { - oc.Attributes["index"] = helper.ExprStringConfig(indexParam.Value) - } - - if sourceTypeParam := rcfg.Input.Configuration.Stanza.Params.Get("sourcetype"); sourceTypeParam != nil { - oc.Attributes["sourcetype"] = helper.ExprStringConfig(sourceTypeParam.Value) - } - - if sourceParam := rcfg.Input.Configuration.Stanza.Params.Get("source"); sourceParam != nil { - oc.Attributes["source"] = helper.ExprStringConfig(sourceParam.Value) - } - - oc.IncludeFilePath = true - oc.Encoding = "utf-8" - oc.StartAt = "beginning" - oc.SplitConfig = split.Config{ - LineStartPattern: "^", - } - oc.TrimConfig = trim.Config{ - PreserveLeading: true, - PreserveTrailing: true, - } - + filter.ApplyIncludeExclude(oc, path, rcfg.Input.Configuration.Stanza, "batch", t.logger) + filter.ApplyStanzaConfig(oc, rcfg.Input.Configuration.Stanza) return operator.NewConfig(oc) } diff --git a/pkg/splunkta/receiver/filter/filter.go b/pkg/splunkta/receiver/filter/filter.go index 81e90f2..925f84c 100644 --- a/pkg/splunkta/receiver/filter/filter.go +++ b/pkg/splunkta/receiver/filter/filter.go @@ -7,10 +7,19 @@ package filter import ( "fmt" + "os" + "path/filepath" "strings" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/helper" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/input/file" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/filter" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/split" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/trim" + "go.uber.org/zap" + + "github.com/splunk/tarunner/pkg/splunkta/conf" ) // IsGlobPattern reports whether s is a glob pattern suitable for filelog's @@ -21,12 +30,6 @@ func IsGlobPattern(s string) bool { return s != "" && strings.ContainsAny(s, "*?[") && !strings.ContainsAny(s, "(|$\\") } -// IsPCREPattern reports whether s looks like a PCRE regex — i.e. contains -// characters that are meaningful in PCRE but not in glob patterns. -func IsPCREPattern(s string) bool { - return s != "" && strings.ContainsAny(s, "(|$\\.+?^") -} - // NewWhitelistOperator returns a filter operator that drops entries whose // log.file.path does NOT match the given PCRE regex. func NewWhitelistOperator(regex string) operator.Config { @@ -42,3 +45,61 @@ func NewBlacklistOperator(regex string) operator.Config { c.Expression = fmt.Sprintf(`attributes["log.file.path"] matches %q`, regex) return operator.NewConfig(c) } + +// ApplyIncludeExclude sets oc.Include and oc.Exclude based on the Splunk +// whitelist/blacklist params and the resolved path. It also logs the resulting +// patterns at debug level using the provided receiver name as context. +func ApplyIncludeExclude(oc *file.Config, path string, stanza conf.Stanza, receiverName string, logger *zap.Logger) { + w := stanza.Params.Get("whitelist") + var allowlist string + switch { + case IsGlobPattern(path): + allowlist = path + case w != nil && IsGlobPattern(w.Value): + allowlist = filepath.Join(path, w.Value) + case w != nil: + // whitelist param present but empty or a Splunk PCRE regex — match all files under the directory + allowlist = filepath.Join(path, "*") + default: + if info, err := os.Stat(path); err == nil && info.IsDir() { + allowlist = filepath.Join(path, "*") + } else { + allowlist = path + } + } + oc.Include = []string{allowlist} + logger.Debug( + receiverName+" receiver include pattern", + zap.String("stanza", stanza.Name), + zap.String("path", path), + zap.String("include", allowlist), + ) + if b := stanza.Params.Get("blacklist"); b != nil && IsGlobPattern(b.Value) { + oc.Exclude = []string{filepath.Join(path, b.Value)} + logger.Debug( + receiverName+" receiver exclude pattern", + zap.String("stanza", stanza.Name), + zap.String("exclude", oc.Exclude[0]), + ) + } +} + +// ApplyStanzaConfig sets file.Config attributes and defaults that are common +// to both monitor and batch receivers. +func ApplyStanzaConfig(oc *file.Config, stanza conf.Stanza) { + for _, name := range []string{"host", "index", "sourcetype", "source"} { + if p := stanza.Params.Get(name); p != nil { + oc.Attributes[name] = helper.ExprStringConfig(p.Value) + } + } + oc.IncludeFilePath = true + oc.Encoding = "utf-8" + oc.StartAt = "beginning" + oc.SplitConfig = split.Config{ + LineStartPattern: "^", + } + oc.TrimConfig = trim.Config{ + PreserveLeading: true, + PreserveTrailing: true, + } +} diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver.go b/pkg/splunkta/receiver/monitorreceiver/receiver.go index 1de52a5..39b95ea 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver.go @@ -4,19 +4,12 @@ package monitorreceiver import ( - "os" - "path/filepath" - "strings" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/adapter" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/entry" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/helper" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/input/file" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/move" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator/transformer/noop" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/split" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/trim" "go.opentelemetry.io/collector/component" "go.uber.org/zap" @@ -50,10 +43,10 @@ func (monitor) BaseConfig(cfg component.Config) adapter.BaseConfig { // Insert PCRE whitelist/blacklist filters before any other processing. // The log.file.path attribute is set by filelog and available here. - if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && filter.IsPCREPattern(w.Value) { + if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && w.Value != "" && !filter.IsGlobPattern(w.Value) { operators = append(operators, filter.NewWhitelistOperator(w.Value)) } - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && filter.IsPCREPattern(b.Value) { + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && b.Value != "" && !filter.IsGlobPattern(b.Value) { operators = append(operators, filter.NewBlacklistOperator(b.Value)) } @@ -92,80 +85,8 @@ func (t monitor) InputConfig(config component.Config) operator.Config { t.logger.Error("error reading command", zap.Error(err)) return operator.NewConfig(oc) } - // pathIsGlob reports whether the path already contains glob metacharacters - // (e.g. monitor:///home/*/.bash_history). In that case filelog can use it - // directly without further expansion. - pathIsGlob := strings.ContainsAny(path, "*?[") - - w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist") - var allowlist string - switch { - case pathIsGlob: - // Path is already a glob pattern — use it as-is; whitelist is ignored - // because there is no sensible directory to join it against. - allowlist = path - case w != nil && filter.IsGlobPattern(w.Value): - // whitelist is a glob pattern relative to the monitored directory - // (e.g. "*.log"). - allowlist = filepath.Join(path, w.Value) - case w != nil: - // whitelist param is present but either empty or a Splunk regex (which - // is not a valid filelog glob). In both cases match all files directly - // under the directory. - allowlist = filepath.Join(path, "*") - default: - // No whitelist param: if the path is a directory, expand to dir/* so - // filelog can match files inside it. If it's a specific file (or the - // path doesn't exist yet), use it as-is. - if info, err := os.Stat(path); err == nil && info.IsDir() { - allowlist = filepath.Join(path, "*") - } else { - allowlist = path - } - } - oc.Include = []string{allowlist} - t.logger.Debug( - "monitor receiver include pattern", - zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), - zap.String("path", path), - zap.String("include", allowlist), - ) - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && filter.IsGlobPattern(b.Value) { - oc.Exclude = []string{filepath.Join(path, b.Value)} - t.logger.Debug( - "monitor receiver exclude pattern", - zap.String("stanza", rcfg.Input.Configuration.Stanza.Name), - zap.String("exclude", oc.Exclude[0]), - ) - } - if hostParam := rcfg.Input.Configuration.Stanza.Params.Get("host"); hostParam != nil { - // TODO: find a way to run host detection when requested. - oc.Attributes["host"] = helper.ExprStringConfig(hostParam.Value) - } - - if indexParam := rcfg.Input.Configuration.Stanza.Params.Get("index"); indexParam != nil { - oc.Attributes["index"] = helper.ExprStringConfig(indexParam.Value) - } - - if sourceTypeParam := rcfg.Input.Configuration.Stanza.Params.Get("sourcetype"); sourceTypeParam != nil { - oc.Attributes["sourcetype"] = helper.ExprStringConfig(sourceTypeParam.Value) - } - - if sourceParam := rcfg.Input.Configuration.Stanza.Params.Get("source"); sourceParam != nil { - oc.Attributes["source"] = helper.ExprStringConfig(sourceParam.Value) - } - - oc.IncludeFilePath = true - oc.Encoding = "utf-8" - oc.StartAt = "beginning" - oc.SplitConfig = split.Config{ - LineStartPattern: "^", - } - oc.TrimConfig = trim.Config{ - PreserveLeading: true, - PreserveTrailing: true, - } - + filter.ApplyIncludeExclude(oc, path, rcfg.Input.Configuration.Stanza, "monitor", t.logger) + filter.ApplyStanzaConfig(oc, rcfg.Input.Configuration.Stanza) return operator.NewConfig(oc) } From ad9218c2181025399b7e9fe3c2d8715d1fc7561d Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Thu, 10 Sep 2026 14:27:33 +0200 Subject: [PATCH 12/13] fix isGlobPattern and a misleading comment --- pkg/splunkta/receiver/filter/filter.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/splunkta/receiver/filter/filter.go b/pkg/splunkta/receiver/filter/filter.go index 925f84c..6e9e9cb 100644 --- a/pkg/splunkta/receiver/filter/filter.go +++ b/pkg/splunkta/receiver/filter/filter.go @@ -24,10 +24,11 @@ import ( // IsGlobPattern reports whether s is a glob pattern suitable for filelog's // Include/Exclude fields. Splunk whitelist/blacklist values can be either -// glob patterns (containing *, ?, or [) or PCRE regexes (containing (, |, -// $, or \). The latter are not valid globs and must not be passed to filelog. +// glob patterns (containing *, ?, or [) or PCRE regexes. A value is treated +// as a glob only when it contains glob metacharacters and none of the +// characters that are meaningful in PCRE but not in globs. func IsGlobPattern(s string) bool { - return s != "" && strings.ContainsAny(s, "*?[") && !strings.ContainsAny(s, "(|$\\") + return s != "" && strings.ContainsAny(s, "*?[") && !strings.ContainsAny(s, "(|$\\.+^") } // NewWhitelistOperator returns a filter operator that drops entries whose @@ -58,7 +59,9 @@ func ApplyIncludeExclude(oc *file.Config, path string, stanza conf.Stanza, recei case w != nil && IsGlobPattern(w.Value): allowlist = filepath.Join(path, w.Value) case w != nil: - // whitelist param present but empty or a Splunk PCRE regex — match all files under the directory + // whitelist param is present but either empty or a PCRE regex (not a valid + // filelog glob). Expand to dir/* so filelog picks up all files; the PCRE + // regex is applied as a filter operator in BaseConfig. allowlist = filepath.Join(path, "*") default: if info, err := os.Stat(path); err == nil && info.IsDir() { From 6129ec4d2e2b2d40acded4a8cf3eda84a2c58542 Mon Sep 17 00:00:00 2001 From: Olga <86965961+omrozowicz-splunk@users.noreply.github.com> Date: Thu, 10 Sep 2026 14:41:07 +0200 Subject: [PATCH 13/13] change checking for patterns --- .../receiver/batchreceiver/receiver.go | 4 +- pkg/splunkta/receiver/filter/filter.go | 40 +++++-------------- .../receiver/monitorreceiver/receiver.go | 4 +- 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/pkg/splunkta/receiver/batchreceiver/receiver.go b/pkg/splunkta/receiver/batchreceiver/receiver.go index 92d7346..da158f7 100644 --- a/pkg/splunkta/receiver/batchreceiver/receiver.go +++ b/pkg/splunkta/receiver/batchreceiver/receiver.go @@ -43,10 +43,10 @@ func (batch) BaseConfig(cfg component.Config) adapter.BaseConfig { // Insert PCRE whitelist/blacklist filters before any other processing. // The log.file.path attribute is set by filelog and available here. - if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && w.Value != "" && !filter.IsGlobPattern(w.Value) { + if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && w.Value != "" { operators = append(operators, filter.NewWhitelistOperator(w.Value)) } - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && b.Value != "" && !filter.IsGlobPattern(b.Value) { + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && b.Value != "" { operators = append(operators, filter.NewBlacklistOperator(b.Value)) } diff --git a/pkg/splunkta/receiver/filter/filter.go b/pkg/splunkta/receiver/filter/filter.go index 6e9e9cb..92d626b 100644 --- a/pkg/splunkta/receiver/filter/filter.go +++ b/pkg/splunkta/receiver/filter/filter.go @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // Package filter provides helpers for translating Splunk whitelist/blacklist -// params into filelog Include/Exclude globs and stanza filter operators. +// PCRE regexes into stanza filter operators and filelog include paths. package filter import ( @@ -22,15 +22,6 @@ import ( "github.com/splunk/tarunner/pkg/splunkta/conf" ) -// IsGlobPattern reports whether s is a glob pattern suitable for filelog's -// Include/Exclude fields. Splunk whitelist/blacklist values can be either -// glob patterns (containing *, ?, or [) or PCRE regexes. A value is treated -// as a glob only when it contains glob metacharacters and none of the -// characters that are meaningful in PCRE but not in globs. -func IsGlobPattern(s string) bool { - return s != "" && strings.ContainsAny(s, "*?[") && !strings.ContainsAny(s, "(|$\\.+^") -} - // NewWhitelistOperator returns a filter operator that drops entries whose // log.file.path does NOT match the given PCRE regex. func NewWhitelistOperator(regex string) operator.Config { @@ -47,21 +38,20 @@ func NewBlacklistOperator(regex string) operator.Config { return operator.NewConfig(c) } -// ApplyIncludeExclude sets oc.Include and oc.Exclude based on the Splunk -// whitelist/blacklist params and the resolved path. It also logs the resulting -// patterns at debug level using the provided receiver name as context. +// ApplyIncludeExclude sets oc.Include based on the resolved path and whitelist +// param. Whitelist/blacklist are treated as PCRE regexes per Splunk docs and +// are applied as filter operators in BaseConfig — this function only sets the +// filelog include path. It logs the resulting pattern at debug level. func ApplyIncludeExclude(oc *file.Config, path string, stanza conf.Stanza, receiverName string, logger *zap.Logger) { - w := stanza.Params.Get("whitelist") var allowlist string switch { - case IsGlobPattern(path): + case strings.ContainsAny(path, "*?["): + // Path already contains glob metacharacters (e.g. monitor:///home/*/.bash_history); + // use it directly. allowlist = path - case w != nil && IsGlobPattern(w.Value): - allowlist = filepath.Join(path, w.Value) - case w != nil: - // whitelist param is present but either empty or a PCRE regex (not a valid - // filelog glob). Expand to dir/* so filelog picks up all files; the PCRE - // regex is applied as a filter operator in BaseConfig. + case stanza.Params.Get("whitelist") != nil: + // whitelist is present (empty or PCRE regex): expand to dir/* so filelog + // picks up all files; the regex is applied as a filter operator in BaseConfig. allowlist = filepath.Join(path, "*") default: if info, err := os.Stat(path); err == nil && info.IsDir() { @@ -77,14 +67,6 @@ func ApplyIncludeExclude(oc *file.Config, path string, stanza conf.Stanza, recei zap.String("path", path), zap.String("include", allowlist), ) - if b := stanza.Params.Get("blacklist"); b != nil && IsGlobPattern(b.Value) { - oc.Exclude = []string{filepath.Join(path, b.Value)} - logger.Debug( - receiverName+" receiver exclude pattern", - zap.String("stanza", stanza.Name), - zap.String("exclude", oc.Exclude[0]), - ) - } } // ApplyStanzaConfig sets file.Config attributes and defaults that are common diff --git a/pkg/splunkta/receiver/monitorreceiver/receiver.go b/pkg/splunkta/receiver/monitorreceiver/receiver.go index 39b95ea..ee03ffc 100644 --- a/pkg/splunkta/receiver/monitorreceiver/receiver.go +++ b/pkg/splunkta/receiver/monitorreceiver/receiver.go @@ -43,10 +43,10 @@ func (monitor) BaseConfig(cfg component.Config) adapter.BaseConfig { // Insert PCRE whitelist/blacklist filters before any other processing. // The log.file.path attribute is set by filelog and available here. - if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && w.Value != "" && !filter.IsGlobPattern(w.Value) { + if w := rcfg.Input.Configuration.Stanza.Params.Get("whitelist"); w != nil && w.Value != "" { operators = append(operators, filter.NewWhitelistOperator(w.Value)) } - if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && b.Value != "" && !filter.IsGlobPattern(b.Value) { + if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && b.Value != "" { operators = append(operators, filter.NewBlacklistOperator(b.Value)) }