Compare commits

...

16 Commits

Author SHA1 Message Date
William Banfield
a7580e4e34 comment fixup 2022-05-09 18:55:11 -04:00
William Banfield
ea6c550a68 fix lint 2022-05-09 18:40:05 -04:00
William Banfield
eed64b30ce check file changes in tests 2022-05-09 18:34:14 -04:00
William Banfield
cc81b63094 fix tags testdata 2022-05-09 18:28:00 -04:00
William Banfield
28b607eb5f codegen testdata metrics 2022-05-09 18:22:22 -04:00
William Banfield
a5a4ec01a8 remove unused dir flag 2022-05-09 18:06:07 -04:00
William Banfield
410a7023c0 label rename 2022-05-09 17:41:18 -04:00
William Banfield
2d52faf462 fetch->find 2022-05-09 17:39:52 -04:00
William Banfield
d50049a0cf extract metrics package name 2022-05-09 17:37:46 -04:00
William Banfield
83455c4772 write string fix 2022-05-09 17:27:30 -04:00
William Banfield
d17edba3cd Update scripts/metricsgen/metricsgen_test.go
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
2022-05-09 17:00:12 -04:00
William Banfield
6469c0564c Update scripts/metricsgen/metricsgen.go
Co-authored-by: M. J. Fromberger <fromberger@interchain.io>
2022-05-09 16:59:02 -04:00
William Banfield
0750b1f13e change erroneous PHONY 2022-05-09 11:44:15 -04:00
William Banfield
f32958f61b Merge branch 'master' into wb/mg 2022-05-09 11:36:59 -04:00
William Banfield
0ba44bd40a make linter happy 2022-05-09 11:36:18 -04:00
William Banfield
2b2c7a6374 scripts/metricsgen: add the initial version of metricsgen 2022-05-09 11:32:14 -04:00
11 changed files with 812 additions and 50 deletions

View File

@@ -251,6 +251,21 @@ mockery:
go generate -run="./scripts/mockery_generate.sh" ./...
.PHONY: mockery
###############################################################################
### Metrics ###
###############################################################################
metrics: testdata-metrics
go generate -run="scripts/metricsgen" ./...
.PHONY: metrics
# By convention, the go tool ignores subdirectories of directories named
# 'testdata'. This command invokes the generate command on the folder directly
# to avoid this.
testdata-metrics:
ls ./scripts/metricsgen/testdata | xargs -I{} go generate -run="scripts/metricsgen" ./scripts/metricsgen/testdata/{}
.PHONY: testdata-metrics
###############################################################################
### Local testnet using docker ###
###############################################################################

View File

@@ -0,0 +1,51 @@
// Code generated by metricsgen. DO NOT EDIT.
package indexer
import (
"github.com/go-kit/kit/metrics/discard"
prometheus "github.com/go-kit/kit/metrics/prometheus"
stdprometheus "github.com/prometheus/client_golang/prometheus"
)
func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
labels := []string{}
for i := 0; i < len(labelsAndValues); i += 2 {
labels = append(labels, labelsAndValues[i])
}
return &Metrics{
BlockEventsSeconds: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "block_events_seconds",
Help: "Latency for indexing block events.",
}, labels).With(labelsAndValues...),
TxEventsSeconds: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "tx_events_seconds",
Help: "Latency for indexing transaction events.",
}, labels).With(labelsAndValues...),
BlocksIndexed: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "blocks_indexed",
Help: "Number of complete blocks indexed.",
}, labels).With(labelsAndValues...),
TransactionsIndexed: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "transactions_indexed",
Help: "Number of transactions indexed.",
}, labels).With(labelsAndValues...),
}
}
func NopMetrics() *Metrics {
return &Metrics{
BlockEventsSeconds: discard.NewHistogram(),
TxEventsSeconds: discard.NewHistogram(),
BlocksIndexed: discard.NewCounter(),
TransactionsIndexed: discard.NewCounter(),
}
}

View File

@@ -2,12 +2,10 @@ package indexer
import (
"github.com/go-kit/kit/metrics"
"github.com/go-kit/kit/metrics/discard"
prometheus "github.com/go-kit/kit/metrics/prometheus"
stdprometheus "github.com/prometheus/client_golang/prometheus"
)
//go:generate go run github.com/tendermint/tendermint/scripts/metricsgen -struct=Metrics
// MetricsSubsystem is a the subsystem label for the indexer package.
const MetricsSubsystem = "indexer"
@@ -25,49 +23,3 @@ type Metrics struct {
// Number of transactions indexed.
TransactionsIndexed metrics.Counter
}
// PrometheusMetrics returns Metrics build using Prometheus client library.
// Optionally, labels can be provided along with their values ("foo",
// "fooValue").
func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
labels := []string{}
for i := 0; i < len(labelsAndValues); i += 2 {
labels = append(labels, labelsAndValues[i])
}
return &Metrics{
BlockEventsSeconds: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "block_events_seconds",
Help: "Latency for indexing block events.",
}, labels).With(labelsAndValues...),
TxEventsSeconds: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "tx_events_seconds",
Help: "Latency for indexing transaction events.",
}, labels).With(labelsAndValues...),
BlocksIndexed: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "blocks_indexed",
Help: "Number of complete blocks indexed.",
}, labels).With(labelsAndValues...),
TransactionsIndexed: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "transactions_indexed",
Help: "Number of transactions indexed.",
}, labels).With(labelsAndValues...),
}
}
// NopMetrics returns an indexer metrics stub that discards all samples.
func NopMetrics() *Metrics {
return &Metrics{
BlockEventsSeconds: discard.NewHistogram(),
TxEventsSeconds: discard.NewHistogram(),
BlocksIndexed: discard.NewCounter(),
TransactionsIndexed: discard.NewCounter(),
}
}

View File

@@ -0,0 +1,337 @@
// metricsgen is a code generation tool for creating constructors for Tendermint
// metrics types.
package main
import (
"bytes"
"flag"
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/token"
"go/types"
"io"
"io/fs"
"log"
"os"
"path"
"path/filepath"
"reflect"
"regexp"
"strconv"
"strings"
"text/template"
)
func init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %[1]s -struct <struct>
Generate constructors for the metrics type specified by -struct contained in
the current directory. The tool creates a new file in the current directory
containing the generated code.
Options:
`, filepath.Base(os.Args[0]))
flag.PrintDefaults()
}
}
const metricsPackageName = "github.com/go-kit/kit/metrics"
const (
metricNameTag = "metrics_name"
labelsTag = "metrics_labels"
bucketTypeTag = "metrics_buckettype"
bucketSizeTag = "metrics_bucketsizes"
)
var (
dir = flag.String("dir", ".", "Path to the directory containing the target package")
strct = flag.String("struct", "Metrics", "Struct to parse for metrics")
)
var bucketType = map[string]string{
"exprange": "stdprometheus.ExponentialBucketsRange",
"exp": "stdprometheus.ExponentialBuckets",
"lin": "stdprometheus.LinearBuckets",
}
var tmpl = template.Must(template.New("tmpl").Parse(`// Code generated by metricsgen. DO NOT EDIT.
package {{ .Package }}
import (
"github.com/go-kit/kit/metrics/discard"
prometheus "github.com/go-kit/kit/metrics/prometheus"
stdprometheus "github.com/prometheus/client_golang/prometheus"
)
func PrometheusMetrics(namespace string, labelsAndValues...string) *Metrics {
labels := []string{}
for i := 0; i < len(labelsAndValues); i += 2 {
labels = append(labels, labelsAndValues[i])
}
return &Metrics{
{{ range $metric := .ParsedMetrics }}
{{- $metric.FieldName }}: prometheus.New{{ $metric.TypeName }}From(stdprometheus.{{$metric.TypeName }}Opts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "{{$metric.MetricName }}",
Help: "{{ $metric.Description }}",
{{ if ne $metric.HistogramOptions.BucketType "" }}
Buckets: {{ $metric.HistogramOptions.BucketType }}({{ $metric.HistogramOptions.BucketSizes }}),
{{ else if ne $metric.HistogramOptions.BucketSizes "" }}
Buckets: []float64{ {{ $metric.HistogramOptions.BucketSizes }} },
{{ end }}
{{- if eq (len $metric.Labels) 0 }}
}, labels).With(labelsAndValues...),
{{ else }}
}, append(labels, {{$metric.Labels | printf "%q" }})).With(labelsAndValues...),
{{- end }}
{{- end }}
}
}
func NopMetrics() *Metrics {
return &Metrics{
{{- range $metric := .ParsedMetrics }}
{{ $metric.FieldName }}: discard.New{{ $metric.TypeName }}(),
{{- end }}
}
}
`))
// ParsedMetricField is the data parsed for a single field of a metric struct.
type ParsedMetricField struct {
TypeName string
FieldName string
MetricName string
Description string
Labels string
HistogramOptions HistogramOpts
}
type HistogramOpts struct {
BucketType string
BucketSizes string
}
// TemplateData is all of the data required for rendering a metric file template.
type TemplateData struct {
Package string
ParsedMetrics []ParsedMetricField
}
func main() {
flag.Parse()
if *strct == "" {
log.Fatal("You must specify a non-empty -struct")
}
td, err := ParseMetricsDir(".", *strct)
if err != nil {
log.Fatalf("Parsing file: %v", err)
}
out := filepath.Join(*dir, "metrics.gen.go")
f, err := os.Create(out)
if err != nil {
log.Fatalf("Opening file: %v", err)
}
err = GenerateMetricsFile(f, td)
if err != nil {
log.Fatalf("Generating code: %v", err)
}
}
func ignoreTestFiles(f fs.FileInfo) bool {
return !strings.Contains(f.Name(), "_test.go")
}
// ParseMetricsDir parses the dir and scans for a struct matching structName,
// ignoring all test files. ParseMetricsDir iterates the fields of the metrics
// struct and builds a TemplateData using the data obtained from the abstract syntax tree.
func ParseMetricsDir(dir string, structName string) (TemplateData, error) {
fs := token.NewFileSet()
d, err := parser.ParseDir(fs, dir, ignoreTestFiles, parser.ParseComments)
if err != nil {
return TemplateData{}, err
}
if len(d) > 1 {
return TemplateData{}, fmt.Errorf("multiple packages found in %s", dir)
}
if len(d) == 0 {
return TemplateData{}, fmt.Errorf("no go pacakges found in %s", dir)
}
// Grab the package name.
var pkgName string
var pkg *ast.Package
for pkgName, pkg = range d {
}
td := TemplateData{
Package: pkgName,
}
// Grab the metrics struct
m, mPkgName, err := findMetricsStruct(pkg.Files, structName)
if err != nil {
return TemplateData{}, err
}
for _, f := range m.Fields.List {
if !isMetric(f.Type, mPkgName) {
continue
}
pmf := parseMetricField(f)
td.ParsedMetrics = append(td.ParsedMetrics, pmf)
}
return td, err
}
// GenerateMetricsFile executes the metrics file template, writing the result
// into the io.Writer.
func GenerateMetricsFile(w io.Writer, td TemplateData) error {
b := []byte{}
buf := bytes.NewBuffer(b)
err := tmpl.Execute(buf, td)
if err != nil {
return err
}
b, err = format.Source(buf.Bytes())
if err != nil {
return err
}
_, err = io.Copy(w, bytes.NewBuffer(b))
if err != nil {
return err
}
return nil
}
func findMetricsStruct(files map[string]*ast.File, structName string) (*ast.StructType, string, error) {
var (
st *ast.StructType
)
for _, file := range files {
mPkgName, err := extractMetricsPackageName(file.Imports)
if err != nil {
return nil, "", fmt.Errorf("unable to determine metrics package name: %v", err)
}
if !ast.FilterFile(file, func(name string) bool {
return name == structName
}) {
continue
}
ast.Inspect(file, func(n ast.Node) bool {
switch f := n.(type) {
case *ast.TypeSpec:
if f.Name.Name == structName {
var ok bool
st, ok = f.Type.(*ast.StructType)
if !ok {
err = fmt.Errorf("found identifier for %q of wrong type", structName)
}
}
return false
default:
return true
}
})
if err != nil {
return nil, "", err
}
if st != nil {
return st, mPkgName, nil
}
}
return nil, "", fmt.Errorf("target struct %q not found in dir", structName)
}
func parseMetricField(f *ast.Field) ParsedMetricField {
var comment string
if f.Doc != nil {
for i, c := range f.Doc.List {
comment += strings.TrimPrefix(c.Text, "// ")
if i < len(f.Doc.List)-1 {
comment += " "
}
}
}
pmf := ParsedMetricField{
Description: comment,
MetricName: extractFieldName(f.Names[0].String(), f.Tag),
FieldName: f.Names[0].String(),
TypeName: extractTypeName(f.Type),
Labels: extractLabels(f.Tag),
}
if pmf.TypeName == "Histogram" {
pmf.HistogramOptions = extractHistogramOptions(f.Tag)
}
return pmf
}
func extractTypeName(e ast.Expr) string {
return strings.TrimPrefix(path.Ext(types.ExprString(e)), ".")
}
func isMetric(e ast.Expr, mPkgName string) bool {
return strings.Contains(types.ExprString(e), fmt.Sprintf("%s.", mPkgName))
}
func extractLabels(bl *ast.BasicLit) string {
if bl != nil {
t := reflect.StructTag(strings.Trim(bl.Value, "`"))
if v := t.Get(labelsTag); v != "" {
return v
}
}
return ""
}
func extractFieldName(name string, tag *ast.BasicLit) string {
if tag != nil {
t := reflect.StructTag(strings.Trim(tag.Value, "`"))
if v := t.Get(metricNameTag); v != "" {
return v
}
}
return toSnakeCase(name)
}
func extractHistogramOptions(tag *ast.BasicLit) HistogramOpts {
h := HistogramOpts{}
if tag != nil {
t := reflect.StructTag(strings.Trim(tag.Value, "`"))
if v := t.Get(bucketTypeTag); v != "" {
h.BucketType = bucketType[v]
}
if v := t.Get(bucketSizeTag); v != "" {
h.BucketSizes = v
}
}
return h
}
func extractMetricsPackageName(imports []*ast.ImportSpec) (string, error) {
for _, i := range imports {
u, err := strconv.Unquote(i.Path.Value)
if err != nil {
return "", err
}
if u == metricsPackageName {
if i.Name != nil {
return i.Name.Name, nil
}
return path.Base(u), nil
}
}
return "", nil
}
var capitalChange = regexp.MustCompile("([a-z0-9])([A-Z])")
func toSnakeCase(str string) string {
snake := capitalChange.ReplaceAllString(str, "${1}_${2}")
return strings.ToLower(snake)
}

View File

@@ -0,0 +1,259 @@
package main_test
import (
"bytes"
"fmt"
"go/parser"
"go/token"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
metricsgen "github.com/tendermint/tendermint/scripts/metricsgen"
)
const testDataDir = "./testdata"
func TestSimpleTemplate(t *testing.T) {
m := metricsgen.ParsedMetricField{
TypeName: "Histogram",
FieldName: "MyMetric",
MetricName: "request_count",
Description: "how many requests were made since the start of the process",
Labels: "first, second, third",
}
td := metricsgen.TemplateData{
Package: "mypack",
ParsedMetrics: []metricsgen.ParsedMetricField{m},
}
b := bytes.NewBuffer([]byte{})
err := metricsgen.GenerateMetricsFile(b, td)
if err != nil {
t.Fatalf("unable to parse template %v", err)
}
}
func TestFromData(t *testing.T) {
infos, err := ioutil.ReadDir(testDataDir)
if err != nil {
t.Fatalf("unable to open file %v", err)
}
for _, dir := range infos {
t.Run(dir.Name(), func(t *testing.T) {
if !dir.IsDir() {
t.Fatalf("expected file %s to be directory", dir.Name())
}
dirName := path.Join(testDataDir, dir.Name())
pt, err := metricsgen.ParseMetricsDir(dirName, "Metrics")
if err != nil {
t.Fatalf("unable to parse from dir %q: %v", dir, err)
}
outFile := path.Join(dirName, "out.go")
if err != nil {
t.Fatalf("unable to open file %s: %v", outFile, err)
}
of, err := os.Create(outFile)
if err != nil {
t.Fatalf("unable to open file %s: %v", outFile, err)
}
defer os.Remove(outFile)
if err := metricsgen.GenerateMetricsFile(of, pt); err != nil {
t.Fatalf("unable to generate metrics file %s: %v", outFile, err)
}
if _, err := parser.ParseFile(token.NewFileSet(), outFile, nil, parser.AllErrors); err != nil {
t.Fatalf("unable to parse generated file %s: %v", outFile, err)
}
bNew, err := ioutil.ReadFile(outFile)
if err != nil {
t.Fatalf("unable to read generated file %s: %v", outFile, err)
}
goldenFile := path.Join(dirName, "metrics.gen.go")
bOld, err := ioutil.ReadFile(goldenFile)
if err != nil {
t.Fatalf("unable to read file %s: %v", goldenFile, err)
}
if !bytes.Equal(bNew, bOld) {
t.Fatalf("newly generated code in file %s does not match golden file %s\n"+
"if the output of the metricsgen tool is expected to change run the following make target: \n"+
"\tmake metrics", outFile, goldenFile)
}
})
}
}
func TestParseMetricsStruct(t *testing.T) {
const pkgName = "mypkg"
metricsTests := []struct {
name string
shouldError bool
metricsStruct string
expected metricsgen.TemplateData
}{
{
name: "basic",
metricsStruct: `type Metrics struct {
myGauge metrics.Gauge
}`,
expected: metricsgen.TemplateData{
Package: pkgName,
ParsedMetrics: []metricsgen.ParsedMetricField{
{
TypeName: "Gauge",
FieldName: "myGauge",
MetricName: "my_gauge",
},
},
},
},
{
name: "histogram",
metricsStruct: "type Metrics struct {\n" +
"myHistogram metrics.Histogram `metrics_buckettype:\"exp\" metrics_bucketsizes:\"1, 100, .8\"`\n" +
"}",
expected: metricsgen.TemplateData{
Package: pkgName,
ParsedMetrics: []metricsgen.ParsedMetricField{
{
TypeName: "Histogram",
FieldName: "myHistogram",
MetricName: "my_histogram",
HistogramOptions: metricsgen.HistogramOpts{
BucketType: "stdprometheus.ExponentialBuckets",
BucketSizes: "1, 100, .8",
},
},
},
},
},
{
name: "labeled name",
metricsStruct: "type Metrics struct {\n" +
"myCounter metrics.Counter `metrics_name:\"new_name\"`\n" +
"}",
expected: metricsgen.TemplateData{
Package: pkgName,
ParsedMetrics: []metricsgen.ParsedMetricField{
{
TypeName: "Counter",
FieldName: "myCounter",
MetricName: "new_name",
},
},
},
},
{
name: "metric labels",
metricsStruct: "type Metrics struct {\n" +
"myCounter metrics.Counter `metrics_labels:\"label1, label2\"`\n" +
"}",
expected: metricsgen.TemplateData{
Package: pkgName,
ParsedMetrics: []metricsgen.ParsedMetricField{
{
TypeName: "Counter",
FieldName: "myCounter",
MetricName: "my_counter",
Labels: "label1, label2",
},
},
},
},
{
name: "ignore non-metric field",
metricsStruct: `type Metrics struct {
myCounter metrics.Counter
nonMetric string
}`,
expected: metricsgen.TemplateData{
Package: pkgName,
ParsedMetrics: []metricsgen.ParsedMetricField{
{
TypeName: "Counter",
FieldName: "myCounter",
MetricName: "my_counter",
},
},
},
},
}
for _, testCase := range metricsTests {
t.Run(testCase.name, func(t *testing.T) {
dir, err := os.MkdirTemp(os.TempDir(), "metricsdir")
if err != nil {
t.Fatalf("unable to create directory: %v", err)
}
defer os.Remove(dir)
f, err := os.Create(filepath.Join(dir, "metrics.go"))
if err != nil {
t.Fatalf("unable to open file: %v", err)
}
pkgLine := fmt.Sprintf("package %s\n", pkgName)
importClause := `
import(
"github.com/go-kit/kit/metrics"
)
`
_, err = io.WriteString(f, pkgLine)
require.NoError(t, err)
_, err = io.WriteString(f, importClause)
require.NoError(t, err)
_, err = io.WriteString(f, testCase.metricsStruct)
require.NoError(t, err)
td, err := metricsgen.ParseMetricsDir(dir, "Metrics")
if testCase.shouldError {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, testCase.expected, td)
}
})
}
}
func TestParseAliasedMetric(t *testing.T) {
aliasedData := `
package mypkg
import(
mymetrics "github.com/go-kit/kit/metrics"
)
type Metrics struct {
m mymetrics.Gauge
}
`
dir, err := os.MkdirTemp(os.TempDir(), "metricsdir")
if err != nil {
t.Fatalf("unable to create directory: %v", err)
}
defer os.Remove(dir)
f, err := os.Create(filepath.Join(dir, "metrics.go"))
if err != nil {
t.Fatalf("unable to open file: %v", err)
}
_, err = io.WriteString(f, aliasedData)
if err != nil {
t.Fatalf("unable to write to file: %v", err)
}
td, err := metricsgen.ParseMetricsDir(dir, "Metrics")
require.NoError(t, err)
expected :=
metricsgen.TemplateData{
Package: "mypkg",
ParsedMetrics: []metricsgen.ParsedMetricField{
{
TypeName: "Gauge",
FieldName: "m",
MetricName: "m",
},
},
}
require.Equal(t, expected, td)
}

View File

@@ -0,0 +1,30 @@
// Code generated by metricsgen. DO NOT EDIT.
package basic
import (
"github.com/go-kit/kit/metrics/discard"
prometheus "github.com/go-kit/kit/metrics/prometheus"
stdprometheus "github.com/prometheus/client_golang/prometheus"
)
func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
labels := []string{}
for i := 0; i < len(labelsAndValues); i += 2 {
labels = append(labels, labelsAndValues[i])
}
return &Metrics{
Height: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "height",
Help: "simple metric that tracks the height of the chain.",
}, labels).With(labelsAndValues...),
}
}
func NopMetrics() *Metrics {
return &Metrics{
Height: discard.NewGauge(),
}
}

View File

@@ -0,0 +1,11 @@
package basic
import "github.com/go-kit/kit/metrics"
//go:generate go run ../../../../scripts/metricsgen -struct=Metrics
// Metrics contains metrics exposed by this package.
type Metrics struct {
// simple metric that tracks the height of the chain.
Height metrics.Gauge
}

View File

@@ -0,0 +1,30 @@
// Code generated by metricsgen. DO NOT EDIT.
package commented
import (
"github.com/go-kit/kit/metrics/discard"
prometheus "github.com/go-kit/kit/metrics/prometheus"
stdprometheus "github.com/prometheus/client_golang/prometheus"
)
func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
labels := []string{}
for i := 0; i < len(labelsAndValues); i += 2 {
labels = append(labels, labelsAndValues[i])
}
return &Metrics{
Field: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "field",
Help: "Height of the chain. We expect multi-line comments to parse correctly.",
}, labels).With(labelsAndValues...),
}
}
func NopMetrics() *Metrics {
return &Metrics{
Field: discard.NewGauge(),
}
}

View File

@@ -0,0 +1,11 @@
package commented
import "github.com/go-kit/kit/metrics"
//go:generate go run ../../../../scripts/metricsgen -struct=Metrics
type Metrics struct {
// Height of the chain.
// We expect multi-line comments to parse correctly.
Field metrics.Gauge
}

View File

@@ -0,0 +1,54 @@
// Code generated by metricsgen. DO NOT EDIT.
package tags
import (
"github.com/go-kit/kit/metrics/discard"
prometheus "github.com/go-kit/kit/metrics/prometheus"
stdprometheus "github.com/prometheus/client_golang/prometheus"
)
func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
labels := []string{}
for i := 0; i < len(labelsAndValues); i += 2 {
labels = append(labels, labelsAndValues[i])
}
return &Metrics{
WithLabels: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "with_labels",
Help: "",
}, append(labels, "step,time")).With(labelsAndValues...), WithExpBuckets: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "with_exp_buckets",
Help: "",
Buckets: stdprometheus.ExponentialBuckets(.1, 100, 8),
}, labels).With(labelsAndValues...),
WithBuckets: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "with_buckets",
Help: "",
Buckets: []float64{1, 2, 3, 4, 5},
}, labels).With(labelsAndValues...),
Named: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "metric_with_name",
Help: "",
}, labels).With(labelsAndValues...),
}
}
func NopMetrics() *Metrics {
return &Metrics{
WithLabels: discard.NewCounter(),
WithExpBuckets: discard.NewHistogram(),
WithBuckets: discard.NewHistogram(),
Named: discard.NewCounter(),
}
}

View File

@@ -0,0 +1,12 @@
package tags
import "github.com/go-kit/kit/metrics"
//go:generate go run ../../../../scripts/metricsgen -struct=Metrics
type Metrics struct {
WithLabels metrics.Counter `metrics_labels:"step,time"`
WithExpBuckets metrics.Histogram `metrics_buckettype:"exp" metrics_bucketsizes:".1,100,8"`
WithBuckets metrics.Histogram `metrics_bucketsizes:"1, 2, 3, 4, 5"`
Named metrics.Counter `metrics_name:"metric_with_name"`
}