Skip to content
This repository was archived by the owner on Aug 23, 2023. It is now read-only.

Commit 4ee8716

Browse files
authored
Merge pull request #1348 from grafana/reject_invalid_tags
Reject invalid tags
2 parents a4bc9e1 + 096af6c commit 4ee8716

File tree

22 files changed

+330
-356
lines changed

22 files changed

+330
-356
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# master
22

33
## breaking changes
4+
* we now reject metrics with invalid tags on ingest by default, this can be disabled via the `input.reject-invalid-tags` flag.
5+
if you're unsure whether you're currently sending invalid tags, it's a good idea to first disable the invalid tag rejection and watch the
6+
new counter called `input.<input name>.metricdata.discarded.invalid_tag`, if invalid tags get ingested this counter will increase without
7+
rejecting them. once you're sure that you don't ingest invalid tags you can enable rejection to enforce the validation.
8+
more information on #1348
49
* refactor jaeger configuration + many more options #1341
510
the following config options have been renamed:
611
- `tracing-enabled -> jaeger.enabled`

Gopkg.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ unused-packages = true
111111

112112
[[constraint]]
113113
name = "github.com/raintank/schema"
114-
revision = "49c3f30550ed40c22931bc7f46e5c3a7676236b4"
114+
revision = "5611429bd204bf26a3de166316cf3cad0de377c9"
115115

116116
[[constraint]]
117117
name = "github.com/rs/cors"

cmd/metrictank/metrictank.go

+4
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ func main() {
101101
fmt.Fprintf(os.Stderr, "FATAL: configuration file error: %s", err)
102102
os.Exit(1)
103103
}
104+
105+
// input handlers
106+
input.ConfigSetup()
107+
104108
// load config for metric ingestors
105109
inCarbon.ConfigSetup()
106110
inKafkaMdm.ConfigSetup()

dashboards/main/metrictank.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@
155155
},
156156
{
157157
"refId": "C",
158-
"target": "groupByNodes(perSecond(metrictank.stats.$environment.$instance.input.*.*.discarded.invalid.counter32), 'sum', 5, 6, 7, 8)"
158+
"target": "groupByNodes(perSecond(metrictank.stats.$environment.$instance.input.*.*.discarded.invalid*.counter32), 'sum', 5, 6, 7, 8)"
159159
},
160160
{
161161
"refId": "D",
@@ -4763,4 +4763,4 @@
47634763
"title": "Metrictank",
47644764
"uid": "tQW3QShiz",
47654765
"version": 5
4766-
}
4766+
}

docker/docker-chaos/metrictank.ini

+4
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ speculation-threshold = 1
237237

238238
## metric data inputs ##
239239

240+
[input]
241+
# reject received metrics that have invalid tags
242+
reject-invalid-tags = true
243+
240244
### carbon input (optional)
241245
[carbon-in]
242246
enabled = true

docker/docker-cluster-query/metrictank.ini

+4
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ speculation-threshold = 1
237237

238238
## metric data inputs ##
239239

240+
[input]
241+
# reject received metrics that have invalid tags
242+
reject-invalid-tags = true
243+
240244
### carbon input (optional)
241245
[carbon-in]
242246
enabled = true

docker/docker-cluster/metrictank.ini

+4
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ speculation-threshold = 1
237237

238238
## metric data inputs ##
239239

240+
[input]
241+
# reject received metrics that have invalid tags
242+
reject-invalid-tags = true
243+
240244
### carbon input (optional)
241245
[carbon-in]
242246
enabled = true

docker/docker-dev-custom-cfg-kafka/metrictank.ini

+4
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ speculation-threshold = 1
237237

238238
## metric data inputs ##
239239

240+
[input]
241+
# reject received metrics that have invalid tags
242+
reject-invalid-tags = true
243+
240244
### carbon input (optional)
241245
[carbon-in]
242246
enabled = true

docs/config.md

+7
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,13 @@ speculation-threshold = 1
286286
```
287287

288288
## metric data inputs ##
289+
290+
```
291+
[input]
292+
# reject received metrics that have invalid tags
293+
reject-invalid-tags = true
294+
```
295+
289296
### carbon input (optional)
290297

291298
```

docs/metrics.md

+3
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ the duration of (successful) update of a metric to the memory idx
214214
the number of currently known metrics in the index
215215
* `input.%s.metricdata.discarded.invalid`:
216216
a count of times a metricdata was invalid by input plugin
217+
* `input.%s.metricdata.discarded.invalid_tags`:
218+
a count of times a metricdata was considered invalid due to
219+
invalid tags in the metric definition. all rejected metrics counted here are also counted in the above "invalid" counter
217220
* `input.%s.metricdata.received`:
218221
the count of metricdata datapoints received by input plugin
219222
* `input.%s.metricpoint.discarded.invalid`:

idx/memory/memory.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,10 @@ func (m *UnpartitionedMemoryIdx) Init() error {
276276
}
277277

278278
func (m *UnpartitionedMemoryIdx) Stop() {
279-
m.findCache.Shutdown()
280-
m.findCache = nil
279+
if m.findCache != nil {
280+
m.findCache.Shutdown()
281+
m.findCache = nil
282+
}
281283
return
282284
}
283285

input/input.go

+49-21
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,28 @@
33
package input
44

55
import (
6+
"flag"
67
"fmt"
78
"math"
89
"strconv"
910

10-
"github.com/raintank/schema"
11-
"github.com/raintank/schema/msg"
12-
11+
"github.com/grafana/globalconf"
1312
"github.com/grafana/metrictank/idx"
1413
"github.com/grafana/metrictank/mdata"
1514
"github.com/grafana/metrictank/stats"
15+
"github.com/raintank/schema"
16+
"github.com/raintank/schema/msg"
1617
log "github.com/sirupsen/logrus"
1718
)
1819

20+
var rejectInvalidTags bool
21+
22+
func ConfigSetup() {
23+
input := flag.NewFlagSet("input", flag.ExitOnError)
24+
input.BoolVar(&rejectInvalidTags, "reject-invalid-tags", true, "reject received metrics that have invalid tags")
25+
globalconf.Register("input", input, flag.ExitOnError)
26+
}
27+
1928
type Handler interface {
2029
ProcessMetricData(md *schema.MetricData, partition int32)
2130
ProcessMetricPoint(point schema.MetricPoint, format msg.Format, partition int32)
@@ -29,6 +38,7 @@ type DefaultHandler struct {
2938
receivedMP *stats.Counter32
3039
receivedMPNO *stats.Counter32
3140
invalidMD *stats.CounterRate32
41+
invalidTagMD *stats.CounterRate32
3242
invalidMP *stats.CounterRate32
3343
unknownMP *stats.Counter32
3444

@@ -57,6 +67,9 @@ func NewDefaultHandler(metrics mdata.Metrics, metricIndex idx.MetricIndex, input
5767
receivedMPNO: stats.NewCounter32(fmt.Sprintf("input.%s.metricpoint_no_org.received", input)),
5868
// metric input.%s.metricdata.discarded.invalid is a count of times a metricdata was invalid by input plugin
5969
invalidMD: stats.NewCounterRate32(fmt.Sprintf("input.%s.metricdata.discarded.invalid", input)),
70+
// metric input.%s.metricdata.discarded.invalid_tags is a count of times a metricdata was considered invalid due to
71+
// invalid tags in the metric definition. all rejected metrics counted here are also counted in the above "invalid" counter
72+
invalidTagMD: stats.NewCounterRate32(fmt.Sprintf("input.%s.metricdata.discarded.invalid_tag", input)),
6073
// metric input.%s.metricpoint.discarded.invalid is a count of times a metricpoint was invalid by input plugin
6174
invalidMP: stats.NewCounterRate32(fmt.Sprintf("input.%s.metricpoint.discarded.invalid", input)),
6275
// metric input.%s.metricpoint.discarded.unknown is the count of times the ID of a received metricpoint was not in the index, by input plugin
@@ -103,27 +116,42 @@ func (in DefaultHandler) ProcessMetricData(md *schema.MetricData, partition int3
103116
err := md.Validate()
104117
if err != nil {
105118
in.invalidMD.Inc()
106-
log.Debugf("in: Invalid metric %v: %s", md, err)
107-
108-
var reason string
109-
switch err {
110-
case schema.ErrInvalidIntervalzero:
111-
reason = invalidInterval
112-
case schema.ErrInvalidOrgIdzero:
113-
reason = invalidOrgId
114-
case schema.ErrInvalidEmptyName:
115-
reason = invalidName
116-
case schema.ErrInvalidMtype:
117-
reason = invalidMtype
118-
case schema.ErrInvalidTagFormat:
119-
reason = invalidTagFormat
120-
default:
121-
reason = "unknown"
119+
120+
ignoreError := false
121+
// assuming that the tag format was the only issue found by Validate()
122+
// better make sure that the tag format is the last check which Validate() checks, to not accidentally ignore a potential following error
123+
if err == schema.ErrInvalidTagFormat {
124+
in.invalidTagMD.Inc()
125+
if !rejectInvalidTags {
126+
log.Debugf("in: Invalid metric %v, not rejecting it because rejection due to invalid tags is disabled: %s", md, err)
127+
ignoreError = true
128+
}
122129
}
123-
mdata.PromDiscardedSamples.WithLabelValues(reason, strconv.Itoa(md.OrgId)).Inc()
124130

125-
return
131+
if !ignoreError {
132+
log.Debugf("in: Invalid metric %v: %s", md, err)
133+
134+
var reason string
135+
switch err {
136+
case schema.ErrInvalidIntervalzero:
137+
reason = invalidInterval
138+
case schema.ErrInvalidOrgIdzero:
139+
reason = invalidOrgId
140+
case schema.ErrInvalidEmptyName:
141+
reason = invalidName
142+
case schema.ErrInvalidMtype:
143+
reason = invalidMtype
144+
case schema.ErrInvalidTagFormat:
145+
reason = invalidTagFormat
146+
default:
147+
reason = "unknown"
148+
}
149+
mdata.PromDiscardedSamples.WithLabelValues(reason, strconv.Itoa(md.OrgId)).Inc()
150+
151+
return
152+
}
126153
}
154+
127155
// in cassandra we store timestamps and interval as 32bit signed integers.
128156
// math.MaxInt32 = Jan 19 03:14:07 UTC 2038
129157
if md.Time <= 0 || md.Time >= math.MaxInt32 {

0 commit comments

Comments
 (0)