diff options
author | 2020-03-31 14:07:36 +0800 | |
---|---|---|
committer | 2020-03-31 08:07:36 +0200 | |
commit | 87214a4c5c05c8918bfe73f734ff4dbd390319dd (patch) | |
tree | 9ca83d03ccdb80572f0166e84add67bb23a1184f /test | |
parent | 10d176b811e229f2b7bc72c342f54f6acfa69fbd (diff) | |
download | coredns-87214a4c5c05c8918bfe73f734ff4dbd390319dd.tar.gz coredns-87214a4c5c05c8918bfe73f734ff4dbd390319dd.tar.zst coredns-87214a4c5c05c8918bfe73f734ff4dbd390319dd.zip |
introduce metric naming test (#3789)
* introduce metric naming test
Signed-off-by: zounengren <zounengren@cmss.chinamobile.com>
* Update metrics.go
Signed-off-by: zounengren <zounengren@cmss.chinamobile.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/metric_naming_test.go | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/test/metric_naming_test.go b/test/metric_naming_test.go new file mode 100644 index 000000000..578e46e9f --- /dev/null +++ b/test/metric_naming_test.go @@ -0,0 +1,172 @@ +package test + +import ( + "bytes" + "go/ast" + "go/parser" + "go/token" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/coredns/coredns/plugin" + + dto "github.com/prometheus/client_model/go" + "github.com/prometheus/common/expfmt" + "github.com/prometheus/prometheus/util/promlint" +) + +func TestMetricNaming(t *testing.T) { + + walker := validMetricWalker{} + err := filepath.Walk("..", walker.walk) + + if err != nil { + t.Fatal(err) + } + + if len(walker.Metrics) > 0 { + + buf := &bytes.Buffer{} + encoder := expfmt.NewEncoder(buf, expfmt.FmtText) + for _, mf := range walker.Metrics { + if err := encoder.Encode(mf); err != nil { + t.Fatalf("Encoding and sending metric family: %s", err) + } + } + + l := promlint.New(buf) + problems, err := l.Lint() + if err != nil { + t.Fatalf("Link found error: %s", err) + } + + if len(problems) > 0 { + t.Fatalf("A slice of Problems indicating any issues found in the metrics stream: %s", problems) + } + } + +} + +type validMetricWalker struct { + Metrics []*dto.MetricFamily +} + +func (w *validMetricWalker) walk(path string, info os.FileInfo, _ error) error { + // only for regular files, not starting with a . and those that are go files. + if !info.Mode().IsRegular() { + return nil + } + // Is it appropriate to compare the file name equals metrics.go directly? + if strings.HasPrefix(path, "../.") { + return nil + } + if strings.HasSuffix(path, "_test.go") { + return nil + } + if !strings.HasSuffix(path, ".go") { + return nil + } + + fs := token.NewFileSet() + f, err := parser.ParseFile(fs, path, nil, parser.AllErrors) + if err != nil { + return err + } + l := &metric{} + ast.Walk(l, f) + if l.Metric != nil { + w.Metrics = append(w.Metrics, l.Metric) + } + return nil +} + +type metric struct { + Metric *dto.MetricFamily +} + +func (l metric) Visit(n ast.Node) ast.Visitor { + if n == nil { + return nil + } + ce, ok := n.(*ast.CallExpr) + if !ok { + return l + } + se, ok := ce.Fun.(*ast.SelectorExpr) + if !ok { + return l + } + id, ok := se.X.(*ast.Ident) + if !ok { + return l + } + if id.Name != "prometheus" { //prometheus + return l + } + var metricsType dto.MetricType + switch se.Sel.Name { + case "NewCounterVec", "NewCounter": + metricsType = dto.MetricType_COUNTER + case "NewGaugeVec", "NewGauge": + metricsType = dto.MetricType_GAUGE + case "NewHistogramVec", "NewHistogram": + metricsType = dto.MetricType_HISTOGRAM + case "NewSummaryVec", "NewSummary": + metricsType = dto.MetricType_SUMMARY + default: + return l + } + // Check first arg, that should have basic lit with capital + if len(ce.Args) < 1 { + return l + } + bl, ok := ce.Args[0].(*ast.CompositeLit) + if !ok { + return l + } + + // parse Namespace Subsystem Name Help + var subsystem, name, help string + for _, elt := range bl.Elts { + expr, ok := elt.(*ast.KeyValueExpr) + if !ok { + continue + } + object, ok := expr.Key.(*ast.Ident) + if !ok { + continue + } + value, ok := expr.Value.(*ast.BasicLit) + if !ok { + continue + } + switch object.Name { + case "Subsystem": + subsystem = value.Value + case "Name": + name = value.Value + case "Help": + help = value.Value + } + } + + // validate metrics field + if len(name) == 0 || len(help) == 0 { + return l + } + + var metricName string + if len(subsystem) > 0 { + metricName = strings.Join([]string{plugin.Namespace, subsystem, name}, "_") + } else { + metricName = strings.Join([]string{plugin.Namespace, name}, "_") + } + l.Metric = &dto.MetricFamily{ + Name: &metricName, + Help: &help, + Type: &metricsType, + } + return l +} |