Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .chloggen/fix-monitor-batch-stanza.yaml
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions pkg/splunkta/conf/inputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
19 changes: 19 additions & 0 deletions pkg/splunkta/conf/inputs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 := `<?xml version="1.0" encoding="UTF-8"?>
<Input>
Expand Down
54 changes: 13 additions & 41 deletions pkg/splunkta/receiver/batchreceiver/receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@
package batchreceiver

import (
"path/filepath"

"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"

"github.com/splunk/tarunner/pkg/splunkta/operator/prop"
"github.com/splunk/tarunner/pkg/splunkta/receiver/filter"
"github.com/splunk/tarunner/pkg/splunkta/script"
)

Expand All @@ -44,6 +40,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 && w.Value != "" {
operators = append(operators, filter.NewWhitelistOperator(w.Value))
}
if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && b.Value != "" {
operators = append(operators, filter.NewBlacklistOperator(b.Value))
}

operators = append(operators, createSetSourceOperator())

for _, p := range rcfg.Props {
Expand Down Expand Up @@ -80,42 +86,8 @@ 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 {
allowlist = filepath.Join(path, w.Value)
}
oc.Include = []string{allowlist}
if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil {
oc.Exclude = []string{filepath.Join(path, b.Value)}
}
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)
}

Expand Down
90 changes: 90 additions & 0 deletions pkg/splunkta/receiver/filter/filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright Splunk, Inc.
// SPDX-License-Identifier: Apache-2.0

// Package filter provides helpers for translating Splunk whitelist/blacklist
// PCRE regexes into stanza filter operators and filelog include paths.
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"
)

// 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)
}

// 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) {
var allowlist string
switch {
case strings.ContainsAny(path, "*?["):
// Path already contains glob metacharacters (e.g. monitor:///home/*/.bash_history);
// use it directly.
allowlist = path
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() {
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),
)
}

// 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,
}
}
54 changes: 13 additions & 41 deletions pkg/splunkta/receiver/monitorreceiver/receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@
package monitorreceiver

import (
"path/filepath"

"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"

"github.com/splunk/tarunner/pkg/splunkta/operator/prop"
"github.com/splunk/tarunner/pkg/splunkta/receiver/filter"
"github.com/splunk/tarunner/pkg/splunkta/script"
)

Expand All @@ -44,6 +40,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 && w.Value != "" {
operators = append(operators, filter.NewWhitelistOperator(w.Value))
}
if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil && b.Value != "" {
operators = append(operators, filter.NewBlacklistOperator(b.Value))
}

operators = append(operators, createSetSourceOperator())

for _, p := range rcfg.Props {
Expand Down Expand Up @@ -79,42 +85,8 @@ 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 {
allowlist = filepath.Join(path, w.Value)
}
oc.Include = []string{allowlist}
if b := rcfg.Input.Configuration.Stanza.Params.Get("blacklist"); b != nil {
oc.Exclude = []string{filepath.Join(path, b.Value)}
}
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)
}

Expand Down
Loading
Loading