aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorGravatar Zou Nengren <zounengren@cmss.chinamobile.com> 2020-03-31 14:07:36 +0800
committerGravatar GitHub <noreply@github.com> 2020-03-31 08:07:36 +0200
commit87214a4c5c05c8918bfe73f734ff4dbd390319dd (patch)
tree9ca83d03ccdb80572f0166e84add67bb23a1184f /test
parent10d176b811e229f2b7bc72c342f54f6acfa69fbd (diff)
downloadcoredns-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.go172
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
+}