From 5d50b02888b0e0dfbbfdfb4e33c20a7c6e6f37c0 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Sat, 5 Mar 2022 19:09:31 +0300 Subject: [PATCH] update workflows Signed-off-by: Vasiliy Tolstov --- .github/workflows/autoapprove.yml | 20 +++ .github/workflows/automerge.yml | 21 +++ .github/workflows/build.yml | 7 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/dependabot-automerge.yml | 14 +- .github/workflows/pr.yml | 7 +- prometheus.go | 182 +++++++++++++++------ prometheus_test.go | 19 +++ 8 files changed, 205 insertions(+), 67 deletions(-) create mode 100644 .github/workflows/autoapprove.yml create mode 100644 .github/workflows/automerge.yml diff --git a/.github/workflows/autoapprove.yml b/.github/workflows/autoapprove.yml new file mode 100644 index 0000000..ebe28c9 --- /dev/null +++ b/.github/workflows/autoapprove.yml @@ -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 }} \ No newline at end of file diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml new file mode 100644 index 0000000..5ff3f69 --- /dev/null +++ b/.github/workflows/automerge.yml @@ -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}} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4182c04..d8002e9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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. diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b50aad2..9b4d428 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -43,7 +43,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: setup uses: actions/setup-go@v2 with: diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index 26cf8ca..3681028 100644 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -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: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index f807f24..ff10c46 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -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. diff --git a/prometheus.go b/prometheus.go index 1354a66..3d1f187 100644 --- a/prometheus.go +++ b/prometheus.go @@ -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{ - 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) + nc := prometheus.NewSummaryVec(prometheus.SummaryOpts{ + Name: nm, + MaxAge: window, + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }, 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()) } diff --git a/prometheus_test.go b/prometheus_test.go index bed8c30..c153027 100644 --- a/prometheus_test.go +++ b/prometheus_test.go @@ -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()) + } +}