micro/meter/meter.go
Evstigneev Denis 38c5fe8b5a
All checks were successful
test / test (push) Successful in 42s
fixed struct alignment && refactor linter (#369)
## Pull Request template
Please, go through these steps before clicking submit on this PR.

1. Give a descriptive title to your PR.
2. Provide a description of your changes.
3. Make sure you have some relevant tests.
4. Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes (if applicable).

**PLEASE REMOVE THIS TEMPLATE BEFORE SUBMITTING**

Reviewed-on: #369
Co-authored-by: Evstigneev Denis <danteevstigneev@yandex.ru>
Co-committed-by: Evstigneev Denis <danteevstigneev@yandex.ru>
2024-12-09 16:23:25 +03:00

159 lines
4.0 KiB
Go

// Package meter is for instrumentation
package meter
import (
"io"
"sort"
"strconv"
"strings"
"time"
)
var (
// DefaultMeter is the default meter
DefaultMeter = NewMeter()
// DefaultAddress data will be made available on this host:port
DefaultAddress = ":9090"
// DefaultPath the meter endpoint where the Meter data will be made available
DefaultPath = "/metrics"
// DefaultMeterStatsInterval specifies interval for meter updating
DefaultMeterStatsInterval = 5 * time.Second
// DefaultSummaryQuantiles is the default spread of stats for summary
DefaultSummaryQuantiles = []float64{0.5, 0.9, 0.97, 0.99, 1}
// DefaultSummaryWindow is the default window for summary
DefaultSummaryWindow = 5 * time.Minute
// DefaultSkipEndpoints is the slice of endpoint that must not be metered
DefaultSkipEndpoints = []string{
"MeterService.Metrics",
"HealthService.Live",
"HealthService.Ready",
"HealthService.Version",
}
)
// Meter is an interface for collecting and instrumenting metrics
type Meter interface {
// Name returns meter name
Name() string
// Init initialize meter
Init(opts ...Option) error
// Clone create meter copy with new options
Clone(opts ...Option) Meter
// Counter get or create counter
Counter(name string, labels ...string) Counter
// FloatCounter get or create float counter
FloatCounter(name string, labels ...string) FloatCounter
// Gauge get or create gauge
Gauge(name string, fn func() float64, labels ...string) Gauge
// Set create new meter metrics set
Set(opts ...Option) Meter
// Histogram get or create histogram
Histogram(name string, labels ...string) Histogram
// Summary get or create summary
Summary(name string, labels ...string) Summary
// SummaryExt get or create summary with spcified quantiles and window time
SummaryExt(name string, window time.Duration, quantiles []float64, labels ...string) Summary
// Write writes metrics to io.Writer
Write(w io.Writer, opts ...Option) error
// Options returns meter options
Options() Options
// String return meter type
String() string
}
// Counter is a counter
type Counter interface {
Add(int)
Dec()
Get() uint64
Inc()
Set(uint64)
}
// FloatCounter is a float64 counter
type FloatCounter interface {
Add(float64)
Get() float64
Set(float64)
Sub(float64)
}
// Gauge is a float64 gauge
type Gauge interface {
Get() float64
}
// Histogram is a histogram for non-negative values with automatically created buckets
type Histogram interface {
Reset()
Update(float64)
UpdateDuration(time.Time)
// VisitNonZeroBuckets(f func(vmrange string, count uint64))
}
// Summary is the summary
type Summary interface {
Update(float64)
UpdateDuration(time.Time)
}
// sort labels alphabeticaly by label name
type byKey []string
func (k byKey) Len() int { return len(k) / 2 }
func (k byKey) Less(i, j int) bool { return k[i*2] < k[j*2] }
func (k byKey) Swap(i, j int) {
k[i*2], k[j*2] = k[j*2], k[i*2]
k[i*2+1], k[j*2+1] = k[j*2+1], k[i*2+1]
}
// BuildLabels used to sort labels and delete duplicates.
// Last value wins in case of duplicate label keys.
func BuildLabels(labels ...string) []string {
if len(labels)%2 == 1 {
labels = labels[:len(labels)-1]
}
sort.Sort(byKey(labels))
return labels
}
// BuildName used to combine metric with labels.
// If labels count is odd, drop last element
func BuildName(name string, labels ...string) string {
if len(labels)%2 == 1 {
labels = labels[:len(labels)-1]
}
if len(labels) > 2 {
sort.Sort(byKey(labels))
idx := 0
for {
if labels[idx] == labels[idx+2] {
copy(labels[idx:], labels[idx+2:])
labels = labels[:len(labels)-2]
} else {
idx += 2
}
if idx+2 >= len(labels) {
break
}
}
}
var b strings.Builder
_, _ = b.WriteString(name)
_, _ = b.WriteRune('{')
for idx := 0; idx < len(labels); idx += 2 {
if idx > 0 {
_, _ = b.WriteRune(',')
}
_, _ = b.WriteString(labels[idx])
_, _ = b.WriteString(`=`)
_, _ = b.WriteString(strconv.Quote(labels[idx+1]))
}
_, _ = b.WriteRune('}')
return b.String()
}