diff options
| author | Taras Madan <tarasmadan@google.com> | 2025-01-22 16:07:17 +0100 |
|---|---|---|
| committer | Taras Madan <tarasmadan@google.com> | 2025-01-23 10:42:36 +0000 |
| commit | 7b4377ad9d8a7205416df8d6217ef2b010f89481 (patch) | |
| tree | e6fec4fd12ff807a16d847923f501075bf71d16c /vendor/github.com/yeya24 | |
| parent | 475a4c203afb8b7d3af51c4fd32bb170ff32a45e (diff) | |
vendor: delete
Diffstat (limited to 'vendor/github.com/yeya24')
| -rw-r--r-- | vendor/github.com/yeya24/promlinter/.gitignore | 20 | ||||
| -rw-r--r-- | vendor/github.com/yeya24/promlinter/LICENSE | 201 | ||||
| -rw-r--r-- | vendor/github.com/yeya24/promlinter/Makefile | 39 | ||||
| -rw-r--r-- | vendor/github.com/yeya24/promlinter/README.md | 80 | ||||
| -rw-r--r-- | vendor/github.com/yeya24/promlinter/promlinter.go | 831 |
5 files changed, 0 insertions, 1171 deletions
diff --git a/vendor/github.com/yeya24/promlinter/.gitignore b/vendor/github.com/yeya24/promlinter/.gitignore deleted file mode 100644 index bffb9a029..000000000 --- a/vendor/github.com/yeya24/promlinter/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# binary -bin - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -.idea diff --git a/vendor/github.com/yeya24/promlinter/LICENSE b/vendor/github.com/yeya24/promlinter/LICENSE deleted file mode 100644 index 261eeb9e9..000000000 --- a/vendor/github.com/yeya24/promlinter/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/vendor/github.com/yeya24/promlinter/Makefile b/vendor/github.com/yeya24/promlinter/Makefile deleted file mode 100644 index d50db1ee7..000000000 --- a/vendor/github.com/yeya24/promlinter/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -GOOS := $(if $(GOOS),$(GOOS),linux) -GOARCH := $(if $(GOARCH),$(GOARCH),amd64) -GO=CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) GO111MODULE=on go -GOVERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1) - -GIT_COMMIT = $(shell git rev-parse --short HEAD) - -BUILDFLAGS ?= - -ifeq ($(shell expr ${GOVERSION} \>= 1.14), 1) - BUILDFLAGS += -mod=mod -endif - -PACKAGE_LIST := go list ./... -PACKAGES := $$($(PACKAGE_LIST)) -FILES_TO_FMT := $(shell find . -path -prune -o -name '*.go' -print) - -all: format build test - -format: vet fmt - -fmt: - @echo "gofmt" - @gofmt -w ${FILES_TO_FMT} - @git diff --exit-code . - -build: mod - $(GO) build ${BUILDFLAGS} -o ./bin/promlinter cmd/promlinter/main.go - -vet: - $(GO) vet ${BUILDFLAGS} ./... - -mod: - @echo "go mod tidy" - $(GO) mod tidy - @git diff --exit-code -- go.mod - -test: - $(GO) test ${BUILDFLAGS} ./... -cover $(PACKAGES) diff --git a/vendor/github.com/yeya24/promlinter/README.md b/vendor/github.com/yeya24/promlinter/README.md deleted file mode 100644 index 4fbffaa6b..000000000 --- a/vendor/github.com/yeya24/promlinter/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# promlinter - -A linter for checking Prometheus metrics name via promlint. - - - -## Installation - -### Go Get - -go get github.com/yeya24/promlinter/cmd/promlinter - -### Download from release - -Please go to https://github.com/yeya24/promlinter/releases. - -### Build from source - -#### Requirements - -- Go >= 1.13 -- make - -``` bash -git clone https://github.com/yeya24/promlinter.git -make build -``` - -Then you can find the `promlinter` binary file in the `./bin` directory. - -## Usage - -``` bash -usage: promlinter [<flags>] <command> [<args> ...] - -Prometheus metrics linter for Go code. - -This tool can cover most of the patterns of metrics naming issues, but it cannot detect metric values that can only be determined in the runtime. - -By default it doesn't output parsing failures, if you want to see them, you can add --strict flag to enable it. - -It is also supported to disable the lint functions using repeated flag --disable. Current supported functions are: - - [Help]: Help detects issues related to the help text for a metric. - - [MetricUnits]: MetricUnits detects issues with metric unit names. - - [Counter]: Counter detects issues specific to counters, as well as patterns that should only be used with counters. - - [HistogramSummaryReserved]: HistogramSummaryReserved detects when other types of metrics use names or labels reserved for use by histograms and/or summaries. - - [MetricTypeInName]: MetricTypeInName detects when metric types are included in the metric name. - - [ReservedChars]: ReservedChars detects colons in metric names. - - [CamelCase]: CamelCase detects metric names and label names written in camelCase. - - [UnitAbbreviations]: UnitAbbreviations detects abbreviated units in the metric name. - -Flags: - -h, --help Show context-sensitive help (also try --help-long and --help-man). - --version Show application version. - -Commands: - help [<command>...] - Show help. - - list [<flags>] [<files>...] - List metrics name. - - lint [<flags>] [<files>...] - Lint metrics via promlint. - -``` - -## Run tests - -``` bash -make test -``` diff --git a/vendor/github.com/yeya24/promlinter/promlinter.go b/vendor/github.com/yeya24/promlinter/promlinter.go deleted file mode 100644 index 17a7f4c3e..000000000 --- a/vendor/github.com/yeya24/promlinter/promlinter.go +++ /dev/null @@ -1,831 +0,0 @@ -package promlinter - -import ( - "fmt" - "go/ast" - "go/token" - "sort" - "strconv" - "strings" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/testutil/promlint" - dto "github.com/prometheus/client_model/go" -) - -var ( - metricsType map[string]dto.MetricType - constMetricArgNum map[string]int - validOptsFields map[string]bool - lintFuncText map[string][]string - LintFuncNames []string -) - -func init() { - metricsType = map[string]dto.MetricType{ - "Counter": dto.MetricType_COUNTER, - "NewCounter": dto.MetricType_COUNTER, - "NewCounterVec": dto.MetricType_COUNTER, - "Gauge": dto.MetricType_GAUGE, - "NewGauge": dto.MetricType_GAUGE, - "NewGaugeVec": dto.MetricType_GAUGE, - "NewHistogram": dto.MetricType_HISTOGRAM, - "NewHistogramVec": dto.MetricType_HISTOGRAM, - "NewSummary": dto.MetricType_SUMMARY, - "NewSummaryVec": dto.MetricType_SUMMARY, - } - - constMetricArgNum = map[string]int{ - "MustNewConstMetric": 3, - "MustNewHistogram": 4, - "MustNewSummary": 4, - "NewLazyConstMetric": 3, - } - - // Doesn't contain ConstLabels since we don't need this field here. - validOptsFields = map[string]bool{ - "Name": true, - "Namespace": true, - "Subsystem": true, - "Help": true, - } - - lintFuncText = map[string][]string{ - "Help": {"no help text"}, - "MetricUnits": {"use base unit"}, - "Counter": {"counter metrics should"}, - "HistogramSummaryReserved": {"non-histogram", "non-summary"}, - "MetricTypeInName": {"metric name should not include type"}, - "ReservedChars": {"metric names should not contain ':'"}, - "CamelCase": {"'snake_case' not 'camelCase'"}, - "lintUnitAbbreviations": {"metric names should not contain abbreviated units"}, - } - - LintFuncNames = []string{"Help", "MetricUnits", "Counter", "HistogramSummaryReserved", - "MetricTypeInName", "ReservedChars", "CamelCase", "lintUnitAbbreviations"} -} - -type Setting struct { - Strict bool - DisabledLintFuncs []string -} - -// Issue contains metric name, error text and metric position. -type Issue struct { - Text string - Metric string - Pos token.Position -} - -type MetricFamilyWithPos struct { - MetricFamily *dto.MetricFamily - Pos token.Position -} - -func (m *MetricFamilyWithPos) Labels() []string { - var arr []string - if len(m.MetricFamily.Metric) > 0 { - for _, label := range m.MetricFamily.Metric[0].Label { - if label.Value != nil { - arr = append(arr, - fmt.Sprintf("%s=%s", - strings.Trim(*label.Name, `"`), - strings.Trim(*label.Value, `"`))) - } else { - arr = append(arr, strings.Trim(*label.Name, `"`)) - } - } - } - return arr -} - -type visitor struct { - fs *token.FileSet - metrics []MetricFamilyWithPos - issues []Issue - strict bool -} - -type opt struct { - namespace string - subsystem string - name string - - help string - helpSet bool - - labels []string - constLabels map[string]string -} - -func RunList(fs *token.FileSet, files []*ast.File, strict bool) []MetricFamilyWithPos { - v := &visitor{ - fs: fs, - metrics: make([]MetricFamilyWithPos, 0), - issues: make([]Issue, 0), - strict: strict, - } - - for _, file := range files { - ast.Walk(v, file) - } - - sort.Slice(v.metrics, func(i, j int) bool { - return v.metrics[i].Pos.String() < v.metrics[j].Pos.String() - }) - return v.metrics -} - -func RunLint(fs *token.FileSet, files []*ast.File, s Setting) []Issue { - v := &visitor{ - fs: fs, - metrics: make([]MetricFamilyWithPos, 0), - issues: make([]Issue, 0), - strict: s.Strict, - } - - for _, file := range files { - ast.Walk(v, file) - } - - // lint metrics - for _, mfp := range v.metrics { - problems, err := promlint.NewWithMetricFamilies([]*dto.MetricFamily{mfp.MetricFamily}).Lint() - if err != nil { - panic(err) - } - - for _, p := range problems { - for _, disabledFunc := range s.DisabledLintFuncs { - for _, pattern := range lintFuncText[disabledFunc] { - if strings.Contains(p.Text, pattern) { - goto END - } - } - } - - v.issues = append(v.issues, Issue{ - Pos: mfp.Pos, - Metric: p.Metric, - Text: p.Text, - }) - - END: - } - } - - return v.issues -} - -func (v *visitor) Visit(n ast.Node) ast.Visitor { - if n == nil { - return v - } - - switch t := n.(type) { - case *ast.CallExpr: - return v.parseCallerExpr(t) - - case *ast.SendStmt: - return v.parseSendMetricChanExpr(t) - - default: - } - - return v -} - -func (v *visitor) addMetric(mfp *MetricFamilyWithPos) { - for _, m := range v.metrics { - if mfp.MetricFamily.String() == m.MetricFamily.String() { - return - } - } - - v.metrics = append(v.metrics, *mfp) -} - -func (v *visitor) parseCallerExpr(call *ast.CallExpr) ast.Visitor { - var ( - metricType dto.MetricType - methodName string - ok bool - ) - - switch stmt := call.Fun.(type) { - - /* - That's the case of setting alias . to client_golang/prometheus or promauto package. - - import . "github.com/prometheus/client_golang/prometheus" - metric := NewCounter(CounterOpts{}) - */ - case *ast.Ident: - if stmt.Name == "NewCounterFunc" { - return v.parseOpts(call.Args, dto.MetricType_COUNTER) - } - - if stmt.Name == "NewGaugeFunc" { - return v.parseOpts(call.Args, dto.MetricType_GAUGE) - } - - if metricType, ok = metricsType[stmt.Name]; !ok { - return v - } - - methodName = stmt.Name - - /* - This case covers the most of cases to initialize metrics. - - prometheus.NewCounter(CounterOpts{}) - - promauto.With(nil).NewCounter(CounterOpts{}) - - factory := promauto.With(nil) - factory.NewCounter(CounterOpts{}) - - prometheus.NewCounterFunc() - */ - case *ast.SelectorExpr: - if stmt.Sel.Name == "NewCounterFunc" { - return v.parseOpts(call.Args, dto.MetricType_COUNTER) - } - - if stmt.Sel.Name == "NewGaugeFunc" { - return v.parseOpts(call.Args, dto.MetricType_GAUGE) - } - - if stmt.Sel.Name == "NewFamilyGenerator" && len(call.Args) == 5 { - return v.parseKSMMetrics(call.Args[0], call.Args[1], call.Args[2]) - } - - if metricType, ok = metricsType[stmt.Sel.Name]; !ok { - return v - } - - methodName = stmt.Sel.Name - - default: - return v - } - - argNum := 1 - if strings.HasSuffix(methodName, "Vec") { - argNum = 2 - } - // The methods used to initialize metrics should have at least one arg. - if len(call.Args) < argNum && v.strict { - v.issues = append(v.issues, Issue{ - Pos: v.fs.Position(call.Pos()), - Metric: "", - Text: fmt.Sprintf("%s should have at least %d arguments", methodName, argNum), - }) - return v - } - - if len(call.Args) == 0 { - return v - } - - return v.parseOpts(call.Args, metricType) -} - -func (v *visitor) parseOpts(optArgs []ast.Expr, metricType dto.MetricType) ast.Visitor { - // position for the first arg of the CallExpr - optsPosition := v.fs.Position(optArgs[0].Pos()) - opts := v.parseOptsExpr(optArgs[0]) - - var metric *dto.Metric - if len(optArgs) > 1 { - // parse labels - if labelOpts := v.parseOptsExpr(optArgs[1]); labelOpts != nil && len(labelOpts.labels) > 0 { - metric = &dto.Metric{} - for idx, _ := range labelOpts.labels { - metric.Label = append(metric.Label, - &dto.LabelPair{ - Name: &labelOpts.labels[idx], - }) - } - } - } - - if opts == nil { - return v - } - - currentMetric := dto.MetricFamily{ - Type: &metricType, - } - - if !opts.helpSet { - currentMetric.Help = nil - } else { - currentMetric.Help = &opts.help - } - - if metric != nil { - currentMetric.Metric = append(currentMetric.Metric, metric) - } - - metricName := prometheus.BuildFQName(opts.namespace, opts.subsystem, opts.name) - // We skip the invalid metric if the name is an empty string. - // This kind of metric declaration might be used as a stud metric - // https://github.com/thanos-io/thanos/blob/main/cmd/thanos/tools_bucket.go#L538. - if metricName == "" { - return v - } - currentMetric.Name = &metricName - - v.addMetric(&MetricFamilyWithPos{MetricFamily: ¤tMetric, Pos: optsPosition}) - return v -} - -// Parser for kube-state-metrics generators. -func (v *visitor) parseKSMMetrics(nameArg ast.Node, helpArg ast.Node, metricTypeArg ast.Node) ast.Visitor { - optsPosition := v.fs.Position(nameArg.Pos()) - currentMetric := dto.MetricFamily{} - name, ok := v.parseValue("name", nameArg) - if !ok { - return v - } - currentMetric.Name = &name - - help, ok := v.parseValue("help", helpArg) - if !ok { - return v - } - currentMetric.Help = &help - - switch stmt := metricTypeArg.(type) { - case *ast.SelectorExpr: - if metricType, ok := metricsType[stmt.Sel.Name]; !ok { - return v - } else { - currentMetric.Type = &metricType - } - } - - v.addMetric(&MetricFamilyWithPos{MetricFamily: ¤tMetric, Pos: optsPosition}) - - return v -} - -func (v *visitor) parseSendMetricChanExpr(chExpr *ast.SendStmt) ast.Visitor { - var ( - ok bool - requiredArgNum int - methodName string - metricType dto.MetricType - ) - - call, ok := chExpr.Value.(*ast.CallExpr) - if !ok { - return v - } - - switch stmt := call.Fun.(type) { - case *ast.Ident: - if requiredArgNum, ok = constMetricArgNum[stmt.Name]; !ok { - return v - } - methodName = stmt.Name - - case *ast.SelectorExpr: - if requiredArgNum, ok = constMetricArgNum[stmt.Sel.Name]; !ok { - return v - } - methodName = stmt.Sel.Name - } - - if len(call.Args) < requiredArgNum && v.strict { - v.issues = append(v.issues, Issue{ - Metric: "", - Pos: v.fs.Position(call.Pos()), - Text: fmt.Sprintf("%s should have at least %d arguments", methodName, requiredArgNum), - }) - return v - } - - if len(call.Args) == 0 { - return v - } - - descCall := v.parseConstMetricOptsExpr(call.Args[0]) - if descCall == nil { - return v - } - - metric := &dto.MetricFamily{ - Name: descCall.name, - Help: descCall.help, - } - - if len(descCall.labels) > 0 { - m := &dto.Metric{} - for idx, _ := range descCall.labels { - m.Label = append(m.Label, - &dto.LabelPair{ - Name: &descCall.labels[idx], - }) - } - - for idx, _ := range descCall.constLabels { - m.Label = append(m.Label, - &dto.LabelPair{ - Name: &descCall.constLabels[idx][0], - Value: &descCall.constLabels[idx][1], - }) - } - - metric.Metric = append(metric.Metric, m) - } - - switch methodName { - case "MustNewConstMetric", "NewLazyConstMetric": - switch t := call.Args[1].(type) { - case *ast.Ident: - metric.Type = getConstMetricType(t.Name) - case *ast.SelectorExpr: - metric.Type = getConstMetricType(t.Sel.Name) - } - - case "MustNewHistogram": - metricType = dto.MetricType_HISTOGRAM - metric.Type = &metricType - case "MustNewSummary": - metricType = dto.MetricType_SUMMARY - metric.Type = &metricType - } - - v.addMetric(&MetricFamilyWithPos{MetricFamily: metric, Pos: v.fs.Position(call.Pos())}) - return v -} - -func (v *visitor) parseOptsExpr(n ast.Node) *opt { - switch stmt := n.(type) { - case *ast.CompositeLit: - return v.parseCompositeOpts(stmt) - - case *ast.Ident: - if stmt.Obj != nil { - if decl, ok := stmt.Obj.Decl.(*ast.AssignStmt); ok && len(decl.Rhs) > 0 { - if t, ok := decl.Rhs[0].(*ast.CompositeLit); ok { - return v.parseCompositeOpts(t) - } - } - } - - case *ast.UnaryExpr: - return v.parseOptsExpr(stmt.X) - } - - return nil -} - -func (v *visitor) parseCompositeOpts(stmt *ast.CompositeLit) *opt { - metricOption := &opt{} - - for _, elt := range stmt.Elts { - - // labels - label, ok := elt.(*ast.BasicLit) - if ok { - metricOption.labels = append(metricOption.labels, strings.Trim(label.Value, `"`)) - continue - } - - kvExpr, ok := elt.(*ast.KeyValueExpr) - if !ok { - continue - } - - // const labels - if key, ok := kvExpr.Key.(*ast.BasicLit); ok { - - if metricOption.constLabels == nil { - metricOption.constLabels = map[string]string{} - } - - // only accept literal string value - // - // { - // "key": "some-string-literal", - // } - switch val := kvExpr.Value.(type) { - case *ast.BasicLit: - metricOption.constLabels[key.Value] = val.Value - - default: - metricOption.constLabels[key.Value] = "?" // use a placeholder for the const label - } - - continue - } - - object, ok := kvExpr.Key.(*ast.Ident) - if !ok { - continue - } - - if _, ok := validOptsFields[object.Name]; !ok { - continue - } - - // If failed to parse field value, stop parsing. - stringLiteral, ok := v.parseValue(object.Name, kvExpr.Value) - if !ok { - return nil - } - - switch object.Name { - case "Namespace": - metricOption.namespace = stringLiteral - case "Subsystem": - metricOption.subsystem = stringLiteral - case "Name": - metricOption.name = stringLiteral - case "Help": - metricOption.help = stringLiteral - metricOption.helpSet = true - } - } - - return metricOption -} - -func (v *visitor) parseValue(object string, n ast.Node) (string, bool) { - - switch t := n.(type) { - - // make sure it is string literal value - case *ast.BasicLit: - if t.Kind == token.STRING { - return mustUnquote(t.Value), true - } - - return "", false - - case *ast.Ident: - if t.Obj == nil { - return "", false - } - - switch vs := t.Obj.Decl.(type) { - - case *ast.ValueSpec: - // var some string = "some string" - return v.parseValue(object, vs) - - case *ast.AssignStmt: - // TODO: - // some := "some string" - return "", false - - default: - return "", false - } - - case *ast.ValueSpec: - if len(t.Values) == 0 { - return "", false - } - - return v.parseValue(object, t.Values[0]) - - // For binary expr, we only support adding two strings like `foo` + `bar`. - case *ast.BinaryExpr: - if t.Op == token.ADD { - x, ok := v.parseValue(object, t.X) - if !ok { - return "", false - } - - y, ok := v.parseValue(object, t.Y) - if !ok { - return "", false - } - - return x + y, true - } - - // We can only cover some basic cases here - case *ast.CallExpr: - return v.parseValueCallExpr(object, t) - - default: - if v.strict { - v.issues = append(v.issues, Issue{ - Pos: v.fs.Position(n.Pos()), - Metric: "", - Text: fmt.Sprintf("parsing %s with type %T is not supported", object, t), - }) - } - } - - return "", false -} - -func (v *visitor) parseValueCallExpr(object string, call *ast.CallExpr) (string, bool) { - var ( - methodName string - namespace string - subsystem string - name string - ok bool - ) - switch expr := call.Fun.(type) { - case *ast.SelectorExpr: - methodName = expr.Sel.Name - case *ast.Ident: - methodName = expr.Name - default: - return "", false - } - - if methodName == "BuildFQName" && len(call.Args) == 3 { - namespace, ok = v.parseValue("namespace", call.Args[0]) - if !ok { - return "", false - } - subsystem, ok = v.parseValue("subsystem", call.Args[1]) - if !ok { - return "", false - } - name, ok = v.parseValue("name", call.Args[2]) - if !ok { - return "", false - } - return prometheus.BuildFQName(namespace, subsystem, name), true - } - - if v.strict { - v.issues = append(v.issues, Issue{ - Metric: "", - Pos: v.fs.Position(call.Pos()), - Text: fmt.Sprintf("parsing %s with function %s is not supported", object, methodName), - }) - } - - return "", false -} - -func (v *visitor) parseConstMetricOptsExpr(n ast.Node) *descCallExpr { - switch stmt := n.(type) { - case *ast.CallExpr: - return v.parseNewDescCallExpr(stmt) - - case *ast.Ident: - if stmt.Obj != nil { - switch t := stmt.Obj.Decl.(type) { - case *ast.AssignStmt: - if len(t.Rhs) > 0 { - if call, ok := t.Rhs[0].(*ast.CallExpr); ok { - return v.parseNewDescCallExpr(call) - } - } - case *ast.ValueSpec: - if len(t.Values) > 0 { - if call, ok := t.Values[0].(*ast.CallExpr); ok { - return v.parseNewDescCallExpr(call) - } - } - } - - if v.strict { - v.issues = append(v.issues, Issue{ - Pos: v.fs.Position(stmt.Pos()), - Metric: "", - Text: fmt.Sprintf("parsing desc of type %T is not supported", stmt.Obj.Decl), - }) - } - } - - default: - if v.strict { - v.issues = append(v.issues, Issue{ - Pos: v.fs.Position(stmt.Pos()), - Metric: "", - Text: fmt.Sprintf("parsing desc of type %T is not supported", stmt), - }) - } - } - - return nil -} - -type descCallExpr struct { - name, help *string - labels []string - constLabels [][2]string -} - -func (v *visitor) parseNewDescCallExpr(call *ast.CallExpr) *descCallExpr { - var ( - help string - name string - ok bool - ) - - switch expr := call.Fun.(type) { - case *ast.Ident: - if expr.Name != "NewDesc" { - if v.strict { - v.issues = append(v.issues, Issue{ - Pos: v.fs.Position(expr.Pos()), - Metric: "", - Text: fmt.Sprintf("parsing desc with function %s is not supported", expr.Name), - }) - } - return nil - } - case *ast.SelectorExpr: - if expr.Sel.Name != "NewDesc" { - if v.strict { - v.issues = append(v.issues, Issue{ - Pos: v.fs.Position(expr.Sel.Pos()), - Metric: "", - Text: fmt.Sprintf("parsing desc with function %s is not supported", expr.Sel.Name), - }) - } - return nil - } - default: - if v.strict { - v.issues = append(v.issues, Issue{ - Pos: v.fs.Position(expr.Pos()), - Metric: "", - Text: fmt.Sprintf("parsing desc of %T is not supported", expr), - }) - } - return nil - } - - // k8s.io/component-base/metrics.NewDesc has 6 args - // while prometheus.NewDesc has 4 args - if len(call.Args) < 4 && v.strict { - v.issues = append(v.issues, Issue{ - Metric: "", - Pos: v.fs.Position(call.Pos()), - Text: "NewDesc should have at least 4 args", - }) - return nil - } - - name, ok = v.parseValue("fqName", call.Args[0]) - if !ok { - return nil - } - - help, ok = v.parseValue("help", call.Args[1]) - if !ok { - return nil - } - - res := &descCallExpr{ - name: &name, - help: &help, - } - - if x, ok := call.Args[2].(*ast.CompositeLit); ok { - opt := v.parseCompositeOpts(x) - if opt == nil { - return nil - } - - res.labels = opt.labels - } - - if x, ok := call.Args[3].(*ast.CompositeLit); ok { - opt := v.parseCompositeOpts(x) - if opt == nil { - return nil - } - - for k, v := range opt.constLabels { - res.constLabels = append(res.constLabels, [2]string{k, v}) - } - } - - return res -} - -func mustUnquote(str string) string { - stringLiteral, err := strconv.Unquote(str) - if err != nil { - panic(err) - } - - return stringLiteral -} - -func getConstMetricType(name string) *dto.MetricType { - metricType := dto.MetricType_UNTYPED - if name == "CounterValue" { - metricType = dto.MetricType_COUNTER - } else if name == "GaugeValue" { - metricType = dto.MetricType_GAUGE - } - - return &metricType -} |
