Skip to content

Commit

Permalink
Add two option flag
Browse files Browse the repository at this point in the history
Signed-off-by: George Robinson <george.robinson@grafana.com>
  • Loading branch information
grobinson-grafana committed Sep 12, 2023
1 parent 233e8e9 commit 5576e19
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 65 deletions.
2 changes: 1 addition & 1 deletion cli/alert_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (a *alertQueryCmd) queryAlerts(ctx context.Context, _ *kingpin.ParseContext
// the user wants alertname=<arg> and prepend `alertname=` to
// the front.
m := a.matcherGroups[0]
_, err := compat.ParseMatcher(m)
_, err := compat.Matcher(m)
if err != nil {
a.matcherGroups[0] = fmt.Sprintf("alertname=%s", m)
}
Expand Down
5 changes: 1 addition & 4 deletions cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,7 @@ func Execute() {
if err != nil {
kingpin.Fatalf(":error parsing the feature flag list: %v\n", err)
}
if featureConfig.DisableNewLabelMatchers() {
compat.ParseMatcher = compat.OldMatcherParser(logger)
compat.ParseMatchers = compat.OldMatchersParser(logger)
}
compat.InitFromFlags(logger, featureConfig)

app.Version(version.Print("amtool"))
app.GetFlag("help").Short('h')
Expand Down
2 changes: 1 addition & 1 deletion cli/silence_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func (c *silenceQueryCmd) query(ctx context.Context, _ *kingpin.ParseContext) er
// If the parser fails then we likely don't have a (=|=~|!=|!~) so lets
// assume that the user wants alertname=<arg> and prepend `alertname=`
// to the front.
_, err := compat.ParseMatcher(c.matchers[0])
_, err := compat.Matcher(c.matchers[0])
if err != nil {
c.matchers[0] = fmt.Sprintf("alertname=%s", c.matchers[0])
}
Expand Down
4 changes: 2 additions & 2 deletions cli/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func parseMatchers(inputMatchers []string) ([]labels.Matcher, error) {
matchers := make([]labels.Matcher, 0, len(inputMatchers))

for _, v := range inputMatchers {
matcher, err := compat.ParseMatcher(v)
matcher, err := compat.Matcher(v)
if err != nil {
return []labels.Matcher{}, err
}
Expand Down Expand Up @@ -108,7 +108,7 @@ func parseLabels(inputLabels []string) (models.LabelSet, error) {
labelSet := make(models.LabelSet, len(inputLabels))

for _, l := range inputLabels {
matcher, err := compat.ParseMatcher(l)
matcher, err := compat.Matcher(l)
if err != nil {
return models.LabelSet{}, err
}
Expand Down
53 changes: 40 additions & 13 deletions featurecontrol/featurecontrol.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package featurecontrol

import (
"errors"
"fmt"
"strings"

Expand All @@ -22,29 +23,40 @@ import (
)

const (
fcReceiverNameInMetrics = "receiver-name-in-metrics"
fcDisabledNewLabelMatchers = "disable-new-label-matchers"
fcReceiverNameInMetrics = "receiver-name-in-metrics"
fcStableMatchersParsing = "stable-matchers-parsing"
fcUTF8MatchersParsing = "utf8-matchers-parsing"
)

var AllowedFlags = []string{fcReceiverNameInMetrics, fcDisabledNewLabelMatchers}
var AllowedFlags = []string{
fcReceiverNameInMetrics,
fcStableMatchersParsing,
fcUTF8MatchersParsing,
}

type Flagger interface {
EnableReceiverNamesInMetrics() bool
DisableNewLabelMatchers() bool
StableMatchersParsing() bool
UTF8MatchersParsing() bool
}

type Flags struct {
logger log.Logger
enableReceiverNamesInMetrics bool
disableNewLabelMatchers bool
utf8MatchersParsing bool
stableMatchersParsing bool
}

func (f *Flags) EnableReceiverNamesInMetrics() bool {
return f.enableReceiverNamesInMetrics
}

func (f *Flags) DisableNewLabelMatchers() bool {
return f.disableNewLabelMatchers
func (f *Flags) StableMatchersParsing() bool {
return f.stableMatchersParsing
}

func (f *Flags) UTF8MatchersParsing() bool {
return f.utf8MatchersParsing
}

type flagOption func(flags *Flags)
Expand All @@ -55,9 +67,15 @@ func enableReceiverNameInMetrics() flagOption {
}
}

func disableNewLabelMatchers() flagOption {
func enableStableMatchersParsing() flagOption {
return func(configs *Flags) {
configs.stableMatchersParsing = true
}
}

func enableUTF8MatchersParsing() flagOption {
return func(configs *Flags) {
configs.disableNewLabelMatchers = true
configs.utf8MatchersParsing = true
}
}

Expand All @@ -74,9 +92,12 @@ func NewFlags(logger log.Logger, features string) (Flagger, error) {
case fcReceiverNameInMetrics:
opts = append(opts, enableReceiverNameInMetrics())
level.Warn(logger).Log("msg", "Experimental receiver name in metrics enabled")
case fcDisabledNewLabelMatchers:
opts = append(opts, disableNewLabelMatchers())
level.Warn(logger).Log("msg", "Disabled new label matchers")
case fcStableMatchersParsing:
opts = append(opts, enableStableMatchersParsing())
level.Warn(logger).Log("msg", "Enabled stable matchers parsing")
case fcUTF8MatchersParsing:
opts = append(opts, enableUTF8MatchersParsing())
level.Warn(logger).Log("msg", "Enabled UTF-8 matchers parsing")
default:
return nil, fmt.Errorf("Unknown option '%s' for --enable-feature", feature)
}
Expand All @@ -86,11 +107,17 @@ func NewFlags(logger log.Logger, features string) (Flagger, error) {
opt(fc)
}

if fc.stableMatchersParsing && fc.utf8MatchersParsing {
return nil, errors.New("Both stable and UTF-8 matchers parsing is enabled, please choose one or remove the flag for both")
}

return fc, nil
}

type NoopFlags struct{}

func (n NoopFlags) EnableReceiverNamesInMetrics() bool { return false }

func (n NoopFlags) DisableNewLabelMatchers() bool { return false }
func (n NoopFlags) StableMatchersParsing() bool { return false }

func (n NoopFlags) UTF8MatchersParsing() bool { return false }
99 changes: 57 additions & 42 deletions matchers/compat/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,69 +16,90 @@ package compat
import (
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus/alertmanager/featurecontrol"

"github.com/prometheus/alertmanager/matchers/parse"
"github.com/prometheus/alertmanager/pkg/labels"
)

var (
// ParseMatcher is the default parser for parsing individual matchers.
ParseMatcher = FallbackMatcherParser(log.NewNopLogger())

// ParseMatchers is the default parser for parsing a series of zero or
// more matchers.
ParseMatchers = FallbackMatchersParser(log.NewNopLogger())
parseMatcher = stableMatcherParser(log.NewNopLogger())
parseMatchers = stableMatchersParser(log.NewNopLogger())
)

// MatcherParser is an interface for parsing a single matcher in the input string.
type MatcherParser func(s string) (*labels.Matcher, error)
type matcherParser func(s string) (*labels.Matcher, error)
type matchersParser func(s string) (labels.Matchers, error)

// Matcher parses the matcher in the input string. It returns an error
// if the input is invalid or contains two or more matchers.
func Matcher(s string) (*labels.Matcher, error) {
return parseMatcher(s)
}

// Matchers parses one or more matchers in the input string. It returns
// an error if the input is invalid.
func Matchers(s string) (labels.Matchers, error) {
return parseMatchers(s)
}

// MatchersParser is an interface for parsing one or more matchers in the input string.
type MatchersParser func(s string) (labels.Matchers, error)
// InitFromFlags initializes the compat package from the flagger.
func InitFromFlags(l log.Logger, f featurecontrol.Flagger) {
if f.StableMatchersParsing() {
parseMatcher = stableMatcherParser(l)
parseMatchers = stableMatchersParser(l)
} else if f.UTF8MatchersParsing() {
parseMatcher = utf8MatcherParser(l)
parseMatchers = utf8MatchersParser(l)
} else {
parseMatcher = fallbackMatcherParser(l)
parseMatchers = fallbackMatchersParser(l)
}
}

// OldMatcherParser uses the old pkg/labels parser to parse the matcher in
// stableMatcherParser uses the old pkg/labels parser to parse the matcher in
// the input string.
func OldMatcherParser(l log.Logger) MatcherParser {
func stableMatcherParser(_ log.Logger) matcherParser {
return func(s string) (*labels.Matcher, error) {
return labels.ParseMatcher(s)
}
}

// stableMatchersParser uses the old pkg/labels parser to parse zero or more
// matchers in the input string. It returns an error if the input is invalid.
func stableMatchersParser(_ log.Logger) matchersParser {
return func(s string) (labels.Matchers, error) {
return labels.ParseMatchers(s)
}
}

// utf8MatcherParser uses the new matchers/parse parser to parse
// the matcher in the input string. If this fails it does not fallback
// to the old pkg/labels parser.
func utf8MatcherParser(_ log.Logger) matcherParser {
return func(s string) (*labels.Matcher, error) {
level.Debug(l).Log(
"msg",
"Parsing matcher with old regular expressions parser",
"matcher",
s,
)
return labels.ParseMatcher(s)
}
}

// OldMatchersParser uses the old pkg/labels parser to parse zero or more
// matchers in the string. It returns an error if the input is invalid.
func OldMatchersParser(l log.Logger) MatchersParser {
// utf8MatchersParser uses the new matchers/parse parser to parse
// zero or more matchers in the input string. If this fails it
// does not fallback to the old pkg/labels parser.
func utf8MatchersParser(_ log.Logger) matchersParser {
return func(s string) (labels.Matchers, error) {
level.Debug(l).Log(
"msg",
"Parsing matchers with old regular expressions parser",
"matchers",
s)
return labels.ParseMatchers(s)
}
}

// FallbackMatcherParser uses the new matchers/parse parser to parse
// fallbackMatcherParser uses the new matchers/parse parser to parse
// zero or more matchers in the string. If this fails it falls back to
// the old pkg/labels parser and emits a warning log line.
func FallbackMatcherParser(l log.Logger) MatcherParser {
func fallbackMatcherParser(l log.Logger) matcherParser {
return func(s string) (*labels.Matcher, error) {
var (
m *labels.Matcher
err error
invalidErr error
)
level.Debug(l).Log(
"msg",
"Parsing matcher with new parser",
"matcher",
s,
)
m, err = parse.Matcher(s)
if err != nil {
// The input is not valid in the old pkg/labels parser either,
Expand All @@ -102,22 +123,16 @@ func FallbackMatcherParser(l log.Logger) MatcherParser {
}
}

// FallbackMatchersParser uses the new matchers/parse parser to parse the
// fallbackMatchersParser uses the new matchers/parse parser to parse the
// matcher in the input string. If this fails it falls back to the old
// pkg/labels parser and emits a warning log line.
func FallbackMatchersParser(l log.Logger) MatchersParser {
func fallbackMatchersParser(l log.Logger) matchersParser {
return func(s string) (labels.Matchers, error) {
var (
m []*labels.Matcher
err error
invalidErr error
)
level.Debug(l).Log(
"msg",
"Parsing matchers with new parser",
"matchers",
s,
)
m, err = parse.Matchers(s)
if err != nil {
// The input is not valid in the old pkg/labels parser either,
Expand Down
4 changes: 2 additions & 2 deletions matchers/compat/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestFallbackMatcherParser(t *testing.T) {
input: "foo!bar",
err: "bad matcher format: foo!bar",
}}
f := FallbackMatcherParser(log.NewNopLogger())
f := fallbackMatcherParser(log.NewNopLogger())
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
matcher, err := f(test.input)
Expand Down Expand Up @@ -91,7 +91,7 @@ func TestFallbackMatchersParser(t *testing.T) {
input: "{foo!bar}",
err: "bad matcher format: foo!bar",
}}
f := FallbackMatchersParser(log.NewNopLogger())
f := fallbackMatchersParser(log.NewNopLogger())
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
matchers, err := f(test.input)
Expand Down

0 comments on commit 5576e19

Please sign in to comment.