Merge branch 'master' into sparsehistogram

This commit is contained in:
beorn7 2022-01-11 14:01:38 +01:00
commit 5b19c553c3
13 changed files with 173 additions and 55 deletions

View File

@ -1,7 +1,7 @@
version: 2.1 version: 2.1
orbs: orbs:
go: circleci/go@0.2.0 go: circleci/go@0.2.0
prometheus: prometheus/prometheus@0.11.0 prometheus: prometheus/prometheus@0.15.0
jobs: jobs:
test: test:
parameters: parameters:
@ -63,6 +63,8 @@ workflows:
name: go-1-16 name: go-1-16
go_version: "1.16" go_version: "1.16"
run_lint: true run_lint: true
# Style and unused/missing packages are only checked against - test:
# the latest supported Go version. name: go-1-17
go_version: "1.17"
run_lint: true
run_style_and_unused: true run_style_and_unused: true

31
.github/workflows/golangci-lint.yml vendored Normal file
View File

@ -0,0 +1,31 @@
name: golangci-lint
on:
push:
paths:
- "go.sum"
- "go.mod"
- "**.go"
- "scripts/errcheck_excludes.txt"
- ".github/workflows/golangci-lint.yml"
- ".golangci.yml"
pull_request:
paths:
- "go.sum"
- "go.mod"
- "**.go"
- "scripts/errcheck_excludes.txt"
- ".github/workflows/golangci-lint.yml"
- ".golangci.yml"
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Lint
uses: golangci/golangci-lint-action@v2
with:
version: v1.42.0

View File

@ -78,17 +78,23 @@ ifneq ($(shell which gotestsum),)
endif endif
endif endif
PROMU_VERSION ?= 0.12.0 PROMU_VERSION ?= 0.13.0
PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
GOLANGCI_LINT := GOLANGCI_LINT :=
GOLANGCI_LINT_OPTS ?= GOLANGCI_LINT_OPTS ?=
GOLANGCI_LINT_VERSION ?= v1.39.0 GOLANGCI_LINT_VERSION ?= v1.42.0
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64. # golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
# windows isn't included here because of the path separator being different. # windows isn't included here because of the path separator being different.
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin)) ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386)) ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386))
GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint # If we're in CI and there is an Actions file, that means the linter
# is being run in Actions, so we don't need to run it here.
ifeq (,$(CIRCLE_JOB))
GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint
else ifeq (,$(wildcard .github/workflows/golangci-lint.yml))
GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint
endif
endif endif
endif endif
@ -154,7 +160,7 @@ endif
update-go-deps: update-go-deps:
@echo ">> updating Go dependencies" @echo ">> updating Go dependencies"
@for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ @for m in $$($(GO) list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \
$(GO) get $$m; \ $(GO) get -d $$m; \
done done
GO111MODULE=$(GO111MODULE) $(GO) mod tidy GO111MODULE=$(GO111MODULE) $(GO) mod tidy
ifneq (,$(wildcard vendor)) ifneq (,$(wildcard vendor))

View File

@ -139,6 +139,7 @@ const (
epBuildinfo = apiPrefix + "/status/buildinfo" epBuildinfo = apiPrefix + "/status/buildinfo"
epRuntimeinfo = apiPrefix + "/status/runtimeinfo" epRuntimeinfo = apiPrefix + "/status/runtimeinfo"
epTSDB = apiPrefix + "/status/tsdb" epTSDB = apiPrefix + "/status/tsdb"
epWalReplay = apiPrefix + "/status/walreplay"
) )
// AlertState models the state of an alert. // AlertState models the state of an alert.
@ -261,6 +262,8 @@ type API interface {
Metadata(ctx context.Context, metric string, limit string) (map[string][]Metadata, error) Metadata(ctx context.Context, metric string, limit string) (map[string][]Metadata, error)
// TSDB returns the cardinality statistics. // TSDB returns the cardinality statistics.
TSDB(ctx context.Context) (TSDBResult, error) TSDB(ctx context.Context) (TSDBResult, error)
// WalReplay returns the current replay status of the wal.
WalReplay(ctx context.Context) (WalReplayStatus, error)
} }
// AlertsResult contains the result from querying the alerts endpoint. // AlertsResult contains the result from querying the alerts endpoint.
@ -303,8 +306,6 @@ type RuntimeinfoResult struct {
CWD string `json:"CWD"` CWD string `json:"CWD"`
ReloadConfigSuccess bool `json:"reloadConfigSuccess"` ReloadConfigSuccess bool `json:"reloadConfigSuccess"`
LastConfigTime time.Time `json:"lastConfigTime"` LastConfigTime time.Time `json:"lastConfigTime"`
ChunkCount int `json:"chunkCount"`
TimeSeriesCount int `json:"timeSeriesCount"`
CorruptionCount int `json:"corruptionCount"` CorruptionCount int `json:"corruptionCount"`
GoroutineCount int `json:"goroutineCount"` GoroutineCount int `json:"goroutineCount"`
GOMAXPROCS int `json:"GOMAXPROCS"` GOMAXPROCS int `json:"GOMAXPROCS"`
@ -431,10 +432,27 @@ type queryResult struct {
// TSDBResult contains the result from querying the tsdb endpoint. // TSDBResult contains the result from querying the tsdb endpoint.
type TSDBResult struct { type TSDBResult struct {
SeriesCountByMetricName []Stat `json:"seriesCountByMetricName"` HeadStats TSDBHeadStats `json:"headStats"`
LabelValueCountByLabelName []Stat `json:"labelValueCountByLabelName"` SeriesCountByMetricName []Stat `json:"seriesCountByMetricName"`
MemoryInBytesByLabelName []Stat `json:"memoryInBytesByLabelName"` LabelValueCountByLabelName []Stat `json:"labelValueCountByLabelName"`
SeriesCountByLabelValuePair []Stat `json:"seriesCountByLabelValuePair"` MemoryInBytesByLabelName []Stat `json:"memoryInBytesByLabelName"`
SeriesCountByLabelValuePair []Stat `json:"seriesCountByLabelValuePair"`
}
// TSDBHeadStats contains TSDB stats
type TSDBHeadStats struct {
NumSeries int `json:"numSeries"`
NumLabelPairs int `json:"numLabelPairs"`
ChunkCount int `json:"chunkCount"`
MinTime int `json:"minTime"`
MaxTime int `json:"maxTime"`
}
// WalReplayStatus represents the wal replay status.
type WalReplayStatus struct {
Min int `json:"min"`
Max int `json:"max"`
Current int `json:"current"`
} }
// Stat models information about statistic value. // Stat models information about statistic value.
@ -984,6 +1002,23 @@ func (h *httpAPI) TSDB(ctx context.Context) (TSDBResult, error) {
return res, json.Unmarshal(body, &res) return res, json.Unmarshal(body, &res)
} }
func (h *httpAPI) WalReplay(ctx context.Context) (WalReplayStatus, error) {
u := h.client.URL(epWalReplay, nil)
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
if err != nil {
return WalReplayStatus{}, err
}
_, body, _, err := h.client.Do(ctx, req)
if err != nil {
return WalReplayStatus{}, err
}
var res WalReplayStatus
return res, json.Unmarshal(body, &res)
}
func (h *httpAPI) QueryExemplars(ctx context.Context, query string, startTime time.Time, endTime time.Time) ([]ExemplarQueryResult, error) { func (h *httpAPI) QueryExemplars(ctx context.Context, query string, startTime time.Time, endTime time.Time) ([]ExemplarQueryResult, error) {
u := h.client.URL(epQueryExemplars, nil) u := h.client.URL(epQueryExemplars, nil)
q := u.Query() q := u.Query()

View File

@ -230,6 +230,13 @@ func TestAPIs(t *testing.T) {
} }
} }
doWalReply := func() func() (interface{}, Warnings, error) {
return func() (interface{}, Warnings, error) {
v, err := promAPI.WalReplay(context.Background())
return v, nil, err
}
}
doQueryExemplars := func(query string, startTime time.Time, endTime time.Time) func() (interface{}, Warnings, error) { doQueryExemplars := func(query string, startTime time.Time, endTime time.Time) func() (interface{}, Warnings, error) {
return func() (interface{}, Warnings, error) { return func() (interface{}, Warnings, error) {
v, err := promAPI.QueryExemplars(context.Background(), query, startTime, endTime) v, err := promAPI.QueryExemplars(context.Background(), query, startTime, endTime)
@ -696,8 +703,6 @@ func TestAPIs(t *testing.T) {
"CWD": "/prometheus", "CWD": "/prometheus",
"reloadConfigSuccess": true, "reloadConfigSuccess": true,
"lastConfigTime": "2020-05-18T15:52:56Z", "lastConfigTime": "2020-05-18T15:52:56Z",
"chunkCount": 72692,
"timeSeriesCount": 18476,
"corruptionCount": 0, "corruptionCount": 0,
"goroutineCount": 217, "goroutineCount": 217,
"GOMAXPROCS": 2, "GOMAXPROCS": 2,
@ -710,8 +715,6 @@ func TestAPIs(t *testing.T) {
CWD: "/prometheus", CWD: "/prometheus",
ReloadConfigSuccess: true, ReloadConfigSuccess: true,
LastConfigTime: time.Date(2020, 5, 18, 15, 52, 56, 0, time.UTC), LastConfigTime: time.Date(2020, 5, 18, 15, 52, 56, 0, time.UTC),
ChunkCount: 72692,
TimeSeriesCount: 18476,
CorruptionCount: 0, CorruptionCount: 0,
GoroutineCount: 217, GoroutineCount: 217,
GOMAXPROCS: 2, GOMAXPROCS: 2,
@ -1145,6 +1148,13 @@ func TestAPIs(t *testing.T) {
reqMethod: "GET", reqMethod: "GET",
reqPath: "/api/v1/status/tsdb", reqPath: "/api/v1/status/tsdb",
inRes: map[string]interface{}{ inRes: map[string]interface{}{
"headStats": map[string]interface{}{
"numSeries": 18476,
"numLabelPairs": 4301,
"chunkCount": 72692,
"minTime": 1634644800304,
"maxTime": 1634650590304,
},
"seriesCountByMetricName": []interface{}{ "seriesCountByMetricName": []interface{}{
map[string]interface{}{ map[string]interface{}{
"name": "kubelet_http_requests_duration_seconds_bucket", "name": "kubelet_http_requests_duration_seconds_bucket",
@ -1171,6 +1181,13 @@ func TestAPIs(t *testing.T) {
}, },
}, },
res: TSDBResult{ res: TSDBResult{
HeadStats: TSDBHeadStats{
NumSeries: 18476,
NumLabelPairs: 4301,
ChunkCount: 72692,
MinTime: 1634644800304,
MaxTime: 1634650590304,
},
SeriesCountByMetricName: []Stat{ SeriesCountByMetricName: []Stat{
{ {
Name: "kubelet_http_requests_duration_seconds_bucket", Name: "kubelet_http_requests_duration_seconds_bucket",
@ -1198,6 +1215,30 @@ func TestAPIs(t *testing.T) {
}, },
}, },
{
do: doWalReply(),
reqMethod: "GET",
reqPath: "/api/v1/status/walreplay",
inErr: fmt.Errorf("some error"),
err: fmt.Errorf("some error"),
},
{
do: doWalReply(),
reqMethod: "GET",
reqPath: "/api/v1/status/walreplay",
inRes: map[string]interface{}{
"min": 2,
"max": 5,
"current": 40,
},
res: WalReplayStatus{
Min: 2,
Max: 5,
Current: 40,
},
},
{ {
do: doQueryExemplars("tns_request_duration_seconds_bucket", testTime.Add(-1*time.Minute), testTime), do: doQueryExemplars("tns_request_duration_seconds_bucket", testTime.Add(-1*time.Minute), testTime),
reqMethod: "GET", reqMethod: "GET",

View File

@ -29,48 +29,46 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
) )
var ( func main() {
addr = flag.String("listen-address", ":8080", "The address to listen on for HTTP requests.") var (
uniformDomain = flag.Float64("uniform.domain", 0.0002, "The domain for the uniform distribution.") addr = flag.String("listen-address", ":8080", "The address to listen on for HTTP requests.")
normDomain = flag.Float64("normal.domain", 0.0002, "The domain for the normal distribution.") uniformDomain = flag.Float64("uniform.domain", 0.0002, "The domain for the uniform distribution.")
normMean = flag.Float64("normal.mean", 0.00001, "The mean for the normal distribution.") normDomain = flag.Float64("normal.domain", 0.0002, "The domain for the normal distribution.")
oscillationPeriod = flag.Duration("oscillation-period", 10*time.Minute, "The duration of the rate oscillation period.") normMean = flag.Float64("normal.mean", 0.00001, "The mean for the normal distribution.")
) oscillationPeriod = flag.Duration("oscillation-period", 10*time.Minute, "The duration of the rate oscillation period.")
)
var (
// Create a summary to track fictional interservice RPC latencies for three flag.Parse()
// distinct services with different latency distributions. These services are
// differentiated via a "service" label. var (
rpcDurations = prometheus.NewSummaryVec( // Create a summary to track fictional interservice RPC latencies for three
prometheus.SummaryOpts{ // distinct services with different latency distributions. These services are
Name: "rpc_durations_seconds", // differentiated via a "service" label.
Help: "RPC latency distributions.", rpcDurations = prometheus.NewSummaryVec(
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, prometheus.SummaryOpts{
}, Name: "rpc_durations_seconds",
[]string{"service"}, Help: "RPC latency distributions.",
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
},
[]string{"service"},
)
// The same as above, but now as a histogram, and only for the normal
// distribution. The buckets are targeted to the parameters of the
// normal distribution, with 20 buckets centered on the mean, each
// half-sigma wide.
rpcDurationsHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
Name: "rpc_durations_histogram_seconds",
Help: "RPC latency distributions.",
Buckets: prometheus.LinearBuckets(*normMean-5**normDomain, .5**normDomain, 20),
SparseBucketsFactor: 1.1,
})
) )
// The same as above, but now as a histogram, and only for the normal
// distribution. The buckets are targeted to the parameters of the
// normal distribution, with 20 buckets centered on the mean, each
// half-sigma wide.
rpcDurationsHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
Name: "rpc_durations_histogram_seconds",
Help: "RPC latency distributions.",
Buckets: prometheus.LinearBuckets(*normMean-5**normDomain, .5**normDomain, 20),
SparseBucketsFactor: 1.1,
})
)
func init() {
// Register the summary and the histogram with Prometheus's default registry. // Register the summary and the histogram with Prometheus's default registry.
prometheus.MustRegister(rpcDurations) prometheus.MustRegister(rpcDurations)
prometheus.MustRegister(rpcDurationsHistogram) prometheus.MustRegister(rpcDurationsHistogram)
// Add Go module build info. // Add Go module build info.
prometheus.MustRegister(prometheus.NewBuildInfoCollector()) prometheus.MustRegister(prometheus.NewBuildInfoCollector())
}
func main() {
flag.Parse()
start := time.Now() start := time.Now()

2
go.mod
View File

@ -2,7 +2,7 @@ module github.com/prometheus/client_golang
require ( require (
github.com/beorn7/perks v1.0.1 github.com/beorn7/perks v1.0.1
github.com/cespare/xxhash/v2 v2.1.1 github.com/cespare/xxhash/v2 v2.1.2
github.com/golang/protobuf v1.4.3 github.com/golang/protobuf v1.4.3
github.com/json-iterator/go v1.1.11 github.com/json-iterator/go v1.1.11
github.com/prometheus/client_model v0.2.1-0.20210624201024-61b6c1aac064 github.com/prometheus/client_model v0.2.1-0.20210624201024-61b6c1aac064

3
go.sum
View File

@ -43,8 +43,9 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=

View File

@ -11,6 +11,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build go1.15
// +build go1.15 // +build go1.15
package collectors package collectors

View File

@ -11,6 +11,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build !go1.15
// +build !go1.15 // +build !go1.15
package collectors package collectors

View File

@ -11,6 +11,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build !windows
// +build !windows // +build !windows
package prometheus package prometheus

View File

@ -11,6 +11,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build linux
// +build linux // +build linux
package prometheus package prometheus

View File

@ -199,7 +199,7 @@ func TestPush(t *testing.T) {
Collector(metric1). Collector(metric1).
Collector(metric2). Collector(metric2).
Push(); err == nil { Push(); err == nil {
t.Error("push with empty job succeded") t.Error("push with empty job succeeded")
} else { } else {
if got, want := err, errJobEmpty; got != want { if got, want := err, errJobEmpty; got != want {
t.Errorf("got error %q, want %q", got, want) t.Errorf("got error %q, want %q", got, want)