From c18bdb0f44f762ba02e9f2c80afbe4f79953e5f5 Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Thu, 30 Oct 2025 13:50:17 +0500 Subject: [PATCH 1/8] add 'validation-regex' config option --- helper/tags/graphite.go | 20 +++++-- receiver/plain.go | 11 +++- receiver/plain_test.go | 127 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 7 deletions(-) diff --git a/helper/tags/graphite.go b/helper/tags/graphite.go index 9a81efce..1df69122 100644 --- a/helper/tags/graphite.go +++ b/helper/tags/graphite.go @@ -190,12 +190,14 @@ type TemplateDesc struct { } type TagConfig struct { - Enabled bool `toml:"enabled"` - Separator string `toml:"separator"` - Tags []string `toml:"tags"` - TagMap map[string]string `toml:"-"` - Templates []string `toml:"templates"` - TemplateDescs []TemplateDesc `toml:"-"` + Enabled bool `toml:"enabled"` + Separator string `toml:"separator"` + validationRegex string `toml:"validation-regex"` + ValidationRegex *regexp.Regexp `toml:"-"` + Tags []string `toml:"tags"` + TagMap map[string]string `toml:"-"` + Templates []string `toml:"templates"` + TemplateDescs []TemplateDesc `toml:"-"` } func DisabledTagConfig() TagConfig { @@ -224,6 +226,12 @@ func (cfg *TagConfig) Configure() error { cfg.TagMap = make(map[string]string) makeTagMap(cfg.TagMap, cfg.Tags) + var err error + cfg.ValidationRegex, err = regexp.Compile(cfg.validationRegex) + if err != nil { + return err + } + for _, s := range cfg.Templates { dirtyTokens := strings.Split(s, " ") tokens := dirtyTokens[:0] diff --git a/receiver/plain.go b/receiver/plain.go index fa026658..c61f2044 100644 --- a/receiver/plain.go +++ b/receiver/plain.go @@ -70,7 +70,16 @@ func (base *Base) PlainParseLine(p []byte, now uint32, buf *tags.GraphiteBuf) ([ i3-- } - value, err := strconv.ParseFloat(unsafeString(p[i1+1:i2]), 64) + var ( + err error + value float64 + ) + + if base.Tags.ValidationRegex != nil && base.Tags.ValidationRegex.Match(p[:i1]) { + return nil, 0, 0, errors.New("message contains invalid characters: '" + unsafeString(p) + "'") + } + + value, err = strconv.ParseFloat(unsafeString(p[i1+1:i2]), 64) if err != nil || math.IsNaN(value) { return nil, 0, 0, errors.New("bad message: '" + unsafeString(p) + "'") } diff --git a/receiver/plain_test.go b/receiver/plain_test.go index 5a0d994e..eb36bcc4 100644 --- a/receiver/plain_test.go +++ b/receiver/plain_test.go @@ -3,6 +3,7 @@ package receiver import ( "context" "fmt" + "regexp" "sync" "testing" "time" @@ -177,6 +178,8 @@ func TestPlainParseLine(t *testing.T) { {"metric.name;tag=value;k=v 42.15 1422642189\r\n", "metric.name?k=v&tag=value", 42.15, 1422642189}, {"metric..name 42.15 -1\n", "metric.name", 42.15, now}, {"cpu.loadavg;env=test2;host=host1;env=test 21.4 1422642189\n", "cpu.loadavg?env=test&host=host1", 21.4, 1422642189}, + {"cpu.loadavg~ 21.4 1422642189\n", "cpu.loadavg~", 21.4, 1422642189}, + {"cpu.loadavg~;env=test2;host=host1;env=test 21.4 1422642189\n", "cpu.loadavg~?env=test&host=host1", 21.4, 1422642189}, } base := &Base{} @@ -202,4 +205,128 @@ func TestPlainParseLine(t *testing.T) { } } } + + tableWithValidation := [](struct { + b string + name string + value float64 + timestamp uint32 + }){ + {b: "42"}, + {b: ""}, + {b: "\n"}, + {b: "metric..name 42 \n"}, + {b: "metric..name 42"}, + {b: "metric.name 42 a1422642189\n"}, + {b: "metric.name 42a 1422642189\n"}, + {b: "metric.name NaN 1422642189\n"}, + {b: "metric.name 42 NaN\n"}, + {"metric.name -42.76 1422642189\n", "metric.name", -42.76, 1422642189}, + {"metric.name 42.15 1422642189\n", "metric.name", 42.15, 1422642189}, + {"metric..name 42.15 1422642189\n", "metric.name", 42.15, 1422642189}, + {"metric...name 42.15 1422642189\n", "metric.name", 42.15, 1422642189}, + {"metric.name 42.15 1422642189\r\n", "metric.name", 42.15, 1422642189}, + {"metric.name;tag=value;k=v 42.15 1422642189\r\n", "metric.name?k=v&tag=value", 42.15, 1422642189}, + {"metric..name 42.15 -1\n", "metric.name", 42.15, now}, + {"cpu.loadavg;env=test2;host=host1;env=test 21.4 1422642189\n", "cpu.loadavg?env=test&host=host1", 21.4, 1422642189}, + + // Additional test cases for validation + // Test invalid characters in metric names + {b: "metric@name 42.15 1422642189\n"}, + {b: "metric#name 42.15 1422642189\n"}, + {b: "metric$name 42.15 1422642189\n"}, + {b: "metric%name 42.15 1422642189\n"}, + {b: "metric&name 42.15 1422642189\n"}, + {b: "metric*name 42.15 1422642189\n"}, + {b: "metric!name 42.15 1422642189\n"}, + {b: "metric name 42.15 1422642189\n"}, // space in metric name + {b: "metric\tname 42.15 1422642189\n"}, // tab in metric name + {b: "metric[name] 42.15 1422642189\n"}, + {b: "metric{name} 42.15 1422642189\n"}, + {b: "metric(name) 42.15 1422642189\n"}, + {b: "metric/name 42.15 1422642189\n"}, + {b: "metric\\name 42.15 1422642189\n"}, + {b: "metric|name 42.15 1422642189\n"}, + {b: "metric?name 42.15 1422642189\n"}, + {b: "metric 42.15 1422642189\n"}, + {b: "metric'name' 42.15 1422642189\n"}, + {b: "metric\"name\" 42.15 1422642189\n"}, + + // Test valid characters that should pass + {"metric-name 42.15 1422642189\n", "metric-name", 42.15, 1422642189}, + {"metric_name 42.15 1422642189\n", "metric_name", 42.15, 1422642189}, + {"metric:name 42.15 1422642189\n", "metric:name", 42.15, 1422642189}, + {"metric.sub.name 42.15 1422642189\n", "metric.sub.name", 42.15, 1422642189}, + {"metric-123_test:data 42.15 1422642189\n", "metric-123_test:data", 42.15, 1422642189}, + + // Test invalid characters in tags + {b: "metric.name;tag@=value 42.15 1422642189\n"}, + {b: "metric.name;tag=val@ue 42.15 1422642189\n"}, + {b: "metric.name;t ag=value 42.15 1422642189\n"}, + {b: "metric.name;tag=val ue 42.15 1422642189\n"}, + {b: "metric.name;tag#key=value 42.15 1422642189\n"}, + {b: "metric.name;tag=value! 42.15 1422642189\n"}, + {b: "metric.name;tag=value;key=val*ue 42.15 1422642189\n"}, + {b: "metric.name;tag=value;k ey=value 42.15 1422642189\n"}, + {b: "metric.name;tag=value;key=val\tue 42.15 1422642189\n"}, + {b: "metric.name;tag=value;key=val\nue 42.15 1422642189\n"}, + + // Test valid tags that should pass + {"metric.name;env=prod 42.15 1422642189\n", "metric.name?env=prod", 42.15, 1422642189}, + {"metric.name;env=prod;region=us-east-1 42.15 1422642189\n", "metric.name?env=prod®ion=us-east-1", 42.15, 1422642189}, + {"metric.name;tag-name=tag-value 42.15 1422642189\n", "metric.name?tag-name=tag-value", 42.15, 1422642189}, + {"metric.name;tag_name=tag_value 42.15 1422642189\n", "metric.name?tag_name=tag_value", 42.15, 1422642189}, + {"metric.name;tag:name=tag:value 42.15 1422642189\n", "metric.name?tag%3Aname=tag%3Avalue", 42.15, 1422642189}, + {"metric.name;tag.name=tag.value 42.15 1422642189\n", "metric.name?tag.name=tag.value", 42.15, 1422642189}, + + // Test edge cases with multiple invalid characters + {b: "metric@#$%name 42.15 1422642189\n"}, + {b: "metric.name;tag@#=value$% 42.15 1422642189\n"}, + {b: "met!ric.na@me;ta#g=val$ue 42.15 1422642189\n"}, + + // Test unicode characters (should fail validation) + {b: "metric.名前 42.15 1422642189\n"}, + {b: "metric.name;tag=値 42.15 1422642189\n"}, + {b: "metric.name;标签=value 42.15 1422642189\n"}, + {b: "метрика.name 42.15 1422642189\n"}, + + // Test empty tag keys/values + {b: "metric.name;=value 42.15 1422642189\n"}, + {b: "metric.name;= 42.15 1422642189\n"}, + + // Test metrics with numbers + {"metric123 42.15 1422642189\n", "metric123", 42.15, 1422642189}, + {"123metric 42.15 1422642189\n", "123metric", 42.15, 1422642189}, + {"123 42.15 1422642189\n", "123", 42.15, 1422642189}, + + // Test metrics with only valid special characters + {"metric-_.:name 42.15 1422642189\n", "metric-_.:name", 42.15, 1422642189}, + {"metric.name;tag-_.:key=tag-_.:value 42.15 1422642189\n", "metric.name?tag-_.%3Akey=tag-_.%3Avalue", 42.15, 1422642189}, + + // Additional tests for colon encoding + {"host:port:metric 42.15 1422642189\n", "host:port:metric", 42.15, 1422642189}, + {"metric.name;service:port=web:8080 42.15 1422642189\n", "metric.name?service%3Aport=web%3A8080", 42.15, 1422642189}, + {"app:service:metric;env=prod:primary 42.15 1422642189\n", "app:service:metric?env=prod%3Aprimary", 42.15, 1422642189}, + } + + baseWithValidation := &Base{Tags: tags.TagConfig{ValidationRegex: regexp.MustCompile(`[^a-zA-Z0-9.;\-_:=]{1}`)}} + for _, p := range tableWithValidation { + name, value, timestamp, err := baseWithValidation.PlainParseLine([]byte(p.b), now, &tagBuf) + if p.name == "" { + // expected error + if err == nil { + t.Fatal("error expected") + } + } else { + if string(name) != p.name { + t.Fatalf("%#v != %#v", string(name), p.name) + } + if value != p.value { + t.Fatalf("%#v != %#v", value, p.value) + } + if timestamp != p.timestamp { + t.Fatalf("%d != %d", timestamp, p.timestamp) + } + } + } } From 646a7e97abb0ffdaa97735741faba23f68afd625 Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Thu, 6 Nov 2025 20:35:00 +0500 Subject: [PATCH 2/8] make validationRegex public --- helper/tags/graphite.go | 18 +++++++++--------- receiver/plain.go | 2 +- receiver/plain_test.go | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/helper/tags/graphite.go b/helper/tags/graphite.go index 1df69122..2968abfb 100644 --- a/helper/tags/graphite.go +++ b/helper/tags/graphite.go @@ -190,14 +190,14 @@ type TemplateDesc struct { } type TagConfig struct { - Enabled bool `toml:"enabled"` - Separator string `toml:"separator"` - validationRegex string `toml:"validation-regex"` - ValidationRegex *regexp.Regexp `toml:"-"` - Tags []string `toml:"tags"` - TagMap map[string]string `toml:"-"` - Templates []string `toml:"templates"` - TemplateDescs []TemplateDesc `toml:"-"` + Enabled bool `toml:"enabled"` + Separator string `toml:"separator"` + ValidationRegex string `toml:"validation-regex"` + ValidationRegexCompiled *regexp.Regexp `toml:"-"` + Tags []string `toml:"tags"` + TagMap map[string]string `toml:"-"` + Templates []string `toml:"templates"` + TemplateDescs []TemplateDesc `toml:"-"` } func DisabledTagConfig() TagConfig { @@ -227,7 +227,7 @@ func (cfg *TagConfig) Configure() error { makeTagMap(cfg.TagMap, cfg.Tags) var err error - cfg.ValidationRegex, err = regexp.Compile(cfg.validationRegex) + cfg.ValidationRegexCompiled, err = regexp.Compile(cfg.ValidationRegex) if err != nil { return err } diff --git a/receiver/plain.go b/receiver/plain.go index c61f2044..5d9b5672 100644 --- a/receiver/plain.go +++ b/receiver/plain.go @@ -75,7 +75,7 @@ func (base *Base) PlainParseLine(p []byte, now uint32, buf *tags.GraphiteBuf) ([ value float64 ) - if base.Tags.ValidationRegex != nil && base.Tags.ValidationRegex.Match(p[:i1]) { + if base.Tags.ValidationRegexCompiled != nil && base.Tags.ValidationRegexCompiled.Match(p[:i1]) { return nil, 0, 0, errors.New("message contains invalid characters: '" + unsafeString(p) + "'") } diff --git a/receiver/plain_test.go b/receiver/plain_test.go index eb36bcc4..cc8213b1 100644 --- a/receiver/plain_test.go +++ b/receiver/plain_test.go @@ -309,7 +309,7 @@ func TestPlainParseLine(t *testing.T) { {"app:service:metric;env=prod:primary 42.15 1422642189\n", "app:service:metric?env=prod%3Aprimary", 42.15, 1422642189}, } - baseWithValidation := &Base{Tags: tags.TagConfig{ValidationRegex: regexp.MustCompile(`[^a-zA-Z0-9.;\-_:=]{1}`)}} + baseWithValidation := &Base{Tags: tags.TagConfig{ValidationRegexCompiled: regexp.MustCompile(`[^a-zA-Z0-9.;\-_:=]{1}`)}} for _, p := range tableWithValidation { name, value, timestamp, err := baseWithValidation.PlainParseLine([]byte(p.b), now, &tagBuf) if p.name == "" { From 9a0f5bdd313a198165de96f409f76b4acaa791db Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Mon, 10 Nov 2025 13:24:47 +0500 Subject: [PATCH 3/8] use base struct instead of tagdesc --- carbon/app.go | 9 +++++++++ carbon/config.go | 18 +++++++++++++----- helper/tags/graphite.go | 15 ++++++--------- receiver/base.go | 2 ++ receiver/plain.go | 2 +- receiver/plain_test.go | 2 +- receiver/receiver.go | 11 +++++++++++ 7 files changed, 43 insertions(+), 16 deletions(-) diff --git a/carbon/app.go b/carbon/app.go index bf649e85..c3dd0d80 100644 --- a/carbon/app.go +++ b/carbon/app.go @@ -6,6 +6,7 @@ import ( "net/url" "os" "path/filepath" + "regexp" "runtime" "strings" "sync" @@ -192,6 +193,8 @@ func (app *App) Start() (err error) { app.writeChan = make(chan *RowBinary.WriteBuffer) + validationRegex := regexp.MustCompile(app.Config.Common.ValidationRegex) + /* WRITER start */ uploaders := make([]string, 0, len(conf.Upload)) for t := range conf.Upload { @@ -256,6 +259,7 @@ func (app *App) Start() (err error) { receiver.DropPast(uint32(conf.Tcp.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Tcp.DropLongerThan), receiver.ReadTimeout(uint32(conf.Tcp.ReadTimeout.Value().Seconds())), + receiver.ValidationRegex(validationRegex), ) if err != nil { @@ -274,6 +278,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Udp.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Udp.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Udp.DropLongerThan), + receiver.ValidationRegex(validationRegex), ) if err != nil { @@ -292,6 +297,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Pickle.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Pickle.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Pickle.DropLongerThan), + receiver.ValidationRegex(validationRegex), ) if err != nil { @@ -309,6 +315,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Grpc.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Grpc.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Grpc.DropLongerThan), + receiver.ValidationRegex(validationRegex), ) if err != nil { @@ -326,6 +333,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Prometheus.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Prometheus.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Prometheus.DropLongerThan), + receiver.ValidationRegex(validationRegex), ) if err != nil { @@ -344,6 +352,7 @@ func (app *App) Start() (err error) { receiver.DropPast(uint32(conf.TelegrafHttpJson.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.TelegrafHttpJson.DropLongerThan), receiver.ConcatChar(conf.TelegrafHttpJson.Concat), + receiver.ValidationRegex(validationRegex), ) if err != nil { diff --git a/carbon/config.go b/carbon/config.go index 7b3a2fc9..82ccc148 100644 --- a/carbon/config.go +++ b/carbon/config.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "io/ioutil" + "regexp" "strings" "time" @@ -20,11 +21,12 @@ const ( ) type commonConfig struct { - MetricPrefix string `toml:"metric-prefix"` - MetricInterval *config.Duration `toml:"metric-interval"` - MetricEndpoint string `toml:"metric-endpoint"` - MaxCPU int `toml:"max-cpu"` - Enabled bool `toml:"enabled"` + MetricPrefix string `toml:"metric-prefix"` + MetricInterval *config.Duration `toml:"metric-interval"` + MetricEndpoint string `toml:"metric-endpoint"` + MaxCPU int `toml:"max-cpu"` + Enabled bool `toml:"enabled"` + ValidationRegex string `toml:"validation-regex"` } type clickhouseConfig struct { @@ -279,6 +281,12 @@ func ReadConfig(filename string, exactConfig bool) (*Config, error) { } } + if cfg.Common.ValidationRegex != "" { + if _, err := regexp.Compile(cfg.Common.ValidationRegex); err != nil { + return nil, err + } + } + if cfg.Logging == nil { cfg.Logging = make([]zapwriter.Config, 0) } diff --git a/helper/tags/graphite.go b/helper/tags/graphite.go index 2968abfb..4b0c5dda 100644 --- a/helper/tags/graphite.go +++ b/helper/tags/graphite.go @@ -190,14 +190,12 @@ type TemplateDesc struct { } type TagConfig struct { - Enabled bool `toml:"enabled"` - Separator string `toml:"separator"` - ValidationRegex string `toml:"validation-regex"` - ValidationRegexCompiled *regexp.Regexp `toml:"-"` - Tags []string `toml:"tags"` - TagMap map[string]string `toml:"-"` - Templates []string `toml:"templates"` - TemplateDescs []TemplateDesc `toml:"-"` + Enabled bool `toml:"enabled"` + Separator string `toml:"separator"` + Tags []string `toml:"tags"` + TagMap map[string]string `toml:"-"` + Templates []string `toml:"templates"` + TemplateDescs []TemplateDesc `toml:"-"` } func DisabledTagConfig() TagConfig { @@ -227,7 +225,6 @@ func (cfg *TagConfig) Configure() error { makeTagMap(cfg.TagMap, cfg.Tags) var err error - cfg.ValidationRegexCompiled, err = regexp.Compile(cfg.ValidationRegex) if err != nil { return err } diff --git a/receiver/base.go b/receiver/base.go index 78319cfc..5095bd28 100644 --- a/receiver/base.go +++ b/receiver/base.go @@ -3,6 +3,7 @@ package receiver import ( "fmt" "net/http" + "regexp" "sort" "sync" "sync/atomic" @@ -36,6 +37,7 @@ type Base struct { dropPastSeconds uint32 dropTooLongLimit uint16 readTimeoutSeconds uint32 + validationRegex *regexp.Regexp writeChan chan *RowBinary.WriteBuffer logger *zap.Logger Tags tags.TagConfig diff --git a/receiver/plain.go b/receiver/plain.go index 5d9b5672..b71872fa 100644 --- a/receiver/plain.go +++ b/receiver/plain.go @@ -75,7 +75,7 @@ func (base *Base) PlainParseLine(p []byte, now uint32, buf *tags.GraphiteBuf) ([ value float64 ) - if base.Tags.ValidationRegexCompiled != nil && base.Tags.ValidationRegexCompiled.Match(p[:i1]) { + if base.validationRegex != nil && base.validationRegex.Match(p[:i1]) { return nil, 0, 0, errors.New("message contains invalid characters: '" + unsafeString(p) + "'") } diff --git a/receiver/plain_test.go b/receiver/plain_test.go index cc8213b1..0ff98717 100644 --- a/receiver/plain_test.go +++ b/receiver/plain_test.go @@ -309,7 +309,7 @@ func TestPlainParseLine(t *testing.T) { {"app:service:metric;env=prod:primary 42.15 1422642189\n", "app:service:metric?env=prod%3Aprimary", 42.15, 1422642189}, } - baseWithValidation := &Base{Tags: tags.TagConfig{ValidationRegexCompiled: regexp.MustCompile(`[^a-zA-Z0-9.;\-_:=]{1}`)}} + baseWithValidation := &Base{validationRegex: regexp.MustCompile(`[^a-zA-Z0-9.;\-_:=]{1}`)} for _, p := range tableWithValidation { name, value, timestamp, err := baseWithValidation.PlainParseLine([]byte(p.b), now, &tagBuf) if p.name == "" { diff --git a/receiver/receiver.go b/receiver/receiver.go index 2ee6c56b..3335effb 100644 --- a/receiver/receiver.go +++ b/receiver/receiver.go @@ -5,6 +5,7 @@ import ( "net" "net/http" "net/url" + "regexp" "strings" "github.com/lomik/carbon-clickhouse/helper/RowBinary" @@ -90,6 +91,16 @@ func ConcatChar(concat string) Option { } } +// ConcatChar creates option for New constructor +func ValidationRegex(regex *regexp.Regexp) Option { + return func(r interface{}) error { + if t, ok := r.(*Base); ok { + t.validationRegex = regex + } + return nil + } +} + // New creates udp, tcp, pickle receiver func New(dsn string, config tags.TagConfig, opts ...Option) (Receiver, error) { u, err := url.Parse(dsn) From 9f461c1e8ff58d24d15ee28eb5ec8d0e21c56b01 Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Thu, 13 Nov 2025 12:31:34 +0500 Subject: [PATCH 4/8] fix empty regex --- carbon/app.go | 15 ++++++--------- receiver/receiver.go | 6 ++++-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/carbon/app.go b/carbon/app.go index c3dd0d80..d216f992 100644 --- a/carbon/app.go +++ b/carbon/app.go @@ -6,7 +6,6 @@ import ( "net/url" "os" "path/filepath" - "regexp" "runtime" "strings" "sync" @@ -193,8 +192,6 @@ func (app *App) Start() (err error) { app.writeChan = make(chan *RowBinary.WriteBuffer) - validationRegex := regexp.MustCompile(app.Config.Common.ValidationRegex) - /* WRITER start */ uploaders := make([]string, 0, len(conf.Upload)) for t := range conf.Upload { @@ -259,7 +256,7 @@ func (app *App) Start() (err error) { receiver.DropPast(uint32(conf.Tcp.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Tcp.DropLongerThan), receiver.ReadTimeout(uint32(conf.Tcp.ReadTimeout.Value().Seconds())), - receiver.ValidationRegex(validationRegex), + receiver.ValidationRegex(app.Config.Common.ValidationRegex), ) if err != nil { @@ -278,7 +275,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Udp.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Udp.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Udp.DropLongerThan), - receiver.ValidationRegex(validationRegex), + receiver.ValidationRegex(app.Config.Common.ValidationRegex), ) if err != nil { @@ -297,7 +294,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Pickle.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Pickle.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Pickle.DropLongerThan), - receiver.ValidationRegex(validationRegex), + receiver.ValidationRegex(app.Config.Common.ValidationRegex), ) if err != nil { @@ -315,7 +312,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Grpc.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Grpc.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Grpc.DropLongerThan), - receiver.ValidationRegex(validationRegex), + receiver.ValidationRegex(app.Config.Common.ValidationRegex), ) if err != nil { @@ -333,7 +330,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Prometheus.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Prometheus.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Prometheus.DropLongerThan), - receiver.ValidationRegex(validationRegex), + receiver.ValidationRegex(app.Config.Common.ValidationRegex), ) if err != nil { @@ -352,7 +349,7 @@ func (app *App) Start() (err error) { receiver.DropPast(uint32(conf.TelegrafHttpJson.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.TelegrafHttpJson.DropLongerThan), receiver.ConcatChar(conf.TelegrafHttpJson.Concat), - receiver.ValidationRegex(validationRegex), + receiver.ValidationRegex(app.Config.Common.ValidationRegex), ) if err != nil { diff --git a/receiver/receiver.go b/receiver/receiver.go index 3335effb..7dd4502d 100644 --- a/receiver/receiver.go +++ b/receiver/receiver.go @@ -92,10 +92,12 @@ func ConcatChar(concat string) Option { } // ConcatChar creates option for New constructor -func ValidationRegex(regex *regexp.Regexp) Option { +func ValidationRegex(regex string) Option { return func(r interface{}) error { if t, ok := r.(*Base); ok { - t.validationRegex = regex + if regex != "" { + t.validationRegex = regexp.MustCompile(regex) + } } return nil } From 3f18bcb74f9697f0db674fc69e71d3868f0f385c Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Thu, 13 Nov 2025 13:50:02 +0500 Subject: [PATCH 5/8] shorten expressions --- carbon/app.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/carbon/app.go b/carbon/app.go index d216f992..c4329e51 100644 --- a/carbon/app.go +++ b/carbon/app.go @@ -256,7 +256,7 @@ func (app *App) Start() (err error) { receiver.DropPast(uint32(conf.Tcp.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Tcp.DropLongerThan), receiver.ReadTimeout(uint32(conf.Tcp.ReadTimeout.Value().Seconds())), - receiver.ValidationRegex(app.Config.Common.ValidationRegex), + receiver.ValidationRegex(conf.Common.ValidationRegex), ) if err != nil { @@ -275,7 +275,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Udp.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Udp.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Udp.DropLongerThan), - receiver.ValidationRegex(app.Config.Common.ValidationRegex), + receiver.ValidationRegex(conf.Common.ValidationRegex), ) if err != nil { @@ -294,7 +294,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Pickle.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Pickle.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Pickle.DropLongerThan), - receiver.ValidationRegex(app.Config.Common.ValidationRegex), + receiver.ValidationRegex(conf.Common.ValidationRegex), ) if err != nil { @@ -312,7 +312,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Grpc.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Grpc.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Grpc.DropLongerThan), - receiver.ValidationRegex(app.Config.Common.ValidationRegex), + receiver.ValidationRegex(conf.Common.ValidationRegex), ) if err != nil { @@ -330,7 +330,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Prometheus.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Prometheus.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Prometheus.DropLongerThan), - receiver.ValidationRegex(app.Config.Common.ValidationRegex), + receiver.ValidationRegex(conf.Common.ValidationRegex), ) if err != nil { @@ -349,7 +349,7 @@ func (app *App) Start() (err error) { receiver.DropPast(uint32(conf.TelegrafHttpJson.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.TelegrafHttpJson.DropLongerThan), receiver.ConcatChar(conf.TelegrafHttpJson.Concat), - receiver.ValidationRegex(app.Config.Common.ValidationRegex), + receiver.ValidationRegex(conf.Common.ValidationRegex), ) if err != nil { From 16ec21b0f5c6a4d06ec75951398b6d43e8bc4b14 Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Fri, 14 Nov 2025 13:57:23 +0500 Subject: [PATCH 6/8] cosmetic changes --- carbon/config.go | 2 +- helper/tags/graphite.go | 5 ----- receiver/plain.go | 7 +------ receiver/receiver.go | 2 +- 4 files changed, 3 insertions(+), 13 deletions(-) diff --git a/carbon/config.go b/carbon/config.go index 82ccc148..5a0807a4 100644 --- a/carbon/config.go +++ b/carbon/config.go @@ -283,7 +283,7 @@ func ReadConfig(filename string, exactConfig bool) (*Config, error) { if cfg.Common.ValidationRegex != "" { if _, err := regexp.Compile(cfg.Common.ValidationRegex); err != nil { - return nil, err + return nil, fmt.Errorf("invalid regex in validation-regex option: %s", err.Error()) } } diff --git a/helper/tags/graphite.go b/helper/tags/graphite.go index 4b0c5dda..9a81efce 100644 --- a/helper/tags/graphite.go +++ b/helper/tags/graphite.go @@ -224,11 +224,6 @@ func (cfg *TagConfig) Configure() error { cfg.TagMap = make(map[string]string) makeTagMap(cfg.TagMap, cfg.Tags) - var err error - if err != nil { - return err - } - for _, s := range cfg.Templates { dirtyTokens := strings.Split(s, " ") tokens := dirtyTokens[:0] diff --git a/receiver/plain.go b/receiver/plain.go index b71872fa..05bb691e 100644 --- a/receiver/plain.go +++ b/receiver/plain.go @@ -70,16 +70,11 @@ func (base *Base) PlainParseLine(p []byte, now uint32, buf *tags.GraphiteBuf) ([ i3-- } - var ( - err error - value float64 - ) - if base.validationRegex != nil && base.validationRegex.Match(p[:i1]) { return nil, 0, 0, errors.New("message contains invalid characters: '" + unsafeString(p) + "'") } - value, err = strconv.ParseFloat(unsafeString(p[i1+1:i2]), 64) + value, err := strconv.ParseFloat(unsafeString(p[i1+1:i2]), 64) if err != nil || math.IsNaN(value) { return nil, 0, 0, errors.New("bad message: '" + unsafeString(p) + "'") } diff --git a/receiver/receiver.go b/receiver/receiver.go index 7dd4502d..a7df1330 100644 --- a/receiver/receiver.go +++ b/receiver/receiver.go @@ -91,7 +91,7 @@ func ConcatChar(concat string) Option { } } -// ConcatChar creates option for New constructor +// ValidationRegex creates option for New constructor func ValidationRegex(regex string) Option { return func(r interface{}) error { if t, ok := r.(*Base); ok { From c989287a0c94f4549178313b2a55ddb1b0b7c8b3 Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Fri, 14 Nov 2025 14:54:36 +0500 Subject: [PATCH 7/8] add validationRegexDropped metric --- receiver/base.go | 29 ++++++++++++++++++++--------- receiver/grpc.go | 2 +- receiver/pickle.go | 2 +- receiver/plain.go | 4 ++-- receiver/prometheus.go | 2 +- receiver/tcp.go | 2 +- receiver/telegraf_http_json.go | 2 +- receiver/udp.go | 2 +- 8 files changed, 28 insertions(+), 17 deletions(-) diff --git a/receiver/base.go b/receiver/base.go index 5095bd28..6d7338ca 100644 --- a/receiver/base.go +++ b/receiver/base.go @@ -19,15 +19,16 @@ const droppedListSize = 1000 type Base struct { stop.Struct stat struct { - samplesReceived uint64 // atomic - messagesReceived uint64 // atomic - metricsReceived uint64 // atomic - errors uint64 // atomic - active int64 // atomic - incompleteReceived uint64 // atomic - futureDropped uint64 // atomic - pastDropped uint64 // atomic - tooLongDropped uint64 // atomic + samplesReceived uint64 // atomic + messagesReceived uint64 // atomic + metricsReceived uint64 // atomic + errors uint64 // atomic + active int64 // atomic + incompleteReceived uint64 // atomic + futureDropped uint64 // atomic + pastDropped uint64 // atomic + tooLongDropped uint64 // atomic + validationRegexDropped uint64 // atomic } droppedList [droppedListSize]string droppedListNext int @@ -87,6 +88,14 @@ func (base *Base) isDropMetricNameTooLong(name string) bool { return false } +func (base *Base) isMatchedByValidationRegex(name []byte) bool { + if base.validationRegex != nil && base.validationRegex.Match(name) { + atomic.AddUint64(&base.stat.validationRegexDropped, 1) + return true + } + return false +} + func (base *Base) DroppedHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") @@ -145,6 +154,8 @@ func (base *Base) SendStat(send func(metric string, value float64), fields ...st sendUint64Counter(send, f, &base.stat.pastDropped) case "tooLongDropped": sendUint64Counter(send, f, &base.stat.tooLongDropped) + case "validationRegexDropped": + sendUint64Counter(send, f, &base.stat.validationRegexDropped) case "errors": sendUint64Counter(send, f, &base.stat.errors) case "active": diff --git a/receiver/grpc.go b/receiver/grpc.go index 6dad436f..a38dd93c 100644 --- a/receiver/grpc.go +++ b/receiver/grpc.go @@ -32,7 +32,7 @@ func (g *GRPC) Addr() net.Addr { } func (g *GRPC) Stat(send func(metric string, value float64)) { - g.SendStat(send, "metricsReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped") + g.SendStat(send, "metricsReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped", "validationRegexDropped") } // Listen bind port. Receive messages and send to out channel diff --git a/receiver/pickle.go b/receiver/pickle.go index 2611f685..5cee707b 100644 --- a/receiver/pickle.go +++ b/receiver/pickle.go @@ -33,7 +33,7 @@ func (rcv *Pickle) Addr() net.Addr { func (rcv *Pickle) Stat(send func(metric string, value float64)) { rcv.SendStat(send, "metricsReceived", "messagesReceived", "errors", "active", "futureDropped", "pastDropped", - "tooLongDropped") + "tooLongDropped", "validationRegexDropped") } func (rcv *Pickle) HandleConnection(conn net.Conn) { diff --git a/receiver/plain.go b/receiver/plain.go index 05bb691e..861fbcfa 100644 --- a/receiver/plain.go +++ b/receiver/plain.go @@ -70,8 +70,8 @@ func (base *Base) PlainParseLine(p []byte, now uint32, buf *tags.GraphiteBuf) ([ i3-- } - if base.validationRegex != nil && base.validationRegex.Match(p[:i1]) { - return nil, 0, 0, errors.New("message contains invalid characters: '" + unsafeString(p) + "'") + if base.isMatchedByValidationRegex(p[:i1]) { + return nil, 0, 0, errors.New("metric name matched by validation regex: '" + unsafeString(p) + "'") } value, err := strconv.ParseFloat(unsafeString(p[i1+1:i2]), 64) diff --git a/receiver/prometheus.go b/receiver/prometheus.go index 5f2621de..dc795b8c 100644 --- a/receiver/prometheus.go +++ b/receiver/prometheus.go @@ -199,7 +199,7 @@ func (rcv *PrometheusRemoteWrite) Addr() net.Addr { } func (rcv *PrometheusRemoteWrite) Stat(send func(metric string, value float64)) { - rcv.SendStat(send, "samplesReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped") + rcv.SendStat(send, "samplesReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped", "validationRegexDropped") } // Listen bind port. Receive messages and send to out channel diff --git a/receiver/tcp.go b/receiver/tcp.go index 81ce4581..4a1bf636 100644 --- a/receiver/tcp.go +++ b/receiver/tcp.go @@ -28,7 +28,7 @@ func (rcv *TCP) Addr() net.Addr { } func (rcv *TCP) Stat(send func(metric string, value float64)) { - rcv.SendStat(send, "metricsReceived", "errors", "active", "futureDropped", "pastDropped", "tooLongDropped") + rcv.SendStat(send, "metricsReceived", "errors", "active", "futureDropped", "pastDropped", "tooLongDropped", "validationRegexDropped") } func (rcv *TCP) HandleConnection(conn net.Conn) { diff --git a/receiver/telegraf_http_json.go b/receiver/telegraf_http_json.go index 58921ba9..034b8847 100644 --- a/receiver/telegraf_http_json.go +++ b/receiver/telegraf_http_json.go @@ -158,7 +158,7 @@ func (rcv *TelegrafHttpJson) Addr() net.Addr { } func (rcv *TelegrafHttpJson) Stat(send func(metric string, value float64)) { - rcv.SendStat(send, "samplesReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped") + rcv.SendStat(send, "samplesReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped", "validationRegexDropped") } // Listen bind port. Receive messages and send to out channel diff --git a/receiver/udp.go b/receiver/udp.go index 5195a804..e532e783 100644 --- a/receiver/udp.go +++ b/receiver/udp.go @@ -28,7 +28,7 @@ func (rcv *UDP) Addr() net.Addr { func (rcv *UDP) Stat(send func(metric string, value float64)) { rcv.SendStat(send, "metricsReceived", "errors", "incompleteReceived", "futureDropped", "pastDropped", - "tooLongDropped") + "tooLongDropped", "validationRegexDropped") } func (rcv *UDP) receiveWorker(ctx context.Context) { From ac970cb9c8b8d8dde3ffdc27eec0cf84cdf69e0c Mon Sep 17 00:00:00 2001 From: Artyom Antonov Date: Fri, 14 Nov 2025 18:09:15 +0500 Subject: [PATCH 8/8] rename validation-regex -> blacklist-regex --- carbon/app.go | 12 ++++++------ carbon/config.go | 18 +++++++++--------- receiver/base.go | 32 ++++++++++++++++---------------- receiver/grpc.go | 2 +- receiver/pickle.go | 2 +- receiver/plain.go | 4 ++-- receiver/plain_test.go | 2 +- receiver/prometheus.go | 2 +- receiver/receiver.go | 6 +++--- receiver/tcp.go | 2 +- receiver/telegraf_http_json.go | 2 +- receiver/udp.go | 2 +- 12 files changed, 43 insertions(+), 43 deletions(-) diff --git a/carbon/app.go b/carbon/app.go index c4329e51..b811c57e 100644 --- a/carbon/app.go +++ b/carbon/app.go @@ -256,7 +256,7 @@ func (app *App) Start() (err error) { receiver.DropPast(uint32(conf.Tcp.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Tcp.DropLongerThan), receiver.ReadTimeout(uint32(conf.Tcp.ReadTimeout.Value().Seconds())), - receiver.ValidationRegex(conf.Common.ValidationRegex), + receiver.BlacklistRegex(conf.Common.BlacklistRegex), ) if err != nil { @@ -275,7 +275,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Udp.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Udp.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Udp.DropLongerThan), - receiver.ValidationRegex(conf.Common.ValidationRegex), + receiver.BlacklistRegex(conf.Common.BlacklistRegex), ) if err != nil { @@ -294,7 +294,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Pickle.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Pickle.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Pickle.DropLongerThan), - receiver.ValidationRegex(conf.Common.ValidationRegex), + receiver.BlacklistRegex(conf.Common.BlacklistRegex), ) if err != nil { @@ -312,7 +312,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Grpc.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Grpc.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Grpc.DropLongerThan), - receiver.ValidationRegex(conf.Common.ValidationRegex), + receiver.BlacklistRegex(conf.Common.BlacklistRegex), ) if err != nil { @@ -330,7 +330,7 @@ func (app *App) Start() (err error) { receiver.DropFuture(uint32(conf.Prometheus.DropFuture.Value().Seconds())), receiver.DropPast(uint32(conf.Prometheus.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.Prometheus.DropLongerThan), - receiver.ValidationRegex(conf.Common.ValidationRegex), + receiver.BlacklistRegex(conf.Common.BlacklistRegex), ) if err != nil { @@ -349,7 +349,7 @@ func (app *App) Start() (err error) { receiver.DropPast(uint32(conf.TelegrafHttpJson.DropPast.Value().Seconds())), receiver.DropLongerThan(conf.TelegrafHttpJson.DropLongerThan), receiver.ConcatChar(conf.TelegrafHttpJson.Concat), - receiver.ValidationRegex(conf.Common.ValidationRegex), + receiver.BlacklistRegex(conf.Common.BlacklistRegex), ) if err != nil { diff --git a/carbon/config.go b/carbon/config.go index 5a0807a4..20cf9bfe 100644 --- a/carbon/config.go +++ b/carbon/config.go @@ -21,12 +21,12 @@ const ( ) type commonConfig struct { - MetricPrefix string `toml:"metric-prefix"` - MetricInterval *config.Duration `toml:"metric-interval"` - MetricEndpoint string `toml:"metric-endpoint"` - MaxCPU int `toml:"max-cpu"` - Enabled bool `toml:"enabled"` - ValidationRegex string `toml:"validation-regex"` + MetricPrefix string `toml:"metric-prefix"` + MetricInterval *config.Duration `toml:"metric-interval"` + MetricEndpoint string `toml:"metric-endpoint"` + MaxCPU int `toml:"max-cpu"` + Enabled bool `toml:"enabled"` + BlacklistRegex string `toml:"blacklist-regex"` } type clickhouseConfig struct { @@ -281,9 +281,9 @@ func ReadConfig(filename string, exactConfig bool) (*Config, error) { } } - if cfg.Common.ValidationRegex != "" { - if _, err := regexp.Compile(cfg.Common.ValidationRegex); err != nil { - return nil, fmt.Errorf("invalid regex in validation-regex option: %s", err.Error()) + if cfg.Common.BlacklistRegex != "" { + if _, err := regexp.Compile(cfg.Common.BlacklistRegex); err != nil { + return nil, fmt.Errorf("invalid regex in blacklist-regex option: %s", err.Error()) } } diff --git a/receiver/base.go b/receiver/base.go index 6d7338ca..fa994d76 100644 --- a/receiver/base.go +++ b/receiver/base.go @@ -19,16 +19,16 @@ const droppedListSize = 1000 type Base struct { stop.Struct stat struct { - samplesReceived uint64 // atomic - messagesReceived uint64 // atomic - metricsReceived uint64 // atomic - errors uint64 // atomic - active int64 // atomic - incompleteReceived uint64 // atomic - futureDropped uint64 // atomic - pastDropped uint64 // atomic - tooLongDropped uint64 // atomic - validationRegexDropped uint64 // atomic + samplesReceived uint64 // atomic + messagesReceived uint64 // atomic + metricsReceived uint64 // atomic + errors uint64 // atomic + active int64 // atomic + incompleteReceived uint64 // atomic + futureDropped uint64 // atomic + pastDropped uint64 // atomic + tooLongDropped uint64 // atomic + blacklistRegexDropped uint64 // atomic } droppedList [droppedListSize]string droppedListNext int @@ -38,7 +38,7 @@ type Base struct { dropPastSeconds uint32 dropTooLongLimit uint16 readTimeoutSeconds uint32 - validationRegex *regexp.Regexp + blacklistRegex *regexp.Regexp writeChan chan *RowBinary.WriteBuffer logger *zap.Logger Tags tags.TagConfig @@ -88,9 +88,9 @@ func (base *Base) isDropMetricNameTooLong(name string) bool { return false } -func (base *Base) isMatchedByValidationRegex(name []byte) bool { - if base.validationRegex != nil && base.validationRegex.Match(name) { - atomic.AddUint64(&base.stat.validationRegexDropped, 1) +func (base *Base) isMatchedByBlacklistRegex(name []byte) bool { + if base.blacklistRegex != nil && base.blacklistRegex.Match(name) { + atomic.AddUint64(&base.stat.blacklistRegexDropped, 1) return true } return false @@ -154,8 +154,8 @@ func (base *Base) SendStat(send func(metric string, value float64), fields ...st sendUint64Counter(send, f, &base.stat.pastDropped) case "tooLongDropped": sendUint64Counter(send, f, &base.stat.tooLongDropped) - case "validationRegexDropped": - sendUint64Counter(send, f, &base.stat.validationRegexDropped) + case "blacklistRegexDropped": + sendUint64Counter(send, f, &base.stat.blacklistRegexDropped) case "errors": sendUint64Counter(send, f, &base.stat.errors) case "active": diff --git a/receiver/grpc.go b/receiver/grpc.go index a38dd93c..aa6363c5 100644 --- a/receiver/grpc.go +++ b/receiver/grpc.go @@ -32,7 +32,7 @@ func (g *GRPC) Addr() net.Addr { } func (g *GRPC) Stat(send func(metric string, value float64)) { - g.SendStat(send, "metricsReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped", "validationRegexDropped") + g.SendStat(send, "metricsReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped", "blacklistRegexDropped") } // Listen bind port. Receive messages and send to out channel diff --git a/receiver/pickle.go b/receiver/pickle.go index 5cee707b..05ed9b91 100644 --- a/receiver/pickle.go +++ b/receiver/pickle.go @@ -33,7 +33,7 @@ func (rcv *Pickle) Addr() net.Addr { func (rcv *Pickle) Stat(send func(metric string, value float64)) { rcv.SendStat(send, "metricsReceived", "messagesReceived", "errors", "active", "futureDropped", "pastDropped", - "tooLongDropped", "validationRegexDropped") + "tooLongDropped", "blacklistRegexDropped") } func (rcv *Pickle) HandleConnection(conn net.Conn) { diff --git a/receiver/plain.go b/receiver/plain.go index 861fbcfa..809259ce 100644 --- a/receiver/plain.go +++ b/receiver/plain.go @@ -70,8 +70,8 @@ func (base *Base) PlainParseLine(p []byte, now uint32, buf *tags.GraphiteBuf) ([ i3-- } - if base.isMatchedByValidationRegex(p[:i1]) { - return nil, 0, 0, errors.New("metric name matched by validation regex: '" + unsafeString(p) + "'") + if base.isMatchedByBlacklistRegex(p[:i1]) { + return nil, 0, 0, errors.New("metric name matched by blacklist regex: '" + unsafeString(p) + "'") } value, err := strconv.ParseFloat(unsafeString(p[i1+1:i2]), 64) diff --git a/receiver/plain_test.go b/receiver/plain_test.go index 0ff98717..074f527e 100644 --- a/receiver/plain_test.go +++ b/receiver/plain_test.go @@ -309,7 +309,7 @@ func TestPlainParseLine(t *testing.T) { {"app:service:metric;env=prod:primary 42.15 1422642189\n", "app:service:metric?env=prod%3Aprimary", 42.15, 1422642189}, } - baseWithValidation := &Base{validationRegex: regexp.MustCompile(`[^a-zA-Z0-9.;\-_:=]{1}`)} + baseWithValidation := &Base{blacklistRegex: regexp.MustCompile(`[^a-zA-Z0-9.;\-_:=]{1}`)} for _, p := range tableWithValidation { name, value, timestamp, err := baseWithValidation.PlainParseLine([]byte(p.b), now, &tagBuf) if p.name == "" { diff --git a/receiver/prometheus.go b/receiver/prometheus.go index dc795b8c..8f88ee35 100644 --- a/receiver/prometheus.go +++ b/receiver/prometheus.go @@ -199,7 +199,7 @@ func (rcv *PrometheusRemoteWrite) Addr() net.Addr { } func (rcv *PrometheusRemoteWrite) Stat(send func(metric string, value float64)) { - rcv.SendStat(send, "samplesReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped", "validationRegexDropped") + rcv.SendStat(send, "samplesReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped", "blacklistRegexDropped") } // Listen bind port. Receive messages and send to out channel diff --git a/receiver/receiver.go b/receiver/receiver.go index a7df1330..06017ad7 100644 --- a/receiver/receiver.go +++ b/receiver/receiver.go @@ -91,12 +91,12 @@ func ConcatChar(concat string) Option { } } -// ValidationRegex creates option for New constructor -func ValidationRegex(regex string) Option { +// BlacklistRegex creates option for New constructor +func BlacklistRegex(regex string) Option { return func(r interface{}) error { if t, ok := r.(*Base); ok { if regex != "" { - t.validationRegex = regexp.MustCompile(regex) + t.blacklistRegex = regexp.MustCompile(regex) } } return nil diff --git a/receiver/tcp.go b/receiver/tcp.go index 4a1bf636..a990cb6c 100644 --- a/receiver/tcp.go +++ b/receiver/tcp.go @@ -28,7 +28,7 @@ func (rcv *TCP) Addr() net.Addr { } func (rcv *TCP) Stat(send func(metric string, value float64)) { - rcv.SendStat(send, "metricsReceived", "errors", "active", "futureDropped", "pastDropped", "tooLongDropped", "validationRegexDropped") + rcv.SendStat(send, "metricsReceived", "errors", "active", "futureDropped", "pastDropped", "tooLongDropped", "blacklistRegexDropped") } func (rcv *TCP) HandleConnection(conn net.Conn) { diff --git a/receiver/telegraf_http_json.go b/receiver/telegraf_http_json.go index 034b8847..d56f291b 100644 --- a/receiver/telegraf_http_json.go +++ b/receiver/telegraf_http_json.go @@ -158,7 +158,7 @@ func (rcv *TelegrafHttpJson) Addr() net.Addr { } func (rcv *TelegrafHttpJson) Stat(send func(metric string, value float64)) { - rcv.SendStat(send, "samplesReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped", "validationRegexDropped") + rcv.SendStat(send, "samplesReceived", "errors", "futureDropped", "pastDropped", "tooLongDropped", "blacklistRegexDropped") } // Listen bind port. Receive messages and send to out channel diff --git a/receiver/udp.go b/receiver/udp.go index e532e783..0f0b2c95 100644 --- a/receiver/udp.go +++ b/receiver/udp.go @@ -28,7 +28,7 @@ func (rcv *UDP) Addr() net.Addr { func (rcv *UDP) Stat(send func(metric string, value float64)) { rcv.SendStat(send, "metricsReceived", "errors", "incompleteReceived", "futureDropped", "pastDropped", - "tooLongDropped", "validationRegexDropped") + "tooLongDropped", "blacklistRegexDropped") } func (rcv *UDP) receiveWorker(ctx context.Context) {