Skip to content

Commit

Permalink
Merge pull request #39 from coanor/master
Browse files Browse the repository at this point in the history
feat: add multiple features and fix
  • Loading branch information
yeya24 authored Apr 22, 2024
2 parents 87286a7 + 5fdcadf commit 66dbcb5
Show file tree
Hide file tree
Showing 7 changed files with 435 additions and 101 deletions.
23 changes: 23 additions & 0 deletions cmd/promlinter/list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"go/token"
"testing"

"github.com/stretchr/testify/assert"
"github.com/yeya24/promlinter"
)

func TestLabel(t *testing.T) {
fs := token.NewFileSet()

metrics := promlinter.RunList(fs, findFiles([]string{"../../testdata/"}, fs), true)

if len(metrics) != 10 {
t.Fatal()
}

assert.Equal(t, []string{"namespace", "name"}, metrics[7].Labels())
assert.Equal(t, []string{"namespace", "name", "const-label1=value1", "const-label2=?"}, metrics[8].Labels())
assert.Equal(t, []string{"namespace", "name"}, metrics[9].Labels())
}
204 changes: 165 additions & 39 deletions cmd/promlinter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"go/ast"
"go/parser"
"go/token"
"log"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -42,26 +43,40 @@ It is also supported to disable the lint functions using repeated flag --disable
[UnitAbbreviations]: UnitAbbreviations detects abbreviated units in the metric name.
`

var MetricType = map[int32]string{
0: "COUNTER",
1: "GAUGE",
2: "SUMMARY",
3: "UNTYPED",
4: "HISTOGRAM",
var (
MetricType = map[int32]string{
0: "COUNTER",
1: "GAUGE",
2: "SUMMARY",
3: "UNTYPED",
4: "HISTOGRAM",
}
withVendor *bool
)

func init() {
// To see the log position, added for debugging.
log.SetFlags(log.LstdFlags | log.Lshortfile)
}

func main() {

app := kingpin.New(filepath.Base(os.Args[0]), help)
app.Version("v0.0.2")
app.Version("v0.0.3")
app.HelpFlag.Short('h')

listCmd := app.Command("list", "List metrics name.")
listPaths := listCmd.Arg("files", "Files to parse metrics.").Strings()
listStrict := listCmd.Flag("strict", "Strict mode. If true, linter will output more issues including parsing failures.").
Default("false").Short('s').Bool()

listPrintAddPos := listCmd.Flag("add-position", "Add metric position column when printing the result.").Default("false").Bool()
listPrintAddModule := listCmd.Flag("add-module", "Add metric module column when printing the result.").Default("false").Bool()

listPrintAddHelp := listCmd.Flag("add-help", "Add metric help column when printing the result.").Default("false").Bool()
listPrintFormat := listCmd.Flag("output", "Print result formatted as JSON/YAML").Short('o').Enum("yaml", "json")
listPrintFormat := listCmd.Flag("output", "Print result formatted as JSON/YAML/Markdown").Short('o').Enum("yaml", "json", "md")

withVendor = listCmd.Flag("with-vendor", "Scan vendor packages.").Default("false").Bool()

lintCmd := app.Command("lint", "Lint metrics via promlint.")
lintPaths := lintCmd.Arg("files", "Files to parse metrics.").Strings()
Expand All @@ -78,7 +93,15 @@ func main() {
switch parsedCmd {
case listCmd.FullCommand():
metrics := promlinter.RunList(fileSet, findFiles(*listPaths, fileSet), *listStrict)
printMetrics(metrics, *listPrintAddPos, *listPrintAddHelp, *listPrintFormat)
p := printer{
fmt: *listPrintFormat,
addHelp: *listPrintAddHelp,
addPosition: *listPrintAddPos,
addModule: *listPrintAddModule,
metrics: metrics,
}

p.printMetrics()
case lintCmd.FullCommand():
setting := promlinter.Setting{Strict: *lintStrict, DisabledLintFuncs: *disableLintFuncs}
for _, iss := range promlinter.RunLint(fileSet, findFiles(*lintPaths, fileSet), setting) {
Expand Down Expand Up @@ -114,9 +137,11 @@ func walkDir(root string) chan string {
defer close(out)
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
sep := string(filepath.Separator)
if strings.HasPrefix(path, "vendor"+sep) || strings.Contains(path, sep+"vendor"+sep) {
if withVendor != nil && !*withVendor &&
(strings.HasPrefix(path, "vendor"+sep) || strings.Contains(path, sep+"vendor"+sep)) {
return nil
}

if !info.IsDir() && !strings.HasSuffix(info.Name(), "_test.go") &&
strings.HasSuffix(info.Name(), ".go") {
out <- path
Expand All @@ -131,48 +156,137 @@ func walkDir(root string) chan string {
return out
}

func printMetrics(metrics []promlinter.MetricFamilyWithPos, addPosition, addHelp bool, printFormat string) {
if len(printFormat) > 0 {
if printFormat == "json" {
printAsJson(metrics)
return
func (p *printer) printDefault() {
tw := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
defer tw.Flush()

fieldSep := "\t"
if p.fmt == "md" {
fieldSep = "|"
}

var (
fields []string
)

if p.addPosition || p.addModule {
fields = []string{
"POSITION", "TYPE", "NAME", "LABELS",
}
if printFormat == "yaml" {
printAsYaml(metrics)
return
} else {
fields = []string{
"TYPE", "NAME", "LABELS",
}
}
tw := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
defer tw.Flush()

var header string
if addPosition {
header = "POSITION\tTYPE\tNAME"
if p.addHelp {
fields = append(fields, "HELP")
}

if p.fmt == "md" {
fmt.Fprintf(tw, "|%s|\n", strings.Join(fields, fieldSep))
} else {
header = "TYPE\tNAME"
fmt.Fprintf(tw, "%s\n", strings.Join(fields, fieldSep))
}

if addHelp {
header += "\tHELP"
if p.fmt == "md" {
fmt.Fprintf(tw, "%s|\n", strings.Repeat("|---", len(fields)))
}

fmt.Fprintln(tw, header)
for _, m := range p.metrics {

for _, m := range metrics {
if addPosition && addHelp {
fmt.Fprintf(tw, "%v\t%v\t%v\t%v\n", m.Pos, MetricType[int32(*m.MetricFamily.Type)], *m.MetricFamily.Name, *m.MetricFamily.Help)
} else if addPosition {
fmt.Fprintf(tw, "%v\t%v\t%v\n", m.Pos, MetricType[int32(*m.MetricFamily.Type)], *m.MetricFamily.Name)
} else if addHelp {
fmt.Fprintf(tw, "%v\t%v\t%v\n", MetricType[int32(*m.MetricFamily.Type)], *m.MetricFamily.Name, *m.MetricFamily.Help)
help := "N/A"
if m.MetricFamily.Help != nil {
help = *m.MetricFamily.Help
}

labels := strings.Join(m.Labels(), ",")
if labels == "" {
labels = "N/A"
}

var lineArr []string

mname := *m.MetricFamily.Name
if p.fmt == "md" {
mname = fmt.Sprintf("`%s`", *m.MetricFamily.Name)
labels = fmt.Sprintf("`%s`", labels)
}

if (p.addPosition || p.addModule) && p.addHelp {
lineArr = []string{
p.pos(m.Pos.String()),
MetricType[int32(*m.MetricFamily.Type)],
mname,
labels,
help,
}
} else if p.addPosition || p.addModule {
lineArr = []string{
p.pos(m.Pos.String()),
MetricType[int32(*m.MetricFamily.Type)],
mname,
labels,
}

} else if p.addHelp {
lineArr = []string{
MetricType[int32(*m.MetricFamily.Type)],
mname,
labels,
help,
}
} else {
fmt.Fprintf(tw, "%v\t%v\n", MetricType[int32(*m.MetricFamily.Type)], *m.MetricFamily.Name)
lineArr = []string{
MetricType[int32(*m.MetricFamily.Type)],
mname,
labels,
}
}

if p.fmt == "md" {
fmt.Fprintf(tw, "|%s|\n", strings.Join(lineArr, fieldSep))
} else {
fmt.Fprintf(tw, "%s\n", strings.Join(lineArr, fieldSep))
}
}
}

func printAsYaml(metrics []promlinter.MetricFamilyWithPos) {
b, err := yaml.Marshal(toPrint(metrics))
type printer struct {
fmt string
addHelp, addPosition, addModule bool
metrics []promlinter.MetricFamilyWithPos
}

func (p *printer) pos(pos string) (x string) {
if p.addModule {
x = filepath.Dir(pos)
} else {
x = pos
}

if p.fmt == "md" {
return fmt.Sprintf("*%s*", x) // italic file path
}
return
}

func (p *printer) printMetrics() {
switch p.fmt {
case "json":
p.printAsJson()
return
case "yaml":
p.printAsYaml()
return
default:
p.printDefault()
return
}
}

func (p *printer) printAsYaml() {
b, err := yaml.Marshal(toPrint(p.metrics))
if err != nil {
fmt.Printf("Failed: %v", err)
os.Exit(1)
Expand All @@ -181,8 +295,8 @@ func printAsYaml(metrics []promlinter.MetricFamilyWithPos) {

}

func printAsJson(metrics []promlinter.MetricFamilyWithPos) {
b, err := json.Marshal(toPrint(metrics))
func (p *printer) printAsJson() {
b, err := json.MarshalIndent(toPrint(p.metrics), "", " ")
if err != nil {
fmt.Printf("Failed: %v", err)
os.Exit(1)
Expand All @@ -195,6 +309,7 @@ type MetricForPrinting struct {
Help string
Type string
Filename string
Labels []string
Line int
Column int
}
Expand All @@ -215,13 +330,24 @@ func toPrint(metrics []promlinter.MetricFamilyWithPos) []MetricForPrinting {
if m.MetricFamily.Help != nil {
h = *m.MetricFamily.Help
}

var labels []string
for _, m := range m.MetricFamily.Metric {
for idx, _ := range m.Label {
if m.Label[idx].Name != nil {
labels = append(labels, strings.Trim(*m.Label[idx].Name, `"`))
}
}
}

i := MetricForPrinting{
Name: n,
Help: h,
Type: MetricType[int32(*m.MetricFamily.Type)],
Filename: m.Pos.Filename,
Line: m.Pos.Line,
Column: m.Pos.Column,
Labels: labels,
}
p = append(p, i)
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.20
require (
github.com/prometheus/client_golang v1.12.1
github.com/prometheus/client_model v0.2.0
github.com/stretchr/testify v1.8.4
gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/yaml.v2 v2.4.0
)
Expand Down
10 changes: 9 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,15 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down Expand Up @@ -461,6 +466,9 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
Expand Down
Loading

0 comments on commit 66dbcb5

Please sign in to comment.