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

View File

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

View File

@ -3,6 +3,7 @@ on:
pull_request: pull_request:
branches: branches:
- master - master
- v3
jobs: jobs:
test: test:
name: test name: test
@ -13,7 +14,7 @@ jobs:
with: with:
go-version: 1.16 go-version: 1.16
- name: checkout - name: checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: cache - name: cache
uses: actions/cache@v2 uses: actions/cache@v2
with: with:
@ -31,9 +32,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: lint - name: lint
uses: golangci/golangci-lint-action@v3 uses: golangci/golangci-lint-action@v3.1.0
continue-on-error: true continue-on-error: true
with: with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. # 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 return m.opts.Name
} }
func (m *prometheusMeter) mapLabels(labels ...string) map[string]string { func (m *prometheusMeter) mapLabels(src ...string) map[string]string {
labels = m.buildLabels(labels...) src = m.buildLabels(src...)
elementMap := make(map[string]string, len(labels)/2) mp := make(map[string]string, len(src)/2)
for idx := 0; idx < len(labels); idx++ { for idx := 0; idx < len(src); idx++ {
elementMap[labels[idx]] = labels[idx+1] mp[src[idx]] = src[idx+1]
idx++ 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 { func (m *prometheusMeter) Counter(name string, labels ...string) meter.Counter {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
nm := m.buildName(name) nm := m.buildName(name)
c, ok := m.counter[nm] c, ok := m.counter[nm]
var lnames []string
if !ok { if !ok {
nc := prometheus.NewGauge(prometheus.GaugeOpts{Name: nm, ConstLabels: m.mapLabels(labels...)}) lnames = m.labelNames(nil, labels)
m.set.MustRegister(nc) fmt.Printf("!ok lnames: %v\n", lnames)
c = prometheusCounter{c: nc} nc := prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: nm}, lnames)
c = prometheusCounter{c: nc, lnames: lnames}
m.counter[nm] = c 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
} }
fmt.Printf("lnames %v\n", lnames)
return c return prometheusCounter{c: c.c, lnames: lnames, labels: m.mapLabels(labels...)}
} }
func (m *prometheusMeter) FloatCounter(name string, labels ...string) meter.FloatCounter { 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) nm := m.buildName(name)
c, ok := m.floatCounter[nm] c, ok := m.floatCounter[nm]
if !ok { if !ok {
nc := prometheus.NewGauge(prometheus.GaugeOpts{Name: nm, ConstLabels: m.mapLabels(labels...)}) nc := prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: nm}, m.labelNames(c.labels, labels))
m.set.MustRegister(nc)
c = prometheusFloatCounter{c: nc} c = prometheusFloatCounter{c: nc}
m.floatCounter[nm] = c 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 { 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) nm := m.buildName(name)
c, ok := m.gauge[nm] c, ok := m.gauge[nm]
if !ok { if !ok {
nc := prometheus.NewGauge(prometheus.GaugeOpts{Name: nm, ConstLabels: m.mapLabels(labels...)}) nc := prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: nm}, m.labelNames(c.labels, labels))
m.set.MustRegister(nc)
c = prometheusGauge{c: nc} c = prometheusGauge{c: nc}
m.gauge[nm] = c 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 { 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) nm := m.buildName(name)
c, ok := m.histogram[nm] c, ok := m.histogram[nm]
if !ok { if !ok {
nc := prometheus.NewHistogram(prometheus.HistogramOpts{Name: nm, ConstLabels: m.mapLabels(labels...)}) nc := prometheus.NewHistogramVec(prometheus.HistogramOpts{Name: nm}, m.labelNames(c.labels, labels))
m.set.MustRegister(nc)
c = prometheusHistogram{c: nc} c = prometheusHistogram{c: nc}
m.histogram[nm] = c 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 { 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) nm := m.buildName(name)
c, ok := m.summary[nm] c, ok := m.summary[nm]
if !ok { if !ok {
nc := prometheus.NewSummary(prometheus.SummaryOpts{Name: nm, ConstLabels: m.mapLabels(labels...)}) nc := prometheus.NewSummaryVec(prometheus.SummaryOpts{Name: nm}, m.labelNames(c.labels, labels))
m.set.MustRegister(nc)
c = prometheusSummary{c: nc} c = prometheusSummary{c: nc}
m.summary[nm] = c 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 { 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) nm := m.buildName(name)
c, ok := m.summary[nm] c, ok := m.summary[nm]
if !ok { if !ok {
nc := prometheus.NewSummary(prometheus.SummaryOpts{ nc := prometheus.NewSummaryVec(prometheus.SummaryOpts{
Name: nm, Name: nm,
ConstLabels: m.mapLabels(labels...), MaxAge: window,
MaxAge: window, Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, }, m.labelNames(c.labels, labels))
})
m.set.MustRegister(nc)
c = prometheusSummary{c: nc} c = prometheusSummary{c: nc}
m.summary[nm] = c 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 { func (m *prometheusMeter) Init(opts ...meter.Option) error {
@ -275,92 +344,103 @@ func (m *prometheusMeter) Set(opts ...meter.Option) meter.Meter {
} }
type prometheusCounter struct { type prometheusCounter struct {
c prometheus.Gauge c *prometheus.GaugeVec
lnames []string
labels prometheus.Labels
} }
func (c prometheusCounter) Add(n int) { 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() { func (c prometheusCounter) Dec() {
c.c.Dec() c.c.With(c.labels).Dec()
} }
func (c prometheusCounter) Inc() { func (c prometheusCounter) Inc() {
c.c.Inc() c.c.With(c.labels).Inc()
} }
func (c prometheusCounter) Get() uint64 { func (c prometheusCounter) Get() uint64 {
m := &dto.Metric{} 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 0
} }
return uint64(m.GetGauge().GetValue()) return uint64(m.GetGauge().GetValue())
} }
func (c prometheusCounter) Set(n uint64) { func (c prometheusCounter) Set(n uint64) {
c.c.Set(float64(n)) c.c.With(c.labels).Set(float64(n))
} }
type prometheusFloatCounter struct { type prometheusFloatCounter struct {
c prometheus.Gauge c *prometheus.GaugeVec
lnames []string
labels prometheus.Labels
} }
func (c prometheusFloatCounter) Add(n float64) { func (c prometheusFloatCounter) Add(n float64) {
c.c.Add(n) c.c.With(c.labels).Add(n)
} }
func (c prometheusFloatCounter) Get() float64 { func (c prometheusFloatCounter) Get() float64 {
m := &dto.Metric{} 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 0
} }
return m.GetGauge().GetValue() return m.GetGauge().GetValue()
} }
func (c prometheusFloatCounter) Set(n float64) { func (c prometheusFloatCounter) Set(n float64) {
c.c.Set(n) c.c.With(c.labels).Set(n)
} }
func (c prometheusFloatCounter) Sub(n float64) { func (c prometheusFloatCounter) Sub(n float64) {
c.c.Add(-n) c.c.With(c.labels).Add(-n)
} }
type prometheusGauge struct { type prometheusGauge struct {
c prometheus.Gauge c *prometheus.GaugeVec
lnames []string
labels prometheus.Labels
} }
func (c prometheusGauge) Get() float64 { func (c prometheusGauge) Get() float64 {
m := &dto.Metric{} 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 0
} }
return float64(m.GetGauge().GetValue()) return float64(m.GetGauge().GetValue())
} }
type prometheusHistogram struct { type prometheusHistogram struct {
c prometheus.Histogram c *prometheus.HistogramVec
lnames []string
labels prometheus.Labels
} }
func (c prometheusHistogram) Reset() { func (c prometheusHistogram) Reset() {
} }
func (c prometheusHistogram) Update(n float64) { func (c prometheusHistogram) Update(n float64) {
c.c.Observe(n) c.c.With(c.labels).Observe(n)
} }
func (c prometheusHistogram) UpdateDuration(n time.Time) { 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 { type prometheusSummary struct {
c prometheus.Summary c *prometheus.SummaryVec
lnames []string
labels prometheus.Labels
} }
func (c prometheusSummary) Update(n float64) { func (c prometheusSummary) Update(n float64) {
c.c.Observe(n) c.c.With(c.labels).Observe(n)
} }
func (c prometheusSummary) UpdateDuration(n time.Time) { 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()) 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())
}
}