Skip to content

Commit

Permalink
Fix panic caused by providing a not valid regex pattern (#47)
Browse files Browse the repository at this point in the history
* fix: fixed panic caused by providing a not valid regex pattern to process filter config

Co-authored-by: Carlos <croman@newrelic.com>
  • Loading branch information
cristianciutea and carlosroman authored Jul 17, 2020
1 parent 3394abd commit 5a97e82
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 15 deletions.
23 changes: 17 additions & 6 deletions pkg/metrics/sampler/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package sampler

import (
"fmt"
"github.com/newrelic/infrastructure-agent/pkg/log"
"reflect"
"regexp"
"strings"
Expand All @@ -20,6 +21,8 @@ var (
typesToEvaluate = map[string]bool{"ProcessSample": true}
)

var mlog = log.WithComponent("SamplerMatcher")

// IncludeSampleMatchFn func that returns whether an event/sample should be included, it satisfies
// the metrics matcher (processor.MatcherChain) interface.
type IncludeSampleMatchFn func(sample interface{}) bool
Expand Down Expand Up @@ -114,7 +117,7 @@ func build(dimensionName string, expr string) ExpressionMatcher {
// so this matcher basically get's ignored in the current implementation
mappedAttributeName, found := attrCache[dimensionName]
if !found {
return constantMatcher{false}
return constantMatcher{value: false}
}

eval := matcher{
Expand All @@ -123,7 +126,10 @@ func build(dimensionName string, expr string) ExpressionMatcher {

if strings.HasPrefix(expr, "regex") {
regex := strings.Trim(strings.TrimSpace(strings.TrimLeft(expr, "regex")), `"`)
cacheRegex(regex)
if err := cacheRegex(regex); err != nil {
mlog.WithError(err).Error(fmt.Sprintf("could not intitilize expression matcher for the provided configuration: '%s'", expr))
return constantMatcher{value: false}
}
eval.ExpectedValue = regex
eval.Evaluator = regularExpressionEvaluator
} else {
Expand All @@ -134,11 +140,16 @@ func build(dimensionName string, expr string) ExpressionMatcher {
return eval
}

func cacheRegex(regex string) {
func cacheRegex(pattern string) error {
//if not cached yet, cache it
if _, ok := regexCache[regex]; !ok {
regexCache[regex] = regexp.MustCompile(regex)
if _, ok := regexCache[pattern]; !ok {
regex, err := regexp.Compile(pattern)
if err != nil {
return err
}
regexCache[pattern] = regex
}
return nil
}

// MatcherChain is a chain of evaluators
Expand Down Expand Up @@ -260,6 +271,6 @@ func NewSampleMatchFn(enableProcessMetrics *bool, includeMetricsMatchers config.
}

enabled, exists := ffRetriever.GetFeatureFlag(handler.FlagFullProcess)
return exists && enabled
return exists && enabled
}
}
57 changes: 48 additions & 9 deletions pkg/metrics/sampler/matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
"github.com/stretchr/testify/assert"
)

var metricDimensionProcessName string = "process.name"
var metricDimensionProcessExecutable string = "process.executable"
var metricDimensionProcessName = "process.name"
var metricDimensionProcessExecutable = "process.executable"

func Test_EvaluatorChain_WithSingleRule(t *testing.T) {

Expand Down Expand Up @@ -103,6 +103,14 @@ func Test_EvaluatorChain_WithSingleRule(t *testing.T) {
},
want: false,
},
{
name: "ProcessCmdLine_NotValidRegex",
input: &types.ProcessSample{CmdLine: "/bin/java"},
rules: map[string][]string{
metricDimensionProcessExecutable: {"regex *"},
},
want: false,
},
}

for _, tc := range cases {
Expand Down Expand Up @@ -165,6 +173,15 @@ func Test_Evaluator_WithTwoLiteralRules(t *testing.T) {
},
want: true,
},
{
name: "ProcessNameAndExecutableAreMatchNotValidRegex",
input: javaProcessSample,
rules: map[string][]string{
metricDimensionProcessExecutable: {"regex *"},
metricDimensionProcessName: {"java"},
},
want: true,
},
}

for _, tc := range cases {
Expand Down Expand Up @@ -453,6 +470,27 @@ func Test_EvaluatorChain_WithMultipleRuleAttribute(t *testing.T) {
},
want: []bool{true, true, false, true, true, true, false},
},
{
/*
matchers:
process.executable:
- regex * # bad regex
- regex .*
*/
name: "ProcessExecutable_NotValidRegex",
input: []interface{}{
types.ProcessSample{CmdLine: "/bin/java"},
types.ProcessSample{CmdLine: "/bin/local/java"},
},
rules: map[string][]string{
metricDimensionProcessExecutable: {
"regex *",
"/bin/java",
"/bin/local/java",
},
},
want: []bool{true, true},
},
}

for _, tc := range cases {
Expand Down Expand Up @@ -509,11 +547,13 @@ func Test_EvaluatorChain_LogTraceMatcher(t *testing.T) {
}

type enabledFFRetriever struct{}

func (e *enabledFFRetriever) GetFeatureFlag(name string) (enabled bool, exists bool) {
return true, true
}

type disabledFFRetriever struct{}

func (e *disabledFFRetriever) GetFeatureFlag(name string) (enabled bool, exists bool) {
return false, true
}
Expand All @@ -523,7 +563,6 @@ func TestNewSampleMatchFn(t *testing.T) {
falseVar := false
emptyMatchers := config.IncludeMetricsMap{}


type args struct {
enableProcessMetrics *bool
includeMetricsMatchers config.IncludeMetricsMap
Expand Down Expand Up @@ -588,20 +627,20 @@ func TestNewSampleMatchFn(t *testing.T) {
{
name: "process samples matching rules are included",
args: args{
enableProcessMetrics: &trueVar,
enableProcessMetrics: &trueVar,
includeMetricsMatchers: config.IncludeMetricsMap{"process.name": []string{"regex \"foo.*\""}},
ffRetriever: testFF.EmptyFFRetriever,
sample: &fixture.ProcessSample,
ffRetriever: testFF.EmptyFFRetriever,
sample: &fixture.ProcessSample,
},
include: true,
},
{
name: "process samples not matching rules are not included",
args: args{
enableProcessMetrics: &trueVar,
enableProcessMetrics: &trueVar,
includeMetricsMatchers: config.IncludeMetricsMap{"process.name": []string{"regex \"bar*\""}},
ffRetriever: testFF.EmptyFFRetriever,
sample: &fixture.ProcessSample,
ffRetriever: testFF.EmptyFFRetriever,
sample: &fixture.ProcessSample,
},
include: false,
},
Expand Down

0 comments on commit 5a97e82

Please sign in to comment.