rewrite prometheus meter #52

Merged
vtolstov merged 12 commits from rewrite into v3 2022-03-11 01:26:46 +03:00
8 changed files with 205 additions and 67 deletions
Showing only changes of commit dc498edc1b - Show all commits

20
.github/workflows/autoapprove.yml vendored Normal file
View File

@ -0,0 +1,20 @@
name: "autoapprove"
on:
pull_request_target:
types: [assigned, opened, synchronize, reopened]
permissions:
pull-requests: write
contents: write
jobs:
autoapprove:
runs-on: ubuntu-latest
steps:
- name: approve
uses: hmarr/auto-approve-action@v2
if: github.actor == 'vtolstov' || github.actor == 'dependabot[bot]'
id: approve
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

21
.github/workflows/automerge.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: "automerge"
on:
pull_request_target:
types: [assigned, opened, synchronize, reopened]
permissions:
pull-requests: write
contents: write
jobs:
automerge:
runs-on: ubuntu-latest
if: github.actor == 'vtolstov'
steps:
- name: merge
id: merge
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.TOKEN}}

View File

@ -3,6 +3,7 @@ on:
push:
branches:
- master
- v3
jobs:
test:
name: test
@ -13,7 +14,7 @@ jobs:
with:
go-version: 1.16
- name: checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: cache
uses: actions/cache@v2
with:
@ -31,9 +32,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v3.1.0
continue-on-error: true
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.

View File

@ -43,7 +43,7 @@ jobs:
steps:
- name: checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: setup
uses: actions/setup-go@v2
with:

View File

@ -1,4 +1,4 @@
name: "prautomerge"
name: "dependabot-automerge"
on:
pull_request_target:
@ -9,21 +9,17 @@ permissions:
contents: write
jobs:
dependabot:
automerge:
runs-on: ubuntu-latest
if: ${{ github.actor == 'dependabot[bot]' }}
if: github.actor == 'dependabot[bot]'
steps:
- name: metadata
id: metadata
uses: dependabot/fetch-metadata@v1.2.1
uses: dependabot/fetch-metadata@v1.3.0
with:
github-token: "${{ secrets.TOKEN }}"
- name: approve
run: gh pr review --approve "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.TOKEN}}
- name: merge
id: merge
if: ${{contains(steps.metadata.outputs.dependency-names, 'go.unistack.org')}}
run: gh pr merge --auto --merge "$PR_URL"
env:

View File

@ -3,6 +3,7 @@ on:
pull_request:
branches:
- master
- v3
jobs:
test:
name: test
@ -13,7 +14,7 @@ jobs:
with:
go-version: 1.16
- name: checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: cache
uses: actions/cache@v2
with:
@ -31,9 +32,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v3.1.0
continue-on-error: true
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.

View File

@ -89,30 +89,75 @@ func (m *prometheusMeter) Name() string {
return m.opts.Name
}
func (m *prometheusMeter) mapLabels(labels ...string) map[string]string {
labels = m.buildLabels(labels...)
elementMap := make(map[string]string, len(labels)/2)
for idx := 0; idx < len(labels); idx++ {
elementMap[labels[idx]] = labels[idx+1]
func (m *prometheusMeter) mapLabels(src ...string) map[string]string {
src = m.buildLabels(src...)
mp := make(map[string]string, len(src)/2)
for idx := 0; idx < len(src); idx++ {
mp[src[idx]] = src[idx+1]
idx++
}
return elementMap
return mp
}
func (m *prometheusMeter) metricEqual(src []string, dst []string) bool {
if len(src) != len(dst)/2 {
return false
}
dst = m.buildLabels(dst...)
mp := make(map[string]struct{}, len(src))
for idx := range src {
mp[src[idx]] = struct{}{}
}
for idx := 0; idx < len(dst); idx++ {
if _, ok := mp[dst[idx]]; !ok {
return false
}
idx++
}
return true
}
func (m *prometheusMeter) labelNames(src map[string]string, dst []string) []string {
dst = m.buildLabels(dst...)
nlabels := make([]string, 0, len(src))
for idx := 0; idx < len(dst); idx++ {
if src == nil {
nlabels = append(nlabels, dst[idx])
} else if _, ok := src[dst[idx]]; ok {
nlabels = append(nlabels, dst[idx])
} else {
nlabels = append(nlabels, dst[idx])
}
idx++
}
return nlabels
}
func (m *prometheusMeter) Counter(name string, labels ...string) meter.Counter {
m.Lock()
defer m.Unlock()
nm := m.buildName(name)
c, ok := m.counter[nm]
var lnames []string
if !ok {
nc := prometheus.NewGauge(prometheus.GaugeOpts{Name: nm, ConstLabels: m.mapLabels(labels...)})
m.set.MustRegister(nc)
c = prometheusCounter{c: nc}
lnames = m.labelNames(nil, labels)
fmt.Printf("!ok lnames: %v\n", lnames)
nc := prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: nm}, lnames)
c = prometheusCounter{c: nc, lnames: lnames}
m.counter[nm] = c
} else if !m.metricEqual(c.lnames, labels) {
fmt.Printf("ok && !m.metricEqual lnames: %v labels: %v\n", c.lnames, labels)
lnames = m.labelNames(c.labels, labels)
m.set.Unregister(c.c)
nc := prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: nm}, lnames)
c = prometheusCounter{c: nc, lnames: lnames}
m.counter[nm] = c
m.set.MustRegister(c.c)
} else {
lnames = c.lnames
}
return c
fmt.Printf("lnames %v\n", lnames)
return prometheusCounter{c: c.c, lnames: lnames, labels: m.mapLabels(labels...)}
}
func (m *prometheusMeter) FloatCounter(name string, labels ...string) meter.FloatCounter {
@ -122,13 +167,18 @@ func (m *prometheusMeter) FloatCounter(name string, labels ...string) meter.Floa
nm := m.buildName(name)
c, ok := m.floatCounter[nm]
if !ok {
nc := prometheus.NewGauge(prometheus.GaugeOpts{Name: nm, ConstLabels: m.mapLabels(labels...)})
m.set.MustRegister(nc)
nc := prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: nm}, m.labelNames(c.labels, labels))
c = prometheusFloatCounter{c: nc}
m.floatCounter[nm] = c
} else if !m.metricEqual(c.lnames, labels) {
m.set.Unregister(c.c)
nc := prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: nm}, m.labelNames(c.labels, labels))
c = prometheusFloatCounter{c: nc}
m.floatCounter[nm] = c
m.set.MustRegister(c.c)
}
return c
return prometheusFloatCounter{c: c.c, labels: m.mapLabels(labels...)}
}
func (m *prometheusMeter) Gauge(name string, fn func() float64, labels ...string) meter.Gauge {
@ -138,13 +188,18 @@ func (m *prometheusMeter) Gauge(name string, fn func() float64, labels ...string
nm := m.buildName(name)
c, ok := m.gauge[nm]
if !ok {
nc := prometheus.NewGauge(prometheus.GaugeOpts{Name: nm, ConstLabels: m.mapLabels(labels...)})
m.set.MustRegister(nc)
nc := prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: nm}, m.labelNames(c.labels, labels))
c = prometheusGauge{c: nc}
m.gauge[nm] = c
} else if !m.metricEqual(c.lnames, labels) {
m.set.Unregister(c.c)
nc := prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: nm}, m.labelNames(c.labels, labels))
c = prometheusGauge{c: nc}
m.gauge[nm] = c
m.set.MustRegister(c.c)
}
return c
return prometheusGauge{c: c.c, labels: m.mapLabels(labels...)}
}
func (m *prometheusMeter) Histogram(name string, labels ...string) meter.Histogram {
@ -154,13 +209,18 @@ func (m *prometheusMeter) Histogram(name string, labels ...string) meter.Histogr
nm := m.buildName(name)
c, ok := m.histogram[nm]
if !ok {
nc := prometheus.NewHistogram(prometheus.HistogramOpts{Name: nm, ConstLabels: m.mapLabels(labels...)})
m.set.MustRegister(nc)
nc := prometheus.NewHistogramVec(prometheus.HistogramOpts{Name: nm}, m.labelNames(c.labels, labels))
c = prometheusHistogram{c: nc}
m.histogram[nm] = c
} else if !m.metricEqual(c.lnames, labels) {
m.set.Unregister(c.c)
nc := prometheus.NewHistogramVec(prometheus.HistogramOpts{Name: nm}, m.labelNames(c.labels, labels))
c = prometheusHistogram{c: nc}
m.histogram[nm] = c
m.set.MustRegister(c.c)
}
return c
return prometheusHistogram{c: c.c, labels: m.mapLabels(labels...)}
}
func (m *prometheusMeter) Summary(name string, labels ...string) meter.Summary {
@ -170,13 +230,18 @@ func (m *prometheusMeter) Summary(name string, labels ...string) meter.Summary {
nm := m.buildName(name)
c, ok := m.summary[nm]
if !ok {
nc := prometheus.NewSummary(prometheus.SummaryOpts{Name: nm, ConstLabels: m.mapLabels(labels...)})
m.set.MustRegister(nc)
nc := prometheus.NewSummaryVec(prometheus.SummaryOpts{Name: nm}, m.labelNames(c.labels, labels))
c = prometheusSummary{c: nc}
m.summary[nm] = c
} else if !m.metricEqual(c.lnames, labels) {
m.set.Unregister(c.c)
nc := prometheus.NewSummaryVec(prometheus.SummaryOpts{Name: nm}, m.labelNames(c.labels, labels))
c = prometheusSummary{c: nc}
m.summary[nm] = c
m.set.MustRegister(c.c)
}
return c
return prometheusSummary{c: c.c, labels: m.mapLabels(labels...)}
}
func (m *prometheusMeter) SummaryExt(name string, window time.Duration, quantiles []float64, labels ...string) meter.Summary {
@ -186,18 +251,22 @@ func (m *prometheusMeter) SummaryExt(name string, window time.Duration, quantile
nm := m.buildName(name)
c, ok := m.summary[nm]
if !ok {
nc := prometheus.NewSummary(prometheus.SummaryOpts{
nc := prometheus.NewSummaryVec(prometheus.SummaryOpts{
Name: nm,
ConstLabels: m.mapLabels(labels...),
MaxAge: window,
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
})
m.set.MustRegister(nc)
}, m.labelNames(c.labels, labels))
c = prometheusSummary{c: nc}
m.summary[nm] = c
} else if !m.metricEqual(c.lnames, labels) {
m.set.Unregister(c.c)
nc := prometheus.NewSummaryVec(prometheus.SummaryOpts{Name: nm}, m.labelNames(c.labels, labels))
c = prometheusSummary{c: nc}
m.summary[nm] = c
m.set.MustRegister(c.c)
}
return c
return prometheusSummary{c: c.c, labels: m.mapLabels(labels...)}
}
func (m *prometheusMeter) Init(opts ...meter.Option) error {
@ -275,92 +344,103 @@ func (m *prometheusMeter) Set(opts ...meter.Option) meter.Meter {
}
type prometheusCounter struct {
c prometheus.Gauge
c *prometheus.GaugeVec
lnames []string
labels prometheus.Labels
}
func (c prometheusCounter) Add(n int) {
c.c.Add(float64(n))
nc, _ := c.c.GetMetricWith(c.labels)
nc.Add(float64(n))
}
func (c prometheusCounter) Dec() {
c.c.Dec()
c.c.With(c.labels).Dec()
}
func (c prometheusCounter) Inc() {
c.c.Inc()
c.c.With(c.labels).Inc()
}
func (c prometheusCounter) Get() uint64 {
m := &dto.Metric{}
if err := c.c.Write(m); err != nil {
if err := c.c.With(c.labels).Write(m); err != nil {
return 0
}
return uint64(m.GetGauge().GetValue())
}
func (c prometheusCounter) Set(n uint64) {
c.c.Set(float64(n))
c.c.With(c.labels).Set(float64(n))
}
type prometheusFloatCounter struct {
c prometheus.Gauge
c *prometheus.GaugeVec
lnames []string
labels prometheus.Labels
}
func (c prometheusFloatCounter) Add(n float64) {
c.c.Add(n)
c.c.With(c.labels).Add(n)
}
func (c prometheusFloatCounter) Get() float64 {
m := &dto.Metric{}
if err := c.c.Write(m); err != nil {
if err := c.c.With(c.labels).Write(m); err != nil {
return 0
}
return m.GetGauge().GetValue()
}
func (c prometheusFloatCounter) Set(n float64) {
c.c.Set(n)
c.c.With(c.labels).Set(n)
}
func (c prometheusFloatCounter) Sub(n float64) {
c.c.Add(-n)
c.c.With(c.labels).Add(-n)
}
type prometheusGauge struct {
c prometheus.Gauge
c *prometheus.GaugeVec
lnames []string
labels prometheus.Labels
}
func (c prometheusGauge) Get() float64 {
m := &dto.Metric{}
if err := c.c.Write(m); err != nil {
if err := c.c.With(c.labels).Write(m); err != nil {
return 0
}
return float64(m.GetGauge().GetValue())
}
type prometheusHistogram struct {
c prometheus.Histogram
c *prometheus.HistogramVec
lnames []string
labels prometheus.Labels
}
func (c prometheusHistogram) Reset() {
}
func (c prometheusHistogram) Update(n float64) {
c.c.Observe(n)
c.c.With(c.labels).Observe(n)
}
func (c prometheusHistogram) UpdateDuration(n time.Time) {
c.c.Observe(time.Since(n).Seconds())
c.c.With(c.labels).Observe(time.Since(n).Seconds())
}
type prometheusSummary struct {
c prometheus.Summary
c *prometheus.SummaryVec
lnames []string
labels prometheus.Labels
}
func (c prometheusSummary) Update(n float64) {
c.c.Observe(n)
c.c.With(c.labels).Observe(n)
}
func (c prometheusSummary) UpdateDuration(n time.Time) {
c.c.Observe(time.Since(n).Seconds())
c.c.With(c.labels).Observe(time.Since(n).Seconds())
}

View File

@ -50,3 +50,22 @@ func TestWrapper(t *testing.T) {
t.Fatalf("invalid metrics output: %s", buf.Bytes())
}
}
func TestMultiple(t *testing.T) {
m := NewMeter() // meter.Labels("test_key", "test_val"))
m.Counter("server", "endpoint", "ep1", "path", "/path1").Inc()
m.Counter("server", "endpoint", "ep1", "path", "/path1").Inc()
m.Counter("server", "endpoint", "ep2", "path", "/path2").Inc()
m.Counter("server", "endpoint", "ep2", "path", "/path2").Inc()
m.Counter("server", "endpoint", "ep3", "path", "/path3", "status", "success").Inc()
buf := bytes.NewBuffer(nil)
_ = m.Write(buf, meter.WriteProcessMetrics(false), meter.WriteFDMetrics(false))
if !bytes.Contains(buf.Bytes(), []byte(`micro_server{micro_endpoint="ep1",micro_path="/path1"} 2`)) {
// t.Fatal("XXXX")
t.Fatalf("invalid metrics output: %s", buf.Bytes())
}
}