Upgrading server dependancies (#6431)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
cd23b8139a
Коммит
d103ed6ca9
7
vendor/github.com/prometheus/client_golang/.travis.yml
сгенерированный
поставляемый
7
vendor/github.com/prometheus/client_golang/.travis.yml
сгенерированный
поставляемый
@@ -2,8 +2,9 @@ sudo: false
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.5.4
|
||||
- 1.6.2
|
||||
- 1.6.3
|
||||
- 1.7
|
||||
- 1.8.1
|
||||
|
||||
script:
|
||||
- go test -short ./...
|
||||
- go test -short ./...
|
||||
|
||||
18
vendor/github.com/prometheus/client_golang/AUTHORS.md
сгенерированный
поставляемый
18
vendor/github.com/prometheus/client_golang/AUTHORS.md
сгенерированный
поставляемый
@@ -1,18 +0,0 @@
|
||||
The Prometheus project was started by Matt T. Proud (emeritus) and
|
||||
Julius Volz in 2012.
|
||||
|
||||
Maintainers of this repository:
|
||||
|
||||
* Björn Rabenstein <beorn@soundcloud.com>
|
||||
|
||||
The following individuals have contributed code to this repository
|
||||
(listed in alphabetical order):
|
||||
|
||||
* Bernerd Schaefer <bj.schaefer@gmail.com>
|
||||
* Björn Rabenstein <beorn@soundcloud.com>
|
||||
* Daniel Bornkessel <daniel@soundcloud.com>
|
||||
* Jeff Younker <jeff@drinktomi.com>
|
||||
* Julius Volz <julius.volz@gmail.com>
|
||||
* Matt T. Proud <matt.proud@gmail.com>
|
||||
* Tobias Schmidt <ts@soundcloud.com>
|
||||
|
||||
6
vendor/github.com/prometheus/client_golang/CONTRIBUTING.md
сгенерированный
поставляемый
6
vendor/github.com/prometheus/client_golang/CONTRIBUTING.md
сгенерированный
поставляемый
@@ -2,9 +2,9 @@
|
||||
|
||||
Prometheus uses GitHub to manage reviews of pull requests.
|
||||
|
||||
* If you have a trivial fix or improvement, go ahead and create a pull
|
||||
request, addressing (with `@...`) one or more of the maintainers
|
||||
(see [AUTHORS.md](AUTHORS.md)) in the description of the pull request.
|
||||
* If you have a trivial fix or improvement, go ahead and create a pull request,
|
||||
addressing (with `@...`) the maintainer of this repository (see
|
||||
[MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request.
|
||||
|
||||
* If you plan to do something more involved, first discuss your ideas
|
||||
on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers).
|
||||
|
||||
1
vendor/github.com/prometheus/client_golang/MAINTAINERS.md
сгенерированный
поставляемый
Обычный файл
1
vendor/github.com/prometheus/client_golang/MAINTAINERS.md
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
||||
* Björn Rabenstein <beorn@soundcloud.com>
|
||||
4
vendor/github.com/prometheus/client_golang/README.md
сгенерированный
поставляемый
4
vendor/github.com/prometheus/client_golang/README.md
сгенерированный
поставляемый
@@ -1,6 +1,7 @@
|
||||
# Prometheus Go client library
|
||||
|
||||
[](https://travis-ci.org/prometheus/client_golang)
|
||||
[](https://goreportcard.com/report/github.com/prometheus/client_golang)
|
||||
|
||||
This is the [Go](http://golang.org) client library for
|
||||
[Prometheus](http://prometheus.io). It has two separate parts, one for
|
||||
@@ -29,7 +30,8 @@ The
|
||||
[`api/prometheus` directory](https://github.com/prometheus/client_golang/tree/master/api/prometheus)
|
||||
contains the client for the
|
||||
[Prometheus HTTP API](http://prometheus.io/docs/querying/api/). It allows you
|
||||
to write Go applications that query time series data from a Prometheus server.
|
||||
to write Go applications that query time series data from a Prometheus
|
||||
server. It is still in alpha stage.
|
||||
|
||||
## Where is `model`, `extraction`, and `text`?
|
||||
|
||||
|
||||
131
vendor/github.com/prometheus/client_golang/api/client.go
сгенерированный
поставляемый
Обычный файл
131
vendor/github.com/prometheus/client_golang/api/client.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,131 @@
|
||||
// Copyright 2015 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build go1.7
|
||||
|
||||
// Package api provides clients for the HTTP APIs.
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DefaultRoundTripper is used if no RoundTripper is set in Config.
|
||||
var DefaultRoundTripper http.RoundTripper = &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
// Config defines configuration parameters for a new client.
|
||||
type Config struct {
|
||||
// The address of the Prometheus to connect to.
|
||||
Address string
|
||||
|
||||
// RoundTripper is used by the Client to drive HTTP requests. If not
|
||||
// provided, DefaultRoundTripper will be used.
|
||||
RoundTripper http.RoundTripper
|
||||
}
|
||||
|
||||
func (cfg *Config) roundTripper() http.RoundTripper {
|
||||
if cfg.RoundTripper == nil {
|
||||
return DefaultRoundTripper
|
||||
}
|
||||
return cfg.RoundTripper
|
||||
}
|
||||
|
||||
// Client is the interface for an API client.
|
||||
type Client interface {
|
||||
URL(ep string, args map[string]string) *url.URL
|
||||
Do(context.Context, *http.Request) (*http.Response, []byte, error)
|
||||
}
|
||||
|
||||
// NewClient returns a new Client.
|
||||
//
|
||||
// It is safe to use the returned Client from multiple goroutines.
|
||||
func NewClient(cfg Config) (Client, error) {
|
||||
u, err := url.Parse(cfg.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.Path = strings.TrimRight(u.Path, "/")
|
||||
|
||||
return &httpClient{
|
||||
endpoint: u,
|
||||
client: http.Client{Transport: cfg.roundTripper()},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type httpClient struct {
|
||||
endpoint *url.URL
|
||||
client http.Client
|
||||
}
|
||||
|
||||
func (c *httpClient) URL(ep string, args map[string]string) *url.URL {
|
||||
p := path.Join(c.endpoint.Path, ep)
|
||||
|
||||
for arg, val := range args {
|
||||
arg = ":" + arg
|
||||
p = strings.Replace(p, arg, val, -1)
|
||||
}
|
||||
|
||||
u := *c.endpoint
|
||||
u.Path = p
|
||||
|
||||
return &u
|
||||
}
|
||||
|
||||
func (c *httpClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
if ctx != nil {
|
||||
req = req.WithContext(ctx)
|
||||
}
|
||||
resp, err := c.client.Do(req)
|
||||
defer func() {
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var body []byte
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
close(done)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
err = resp.Body.Close()
|
||||
<-done
|
||||
if err == nil {
|
||||
err = ctx.Err()
|
||||
}
|
||||
case <-done:
|
||||
}
|
||||
|
||||
return resp, body, err
|
||||
}
|
||||
115
vendor/github.com/prometheus/client_golang/api/client_test.go
сгенерированный
поставляемый
Обычный файл
115
vendor/github.com/prometheus/client_golang/api/client_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,115 @@
|
||||
// Copyright 2015 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build go1.7
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
c := Config{}
|
||||
if c.roundTripper() != DefaultRoundTripper {
|
||||
t.Fatalf("expected default roundtripper for nil RoundTripper field")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
address string
|
||||
endpoint string
|
||||
args map[string]string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "/test",
|
||||
expected: "http://localhost:9090/test",
|
||||
},
|
||||
{
|
||||
address: "http://localhost",
|
||||
endpoint: "/test",
|
||||
expected: "http://localhost/test",
|
||||
},
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "test",
|
||||
expected: "http://localhost:9090/test",
|
||||
},
|
||||
{
|
||||
address: "http://localhost:9090/prefix",
|
||||
endpoint: "/test",
|
||||
expected: "http://localhost:9090/prefix/test",
|
||||
},
|
||||
{
|
||||
address: "https://localhost:9090/",
|
||||
endpoint: "/test/",
|
||||
expected: "https://localhost:9090/test",
|
||||
},
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "/test/:param",
|
||||
args: map[string]string{
|
||||
"param": "content",
|
||||
},
|
||||
expected: "http://localhost:9090/test/content",
|
||||
},
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "/test/:param/more/:param",
|
||||
args: map[string]string{
|
||||
"param": "content",
|
||||
},
|
||||
expected: "http://localhost:9090/test/content/more/content",
|
||||
},
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "/test/:param/more/:foo",
|
||||
args: map[string]string{
|
||||
"param": "content",
|
||||
"foo": "bar",
|
||||
},
|
||||
expected: "http://localhost:9090/test/content/more/bar",
|
||||
},
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "/test/:param",
|
||||
args: map[string]string{
|
||||
"nonexistant": "content",
|
||||
},
|
||||
expected: "http://localhost:9090/test/:param",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
ep, err := url.Parse(test.address)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hclient := &httpClient{
|
||||
endpoint: ep,
|
||||
client: http.Client{Transport: DefaultRoundTripper},
|
||||
}
|
||||
|
||||
u := hclient.URL(test.endpoint, test.args)
|
||||
if u.String() != test.expected {
|
||||
t.Errorf("unexpected result: got %s, want %s", u, test.expected)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015 The Prometheus Authors
|
||||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -11,41 +11,40 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package prometheus provides bindings to the Prometheus HTTP API:
|
||||
// +build go1.7
|
||||
|
||||
// Package v1 provides bindings to the Prometheus HTTP API v1:
|
||||
// http://prometheus.io/docs/querying/api/
|
||||
package prometheus
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/api"
|
||||
"github.com/prometheus/common/model"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
)
|
||||
|
||||
const (
|
||||
statusAPIError = 422
|
||||
apiPrefix = "/api/v1"
|
||||
|
||||
epQuery = "/query"
|
||||
epQueryRange = "/query_range"
|
||||
epLabelValues = "/label/:name/values"
|
||||
epSeries = "/series"
|
||||
apiPrefix = "/api/v1"
|
||||
|
||||
epQuery = apiPrefix + "/query"
|
||||
epQueryRange = apiPrefix + "/query_range"
|
||||
epLabelValues = apiPrefix + "/label/:name/values"
|
||||
epSeries = apiPrefix + "/series"
|
||||
)
|
||||
|
||||
// ErrorType models the different API error types.
|
||||
type ErrorType string
|
||||
|
||||
// Possible values for ErrorType.
|
||||
const (
|
||||
// The different API error types.
|
||||
ErrBadData ErrorType = "bad_data"
|
||||
ErrTimeout = "timeout"
|
||||
ErrCanceled = "canceled"
|
||||
@@ -63,166 +62,6 @@ func (e *Error) Error() string {
|
||||
return fmt.Sprintf("%s: %s", e.Type, e.Msg)
|
||||
}
|
||||
|
||||
// CancelableTransport is like net.Transport but provides
|
||||
// per-request cancelation functionality.
|
||||
type CancelableTransport interface {
|
||||
http.RoundTripper
|
||||
CancelRequest(req *http.Request)
|
||||
}
|
||||
|
||||
var DefaultTransport CancelableTransport = &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
// Config defines configuration parameters for a new client.
|
||||
type Config struct {
|
||||
// The address of the Prometheus to connect to.
|
||||
Address string
|
||||
|
||||
// Transport is used by the Client to drive HTTP requests. If not
|
||||
// provided, DefaultTransport will be used.
|
||||
Transport CancelableTransport
|
||||
}
|
||||
|
||||
func (cfg *Config) transport() CancelableTransport {
|
||||
if cfg.Transport == nil {
|
||||
return DefaultTransport
|
||||
}
|
||||
return cfg.Transport
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
url(ep string, args map[string]string) *url.URL
|
||||
do(context.Context, *http.Request) (*http.Response, []byte, error)
|
||||
}
|
||||
|
||||
// New returns a new Client.
|
||||
//
|
||||
// It is safe to use the returned Client from multiple goroutines.
|
||||
func New(cfg Config) (Client, error) {
|
||||
u, err := url.Parse(cfg.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.Path = strings.TrimRight(u.Path, "/") + apiPrefix
|
||||
|
||||
return &httpClient{
|
||||
endpoint: u,
|
||||
transport: cfg.transport(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type httpClient struct {
|
||||
endpoint *url.URL
|
||||
transport CancelableTransport
|
||||
}
|
||||
|
||||
func (c *httpClient) url(ep string, args map[string]string) *url.URL {
|
||||
p := path.Join(c.endpoint.Path, ep)
|
||||
|
||||
for arg, val := range args {
|
||||
arg = ":" + arg
|
||||
p = strings.Replace(p, arg, val, -1)
|
||||
}
|
||||
|
||||
u := *c.endpoint
|
||||
u.Path = p
|
||||
|
||||
return &u
|
||||
}
|
||||
|
||||
func (c *httpClient) do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
resp, err := ctxhttp.Do(ctx, &http.Client{Transport: c.transport}, req)
|
||||
|
||||
defer func() {
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var body []byte
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
close(done)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
err = resp.Body.Close()
|
||||
<-done
|
||||
if err == nil {
|
||||
err = ctx.Err()
|
||||
}
|
||||
case <-done:
|
||||
}
|
||||
|
||||
return resp, body, err
|
||||
}
|
||||
|
||||
// apiClient wraps a regular client and processes successful API responses.
|
||||
// Successful also includes responses that errored at the API level.
|
||||
type apiClient struct {
|
||||
Client
|
||||
}
|
||||
|
||||
type apiResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
ErrorType ErrorType `json:"errorType"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
func (c apiClient) do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
resp, body, err := c.Client.do(ctx, req)
|
||||
if err != nil {
|
||||
return resp, body, err
|
||||
}
|
||||
|
||||
code := resp.StatusCode
|
||||
|
||||
if code/100 != 2 && code != statusAPIError {
|
||||
return resp, body, &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: fmt.Sprintf("bad response code %d", resp.StatusCode),
|
||||
}
|
||||
}
|
||||
|
||||
var result apiResponse
|
||||
|
||||
if err = json.Unmarshal(body, &result); err != nil {
|
||||
return resp, body, &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
if (code == statusAPIError) != (result.Status == "error") {
|
||||
err = &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: "inconsistent body for response code",
|
||||
}
|
||||
}
|
||||
|
||||
if code == statusAPIError && result.Status == "error" {
|
||||
err = &Error{
|
||||
Type: result.ErrorType,
|
||||
Msg: result.Error,
|
||||
}
|
||||
}
|
||||
|
||||
return resp, []byte(result.Data), err
|
||||
}
|
||||
|
||||
// Range represents a sliced time range.
|
||||
type Range struct {
|
||||
// The boundaries of the time range.
|
||||
@@ -231,6 +70,16 @@ type Range struct {
|
||||
Step time.Duration
|
||||
}
|
||||
|
||||
// API provides bindings for Prometheus's v1 API.
|
||||
type API interface {
|
||||
// Query performs a query for the given time.
|
||||
Query(ctx context.Context, query string, ts time.Time) (model.Value, error)
|
||||
// QueryRange performs a query for the given range.
|
||||
QueryRange(ctx context.Context, query string, r Range) (model.Value, error)
|
||||
// LabelValues performs a query for the values of the given label.
|
||||
LabelValues(ctx context.Context, label string) (model.LabelValues, error)
|
||||
}
|
||||
|
||||
// queryResult contains result data for a query.
|
||||
type queryResult struct {
|
||||
Type model.ValueType `json:"resultType"`
|
||||
@@ -273,27 +122,19 @@ func (qr *queryResult) UnmarshalJSON(b []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// QueryAPI provides bindings the Prometheus's query API.
|
||||
type QueryAPI interface {
|
||||
// Query performs a query for the given time.
|
||||
Query(ctx context.Context, query string, ts time.Time) (model.Value, error)
|
||||
// Query performs a query for the given range.
|
||||
QueryRange(ctx context.Context, query string, r Range) (model.Value, error)
|
||||
}
|
||||
|
||||
// NewQueryAPI returns a new QueryAPI for the client.
|
||||
// NewAPI returns a new API for the client.
|
||||
//
|
||||
// It is safe to use the returned QueryAPI from multiple goroutines.
|
||||
func NewQueryAPI(c Client) QueryAPI {
|
||||
return &httpQueryAPI{client: apiClient{c}}
|
||||
// It is safe to use the returned API from multiple goroutines.
|
||||
func NewAPI(c api.Client) API {
|
||||
return &httpAPI{client: apiClient{c}}
|
||||
}
|
||||
|
||||
type httpQueryAPI struct {
|
||||
client Client
|
||||
type httpAPI struct {
|
||||
client api.Client
|
||||
}
|
||||
|
||||
func (h *httpQueryAPI) Query(ctx context.Context, query string, ts time.Time) (model.Value, error) {
|
||||
u := h.client.url(epQuery, nil)
|
||||
func (h *httpAPI) Query(ctx context.Context, query string, ts time.Time) (model.Value, error) {
|
||||
u := h.client.URL(epQuery, nil)
|
||||
q := u.Query()
|
||||
|
||||
q.Set("query", query)
|
||||
@@ -301,9 +142,12 @@ func (h *httpQueryAPI) Query(ctx context.Context, query string, ts time.Time) (m
|
||||
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
req, _ := http.NewRequest("GET", u.String(), nil)
|
||||
req, err := http.NewRequest("GET", u.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, body, err := h.client.do(ctx, req)
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -314,8 +158,8 @@ func (h *httpQueryAPI) Query(ctx context.Context, query string, ts time.Time) (m
|
||||
return model.Value(qres.v), err
|
||||
}
|
||||
|
||||
func (h *httpQueryAPI) QueryRange(ctx context.Context, query string, r Range) (model.Value, error) {
|
||||
u := h.client.url(epQueryRange, nil)
|
||||
func (h *httpAPI) QueryRange(ctx context.Context, query string, r Range) (model.Value, error) {
|
||||
u := h.client.URL(epQueryRange, nil)
|
||||
q := u.Query()
|
||||
|
||||
var (
|
||||
@@ -331,9 +175,12 @@ func (h *httpQueryAPI) QueryRange(ctx context.Context, query string, r Range) (m
|
||||
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
req, _ := http.NewRequest("GET", u.String(), nil)
|
||||
req, err := http.NewRequest("GET", u.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, body, err := h.client.do(ctx, req)
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -343,3 +190,72 @@ func (h *httpQueryAPI) QueryRange(ctx context.Context, query string, r Range) (m
|
||||
|
||||
return model.Value(qres.v), err
|
||||
}
|
||||
|
||||
func (h *httpAPI) LabelValues(ctx context.Context, label string) (model.LabelValues, error) {
|
||||
u := h.client.URL(epLabelValues, map[string]string{"name": label})
|
||||
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, body, err := h.client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var labelValues model.LabelValues
|
||||
err = json.Unmarshal(body, &labelValues)
|
||||
return labelValues, err
|
||||
}
|
||||
|
||||
// apiClient wraps a regular client and processes successful API responses.
|
||||
// Successful also includes responses that errored at the API level.
|
||||
type apiClient struct {
|
||||
api.Client
|
||||
}
|
||||
|
||||
type apiResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
ErrorType ErrorType `json:"errorType"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
func (c apiClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
resp, body, err := c.Client.Do(ctx, req)
|
||||
if err != nil {
|
||||
return resp, body, err
|
||||
}
|
||||
|
||||
code := resp.StatusCode
|
||||
|
||||
if code/100 != 2 && code != statusAPIError {
|
||||
return resp, body, &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: fmt.Sprintf("bad response code %d", resp.StatusCode),
|
||||
}
|
||||
}
|
||||
|
||||
var result apiResponse
|
||||
|
||||
if err = json.Unmarshal(body, &result); err != nil {
|
||||
return resp, body, &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
if (code == statusAPIError) != (result.Status == "error") {
|
||||
err = &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: "inconsistent body for response code",
|
||||
}
|
||||
}
|
||||
|
||||
if code == statusAPIError && result.Status == "error" {
|
||||
err = &Error{
|
||||
Type: result.ErrorType,
|
||||
Msg: result.Error,
|
||||
}
|
||||
}
|
||||
|
||||
return resp, []byte(result.Data), err
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015 The Prometheus Authors
|
||||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -11,118 +11,203 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package prometheus
|
||||
// +build go1.7
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
c := Config{}
|
||||
if c.transport() != DefaultTransport {
|
||||
t.Fatalf("expected default transport for nil Transport field")
|
||||
}
|
||||
type apiTest struct {
|
||||
do func() (interface{}, error)
|
||||
inErr error
|
||||
inRes interface{}
|
||||
|
||||
reqPath string
|
||||
reqParam url.Values
|
||||
reqMethod string
|
||||
res interface{}
|
||||
err error
|
||||
}
|
||||
|
||||
func TestClientURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
address string
|
||||
endpoint string
|
||||
args map[string]string
|
||||
expected string
|
||||
}{
|
||||
type apiTestClient struct {
|
||||
*testing.T
|
||||
curTest apiTest
|
||||
}
|
||||
|
||||
func (c *apiTestClient) URL(ep string, args map[string]string) *url.URL {
|
||||
path := ep
|
||||
for k, v := range args {
|
||||
path = strings.Replace(path, ":"+k, v, -1)
|
||||
}
|
||||
u := &url.URL{
|
||||
Host: "test:9090",
|
||||
Path: path,
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
func (c *apiTestClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
|
||||
test := c.curTest
|
||||
|
||||
if req.URL.Path != test.reqPath {
|
||||
c.Errorf("unexpected request path: want %s, got %s", test.reqPath, req.URL.Path)
|
||||
}
|
||||
if req.Method != test.reqMethod {
|
||||
c.Errorf("unexpected request method: want %s, got %s", test.reqMethod, req.Method)
|
||||
}
|
||||
|
||||
b, err := json.Marshal(test.inRes)
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
resp := &http.Response{}
|
||||
if test.inErr != nil {
|
||||
resp.StatusCode = statusAPIError
|
||||
} else {
|
||||
resp.StatusCode = http.StatusOK
|
||||
}
|
||||
|
||||
return resp, b, test.inErr
|
||||
}
|
||||
|
||||
func TestAPIs(t *testing.T) {
|
||||
|
||||
testTime := time.Now()
|
||||
|
||||
client := &apiTestClient{T: t}
|
||||
|
||||
queryAPI := &httpAPI{
|
||||
client: client,
|
||||
}
|
||||
|
||||
doQuery := func(q string, ts time.Time) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
return queryAPI.Query(context.Background(), q, ts)
|
||||
}
|
||||
}
|
||||
|
||||
doQueryRange := func(q string, rng Range) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
return queryAPI.QueryRange(context.Background(), q, rng)
|
||||
}
|
||||
}
|
||||
|
||||
doLabelValues := func(label string) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
return queryAPI.LabelValues(context.Background(), label)
|
||||
}
|
||||
}
|
||||
|
||||
queryTests := []apiTest{
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "/test",
|
||||
expected: "http://localhost:9090/test",
|
||||
},
|
||||
{
|
||||
address: "http://localhost",
|
||||
endpoint: "/test",
|
||||
expected: "http://localhost/test",
|
||||
},
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "test",
|
||||
expected: "http://localhost:9090/test",
|
||||
},
|
||||
{
|
||||
address: "http://localhost:9090/prefix",
|
||||
endpoint: "/test",
|
||||
expected: "http://localhost:9090/prefix/test",
|
||||
},
|
||||
{
|
||||
address: "https://localhost:9090/",
|
||||
endpoint: "/test/",
|
||||
expected: "https://localhost:9090/test",
|
||||
},
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "/test/:param",
|
||||
args: map[string]string{
|
||||
"param": "content",
|
||||
do: doQuery("2", testTime),
|
||||
inRes: &queryResult{
|
||||
Type: model.ValScalar,
|
||||
Result: &model.Scalar{
|
||||
Value: 2,
|
||||
Timestamp: model.TimeFromUnix(testTime.Unix()),
|
||||
},
|
||||
},
|
||||
|
||||
reqMethod: "GET",
|
||||
reqPath: "/api/v1/query",
|
||||
reqParam: url.Values{
|
||||
"query": []string{"2"},
|
||||
"time": []string{testTime.Format(time.RFC3339Nano)},
|
||||
},
|
||||
res: &model.Scalar{
|
||||
Value: 2,
|
||||
Timestamp: model.TimeFromUnix(testTime.Unix()),
|
||||
},
|
||||
expected: "http://localhost:9090/test/content",
|
||||
},
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "/test/:param/more/:param",
|
||||
args: map[string]string{
|
||||
"param": "content",
|
||||
do: doQuery("2", testTime),
|
||||
inErr: fmt.Errorf("some error"),
|
||||
|
||||
reqMethod: "GET",
|
||||
reqPath: "/api/v1/query",
|
||||
reqParam: url.Values{
|
||||
"query": []string{"2"},
|
||||
"time": []string{testTime.Format(time.RFC3339Nano)},
|
||||
},
|
||||
expected: "http://localhost:9090/test/content/more/content",
|
||||
err: fmt.Errorf("some error"),
|
||||
},
|
||||
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "/test/:param/more/:foo",
|
||||
args: map[string]string{
|
||||
"param": "content",
|
||||
"foo": "bar",
|
||||
do: doQueryRange("2", Range{
|
||||
Start: testTime.Add(-time.Minute),
|
||||
End: testTime,
|
||||
Step: time.Minute,
|
||||
}),
|
||||
inErr: fmt.Errorf("some error"),
|
||||
|
||||
reqMethod: "GET",
|
||||
reqPath: "/api/v1/query_range",
|
||||
reqParam: url.Values{
|
||||
"query": []string{"2"},
|
||||
"start": []string{testTime.Add(-time.Minute).Format(time.RFC3339Nano)},
|
||||
"end": []string{testTime.Format(time.RFC3339Nano)},
|
||||
"step": []string{time.Minute.String()},
|
||||
},
|
||||
expected: "http://localhost:9090/test/content/more/bar",
|
||||
err: fmt.Errorf("some error"),
|
||||
},
|
||||
|
||||
{
|
||||
address: "http://localhost:9090",
|
||||
endpoint: "/test/:param",
|
||||
args: map[string]string{
|
||||
"nonexistant": "content",
|
||||
},
|
||||
expected: "http://localhost:9090/test/:param",
|
||||
do: doLabelValues("mylabel"),
|
||||
inRes: []string{"val1", "val2"},
|
||||
reqMethod: "GET",
|
||||
reqPath: "/api/v1/label/mylabel/values",
|
||||
res: model.LabelValues{"val1", "val2"},
|
||||
},
|
||||
|
||||
{
|
||||
do: doLabelValues("mylabel"),
|
||||
inErr: fmt.Errorf("some error"),
|
||||
reqMethod: "GET",
|
||||
reqPath: "/api/v1/label/mylabel/values",
|
||||
err: fmt.Errorf("some error"),
|
||||
},
|
||||
}
|
||||
|
||||
var tests []apiTest
|
||||
tests = append(tests, queryTests...)
|
||||
|
||||
for _, test := range tests {
|
||||
ep, err := url.Parse(test.address)
|
||||
client.curTest = test
|
||||
|
||||
res, err := test.do()
|
||||
|
||||
if test.err != nil {
|
||||
if err == nil {
|
||||
t.Errorf("expected error %q but got none", test.err)
|
||||
continue
|
||||
}
|
||||
if err.Error() != test.err.Error() {
|
||||
t.Errorf("unexpected error: want %s, got %s", test.err, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hclient := &httpClient{
|
||||
endpoint: ep,
|
||||
transport: DefaultTransport,
|
||||
}
|
||||
|
||||
u := hclient.url(test.endpoint, test.args)
|
||||
if u.String() != test.expected {
|
||||
t.Errorf("unexpected result: got %s, want %s", u, test.expected)
|
||||
t.Errorf("unexpected error: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// The apiClient must return exactly the same result as the httpClient.
|
||||
aclient := &apiClient{hclient}
|
||||
|
||||
u = aclient.url(test.endpoint, test.args)
|
||||
if u.String() != test.expected {
|
||||
t.Errorf("unexpected result: got %s, want %s", u, test.expected)
|
||||
if !reflect.DeepEqual(res, test.res) {
|
||||
t.Errorf("unexpected result: want %v, got %v", test.res, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,11 +226,11 @@ type apiClientTest struct {
|
||||
err *Error
|
||||
}
|
||||
|
||||
func (c *testClient) url(ep string, args map[string]string) *url.URL {
|
||||
func (c *testClient) URL(ep string, args map[string]string) *url.URL {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *testClient) do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
func (c *testClient) Do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
if ctx == nil {
|
||||
c.Fatalf("context was not passed down")
|
||||
}
|
||||
@@ -271,7 +356,7 @@ func TestAPIClientDo(t *testing.T) {
|
||||
|
||||
tc.ch <- test
|
||||
|
||||
_, body, err := client.do(context.Background(), tc.req)
|
||||
_, body, err := client.Do(context.Background(), tc.req)
|
||||
|
||||
if test.err != nil {
|
||||
if err == nil {
|
||||
@@ -294,160 +379,3 @@ func TestAPIClientDo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type apiTestClient struct {
|
||||
*testing.T
|
||||
curTest apiTest
|
||||
}
|
||||
|
||||
type apiTest struct {
|
||||
do func() (interface{}, error)
|
||||
inErr error
|
||||
inRes interface{}
|
||||
|
||||
reqPath string
|
||||
reqParam url.Values
|
||||
reqMethod string
|
||||
res interface{}
|
||||
err error
|
||||
}
|
||||
|
||||
func (c *apiTestClient) url(ep string, args map[string]string) *url.URL {
|
||||
u := &url.URL{
|
||||
Host: "test:9090",
|
||||
Path: apiPrefix + ep,
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
func (c *apiTestClient) do(ctx context.Context, req *http.Request) (*http.Response, []byte, error) {
|
||||
|
||||
test := c.curTest
|
||||
|
||||
if req.URL.Path != test.reqPath {
|
||||
c.Errorf("unexpected request path: want %s, got %s", test.reqPath, req.URL.Path)
|
||||
}
|
||||
if req.Method != test.reqMethod {
|
||||
c.Errorf("unexpected request method: want %s, got %s", test.reqMethod, req.Method)
|
||||
}
|
||||
|
||||
b, err := json.Marshal(test.inRes)
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
resp := &http.Response{}
|
||||
if test.inErr != nil {
|
||||
resp.StatusCode = statusAPIError
|
||||
} else {
|
||||
resp.StatusCode = http.StatusOK
|
||||
}
|
||||
|
||||
return resp, b, test.inErr
|
||||
}
|
||||
|
||||
func TestAPIs(t *testing.T) {
|
||||
|
||||
testTime := time.Now()
|
||||
|
||||
client := &apiTestClient{T: t}
|
||||
|
||||
queryApi := &httpQueryAPI{
|
||||
client: client,
|
||||
}
|
||||
|
||||
doQuery := func(q string, ts time.Time) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
return queryApi.Query(context.Background(), q, ts)
|
||||
}
|
||||
}
|
||||
|
||||
doQueryRange := func(q string, rng Range) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
return queryApi.QueryRange(context.Background(), q, rng)
|
||||
}
|
||||
}
|
||||
|
||||
queryTests := []apiTest{
|
||||
{
|
||||
do: doQuery("2", testTime),
|
||||
inRes: &queryResult{
|
||||
Type: model.ValScalar,
|
||||
Result: &model.Scalar{
|
||||
Value: 2,
|
||||
Timestamp: model.TimeFromUnix(testTime.Unix()),
|
||||
},
|
||||
},
|
||||
|
||||
reqMethod: "GET",
|
||||
reqPath: "/api/v1/query",
|
||||
reqParam: url.Values{
|
||||
"query": []string{"2"},
|
||||
"time": []string{testTime.Format(time.RFC3339Nano)},
|
||||
},
|
||||
res: &model.Scalar{
|
||||
Value: 2,
|
||||
Timestamp: model.TimeFromUnix(testTime.Unix()),
|
||||
},
|
||||
},
|
||||
{
|
||||
do: doQuery("2", testTime),
|
||||
inErr: fmt.Errorf("some error"),
|
||||
|
||||
reqMethod: "GET",
|
||||
reqPath: "/api/v1/query",
|
||||
reqParam: url.Values{
|
||||
"query": []string{"2"},
|
||||
"time": []string{testTime.Format(time.RFC3339Nano)},
|
||||
},
|
||||
err: fmt.Errorf("some error"),
|
||||
},
|
||||
|
||||
{
|
||||
do: doQueryRange("2", Range{
|
||||
Start: testTime.Add(-time.Minute),
|
||||
End: testTime,
|
||||
Step: time.Minute,
|
||||
}),
|
||||
inErr: fmt.Errorf("some error"),
|
||||
|
||||
reqMethod: "GET",
|
||||
reqPath: "/api/v1/query_range",
|
||||
reqParam: url.Values{
|
||||
"query": []string{"2"},
|
||||
"start": []string{testTime.Add(-time.Minute).Format(time.RFC3339Nano)},
|
||||
"end": []string{testTime.Format(time.RFC3339Nano)},
|
||||
"step": []string{time.Minute.String()},
|
||||
},
|
||||
err: fmt.Errorf("some error"),
|
||||
},
|
||||
}
|
||||
|
||||
var tests []apiTest
|
||||
tests = append(tests, queryTests...)
|
||||
|
||||
for _, test := range tests {
|
||||
client.curTest = test
|
||||
|
||||
res, err := test.do()
|
||||
|
||||
if test.err != nil {
|
||||
if err == nil {
|
||||
t.Errorf("expected error %q but got none", test.err)
|
||||
continue
|
||||
}
|
||||
if err.Error() != test.err.Error() {
|
||||
t.Errorf("unexpected error: want %s, got %s", test.err, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(res, test.res) {
|
||||
t.Errorf("unexpected result: want %v, got %v", test.res, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
21
vendor/github.com/prometheus/client_golang/examples/random/main.go
сгенерированный
поставляемый
21
vendor/github.com/prometheus/client_golang/examples/random/main.go
сгенерированный
поставляемый
@@ -18,19 +18,21 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
var (
|
||||
addr = flag.String("listen-address", ":8080", "The address to listen on for HTTP requests.")
|
||||
uniformDomain = flag.Float64("uniform.domain", 200, "The domain for the uniform distribution.")
|
||||
normDomain = flag.Float64("normal.domain", 200, "The domain for the normal distribution.")
|
||||
normMean = flag.Float64("normal.mean", 10, "The mean for the normal distribution.")
|
||||
uniformDomain = flag.Float64("uniform.domain", 0.0002, "The domain for the uniform distribution.")
|
||||
normDomain = flag.Float64("normal.domain", 0.0002, "The domain for the normal distribution.")
|
||||
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.")
|
||||
)
|
||||
|
||||
@@ -40,8 +42,9 @@ var (
|
||||
// differentiated via a "service" label.
|
||||
rpcDurations = prometheus.NewSummaryVec(
|
||||
prometheus.SummaryOpts{
|
||||
Name: "rpc_durations_microseconds",
|
||||
Help: "RPC latency distributions.",
|
||||
Name: "rpc_durations_seconds",
|
||||
Help: "RPC latency distributions.",
|
||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||
},
|
||||
[]string{"service"},
|
||||
)
|
||||
@@ -50,7 +53,7 @@ var (
|
||||
// normal distribution, with 20 buckets centered on the mean, each
|
||||
// half-sigma wide.
|
||||
rpcDurationsHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
|
||||
Name: "rpc_durations_histogram_microseconds",
|
||||
Name: "rpc_durations_histogram_seconds",
|
||||
Help: "RPC latency distributions.",
|
||||
Buckets: prometheus.LinearBuckets(*normMean-5**normDomain, .5**normDomain, 20),
|
||||
})
|
||||
@@ -91,13 +94,13 @@ func main() {
|
||||
|
||||
go func() {
|
||||
for {
|
||||
v := rand.ExpFloat64()
|
||||
v := rand.ExpFloat64() / 1e6
|
||||
rpcDurations.WithLabelValues("exponential").Observe(v)
|
||||
time.Sleep(time.Duration(50*oscillationFactor()) * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
// Expose the registered metrics via HTTP.
|
||||
http.Handle("/metrics", prometheus.Handler())
|
||||
http.ListenAndServe(*addr, nil)
|
||||
http.Handle("/metrics", promhttp.Handler())
|
||||
log.Fatal(http.ListenAndServe(*addr, nil))
|
||||
}
|
||||
|
||||
7
vendor/github.com/prometheus/client_golang/examples/simple/main.go
сгенерированный
поставляемый
7
vendor/github.com/prometheus/client_golang/examples/simple/main.go
сгенерированный
поставляемый
@@ -16,15 +16,16 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
var addr = flag.String("listen-address", ":8080", "The address to listen on for HTTP requests.")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
http.Handle("/metrics", prometheus.Handler())
|
||||
http.ListenAndServe(*addr, nil)
|
||||
http.Handle("/metrics", promhttp.Handler())
|
||||
log.Fatal(http.ListenAndServe(*addr, nil))
|
||||
}
|
||||
|
||||
10
vendor/github.com/prometheus/client_golang/prometheus/benchmark_test.go
сгенерированный
поставляемый
10
vendor/github.com/prometheus/client_golang/prometheus/benchmark_test.go
сгенерированный
поставляемый
@@ -129,8 +129,9 @@ func BenchmarkGaugeNoLabels(b *testing.B) {
|
||||
func BenchmarkSummaryWithLabelValues(b *testing.B) {
|
||||
m := NewSummaryVec(
|
||||
SummaryOpts{
|
||||
Name: "benchmark_summary",
|
||||
Help: "A summary to benchmark it.",
|
||||
Name: "benchmark_summary",
|
||||
Help: "A summary to benchmark it.",
|
||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||
},
|
||||
[]string{"one", "two", "three"},
|
||||
)
|
||||
@@ -143,8 +144,9 @@ func BenchmarkSummaryWithLabelValues(b *testing.B) {
|
||||
|
||||
func BenchmarkSummaryNoLabels(b *testing.B) {
|
||||
m := NewSummary(SummaryOpts{
|
||||
Name: "benchmark_summary",
|
||||
Help: "A summary to benchmark it.",
|
||||
Name: "benchmark_summary",
|
||||
Help: "A summary to benchmark it.",
|
||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||
},
|
||||
)
|
||||
b.ReportAllocs()
|
||||
|
||||
12
vendor/github.com/prometheus/client_golang/prometheus/counter.go
сгенерированный
поставляемый
12
vendor/github.com/prometheus/client_golang/prometheus/counter.go
сгенерированный
поставляемый
@@ -30,16 +30,8 @@ type Counter interface {
|
||||
Metric
|
||||
Collector
|
||||
|
||||
// Set is used to set the Counter to an arbitrary value. It is only used
|
||||
// if you have to transfer a value from an external counter into this
|
||||
// Prometheus metric. Do not use it for regular handling of a
|
||||
// Prometheus counter (as it can be used to break the contract of
|
||||
// monotonically increasing values).
|
||||
//
|
||||
// Deprecated: Use NewConstMetric to create a counter for an external
|
||||
// value. A Counter should never be set.
|
||||
Set(float64)
|
||||
// Inc increments the counter by 1.
|
||||
// Inc increments the counter by 1. Use Add to increment it by arbitrary
|
||||
// non-negative values.
|
||||
Inc()
|
||||
// Add adds the given value to the counter. It panics if the value is <
|
||||
// 0.
|
||||
|
||||
13
vendor/github.com/prometheus/client_golang/prometheus/desc.go
сгенерированный
поставляемый
13
vendor/github.com/prometheus/client_golang/prometheus/desc.go
сгенерированный
поставляемый
@@ -16,20 +16,15 @@ package prometheus
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
var (
|
||||
metricNameRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_:]*$`)
|
||||
labelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
|
||||
)
|
||||
|
||||
// reservedLabelPrefix is a prefix which is not legal in user-supplied
|
||||
// label names.
|
||||
const reservedLabelPrefix = "__"
|
||||
@@ -78,7 +73,7 @@ type Desc struct {
|
||||
// Help string. Each Desc with the same fqName must have the same
|
||||
// dimHash.
|
||||
dimHash uint64
|
||||
// err is an error that occured during construction. It is reported on
|
||||
// err is an error that occurred during construction. It is reported on
|
||||
// registration time.
|
||||
err error
|
||||
}
|
||||
@@ -103,7 +98,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *
|
||||
d.err = errors.New("empty help string")
|
||||
return d
|
||||
}
|
||||
if !metricNameRE.MatchString(fqName) {
|
||||
if !model.IsValidMetricName(model.LabelValue(fqName)) {
|
||||
d.err = fmt.Errorf("%q is not a valid metric name", fqName)
|
||||
return d
|
||||
}
|
||||
@@ -200,6 +195,6 @@ func (d *Desc) String() string {
|
||||
}
|
||||
|
||||
func checkLabelName(l string) bool {
|
||||
return labelNameRE.MatchString(l) &&
|
||||
return model.LabelName(l).IsValid() &&
|
||||
!strings.HasPrefix(l, reservedLabelPrefix)
|
||||
}
|
||||
|
||||
64
vendor/github.com/prometheus/client_golang/prometheus/doc.go
сгенерированный
поставляемый
64
vendor/github.com/prometheus/client_golang/prometheus/doc.go
сгенерированный
поставляемый
@@ -17,7 +17,7 @@
|
||||
// Pushgateway (package push).
|
||||
//
|
||||
// All exported functions and methods are safe to be used concurrently unless
|
||||
//specified otherwise.
|
||||
// specified otherwise.
|
||||
//
|
||||
// A Basic Example
|
||||
//
|
||||
@@ -59,7 +59,7 @@
|
||||
// // The Handler function provides a default handler to expose metrics
|
||||
// // via an HTTP server. "/metrics" is the usual endpoint for that.
|
||||
// http.Handle("/metrics", promhttp.Handler())
|
||||
// http.ListenAndServe(":8080", nil)
|
||||
// log.Fatal(http.ListenAndServe(":8080", nil))
|
||||
// }
|
||||
//
|
||||
//
|
||||
@@ -69,7 +69,7 @@
|
||||
// Metrics
|
||||
//
|
||||
// The number of exported identifiers in this package might appear a bit
|
||||
// overwhelming. Hovever, in addition to the basic plumbing shown in the example
|
||||
// overwhelming. However, in addition to the basic plumbing shown in the example
|
||||
// above, you only need to understand the different metric types and their
|
||||
// vector versions for basic usage.
|
||||
//
|
||||
@@ -95,8 +95,8 @@
|
||||
// SummaryVec, HistogramVec, and UntypedVec are not.
|
||||
//
|
||||
// To create instances of Metrics and their vector versions, you need a suitable
|
||||
// …Opts struct, i.e. GaugeOpts, CounterOpts, SummaryOpts,
|
||||
// HistogramOpts, or UntypedOpts.
|
||||
// …Opts struct, i.e. GaugeOpts, CounterOpts, SummaryOpts, HistogramOpts, or
|
||||
// UntypedOpts.
|
||||
//
|
||||
// Custom Collectors and constant Metrics
|
||||
//
|
||||
@@ -114,8 +114,8 @@
|
||||
// Metric instances “on the fly” using NewConstMetric, NewConstHistogram, and
|
||||
// NewConstSummary (and their respective Must… versions). That will happen in
|
||||
// the Collect method. The Describe method has to return separate Desc
|
||||
// instances, representative of the “throw-away” metrics to be created
|
||||
// later. NewDesc comes in handy to create those Desc instances.
|
||||
// instances, representative of the “throw-away” metrics to be created later.
|
||||
// NewDesc comes in handy to create those Desc instances.
|
||||
//
|
||||
// The Collector example illustrates the use case. You can also look at the
|
||||
// source code of the processCollector (mirroring process metrics), the
|
||||
@@ -129,32 +129,32 @@
|
||||
// Advanced Uses of the Registry
|
||||
//
|
||||
// While MustRegister is the by far most common way of registering a Collector,
|
||||
// sometimes you might want to handle the errors the registration might
|
||||
// cause. As suggested by the name, MustRegister panics if an error occurs. With
|
||||
// the Register function, the error is returned and can be handled.
|
||||
// sometimes you might want to handle the errors the registration might cause.
|
||||
// As suggested by the name, MustRegister panics if an error occurs. With the
|
||||
// Register function, the error is returned and can be handled.
|
||||
//
|
||||
// An error is returned if the registered Collector is incompatible or
|
||||
// inconsistent with already registered metrics. The registry aims for
|
||||
// consistency of the collected metrics according to the Prometheus data
|
||||
// model. Inconsistencies are ideally detected at registration time, not at
|
||||
// collect time. The former will usually be detected at start-up time of a
|
||||
// program, while the latter will only happen at scrape time, possibly not even
|
||||
// on the first scrape if the inconsistency only becomes relevant later. That is
|
||||
// the main reason why a Collector and a Metric have to describe themselves to
|
||||
// the registry.
|
||||
// consistency of the collected metrics according to the Prometheus data model.
|
||||
// Inconsistencies are ideally detected at registration time, not at collect
|
||||
// time. The former will usually be detected at start-up time of a program,
|
||||
// while the latter will only happen at scrape time, possibly not even on the
|
||||
// first scrape if the inconsistency only becomes relevant later. That is the
|
||||
// main reason why a Collector and a Metric have to describe themselves to the
|
||||
// registry.
|
||||
//
|
||||
// So far, everything we did operated on the so-called default registry, as it
|
||||
// can be found in the global DefaultRegistry variable. With NewRegistry, you
|
||||
// can create a custom registry, or you can even implement the Registerer or
|
||||
// Gatherer interfaces yourself. The methods Register and Unregister work in
|
||||
// the same way on a custom registry as the global functions Register and
|
||||
// Unregister on the default registry.
|
||||
// Gatherer interfaces yourself. The methods Register and Unregister work in the
|
||||
// same way on a custom registry as the global functions Register and Unregister
|
||||
// on the default registry.
|
||||
//
|
||||
// There are a number of uses for custom registries: You can use registries
|
||||
// with special properties, see NewPedanticRegistry. You can avoid global state,
|
||||
// as it is imposed by the DefaultRegistry. You can use multiple registries at
|
||||
// the same time to expose different metrics in different ways. You can use
|
||||
// separate registries for testing purposes.
|
||||
// There are a number of uses for custom registries: You can use registries with
|
||||
// special properties, see NewPedanticRegistry. You can avoid global state, as
|
||||
// it is imposed by the DefaultRegistry. You can use multiple registries at the
|
||||
// same time to expose different metrics in different ways. You can use separate
|
||||
// registries for testing purposes.
|
||||
//
|
||||
// Also note that the DefaultRegistry comes registered with a Collector for Go
|
||||
// runtime metrics (via NewGoCollector) and a Collector for process metrics (via
|
||||
@@ -166,16 +166,20 @@
|
||||
// The Registry implements the Gatherer interface. The caller of the Gather
|
||||
// method can then expose the gathered metrics in some way. Usually, the metrics
|
||||
// are served via HTTP on the /metrics endpoint. That's happening in the example
|
||||
// above. The tools to expose metrics via HTTP are in the promhttp
|
||||
// sub-package. (The top-level functions in the prometheus package are
|
||||
// deprecated.)
|
||||
// above. The tools to expose metrics via HTTP are in the promhttp sub-package.
|
||||
// (The top-level functions in the prometheus package are deprecated.)
|
||||
//
|
||||
// Pushing to the Pushgateway
|
||||
//
|
||||
// Function for pushing to the Pushgateway can be found in the push sub-package.
|
||||
//
|
||||
// Graphite Bridge
|
||||
//
|
||||
// Functions and examples to push metrics from a Gatherer to Graphite can be
|
||||
// found in the graphite sub-package.
|
||||
//
|
||||
// Other Means of Exposition
|
||||
//
|
||||
// More ways of exposing metrics can easily be added. Sending metrics to
|
||||
// Graphite would be an example that will soon be implemented.
|
||||
// More ways of exposing metrics can easily be added by following the approaches
|
||||
// of the existing implementations.
|
||||
package prometheus
|
||||
|
||||
71
vendor/github.com/prometheus/client_golang/prometheus/example_timer_complex_test.go
сгенерированный
поставляемый
Обычный файл
71
vendor/github.com/prometheus/client_golang/prometheus/example_timer_complex_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,71 @@
|
||||
// Copyright 2014 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package prometheus_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
// apiRequestDuration tracks the duration separate for each HTTP status
|
||||
// class (1xx, 2xx, ...). This creates a fair amount of time series on
|
||||
// the Prometheus server. Usually, you would track the duration of
|
||||
// serving HTTP request without partitioning by outcome. Do something
|
||||
// like this only if needed. Also note how only status classes are
|
||||
// tracked, not every single status code. The latter would create an
|
||||
// even larger amount of time series. Request counters partitioned by
|
||||
// status code are usually OK as each counter only creates one time
|
||||
// series. Histograms are way more expensive, so partition with care and
|
||||
// only where you really need separate latency tracking. Partitioning by
|
||||
// status class is only an example. In concrete cases, other partitions
|
||||
// might make more sense.
|
||||
apiRequestDuration = prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "api_request_duration_seconds",
|
||||
Help: "Histogram for the request duration of the public API, partitioned by status class.",
|
||||
Buckets: prometheus.ExponentialBuckets(0.1, 1.5, 5),
|
||||
},
|
||||
[]string{"status_class"},
|
||||
)
|
||||
)
|
||||
|
||||
func handler(w http.ResponseWriter, r *http.Request) {
|
||||
status := http.StatusOK
|
||||
// The ObserverFunc gets called by the deferred ObserveDuration and
|
||||
// decides wich Histogram's Observe method is called.
|
||||
timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) {
|
||||
switch {
|
||||
case status >= 500: // Server error.
|
||||
apiRequestDuration.WithLabelValues("5xx").Observe(v)
|
||||
case status >= 400: // Client error.
|
||||
apiRequestDuration.WithLabelValues("4xx").Observe(v)
|
||||
case status >= 300: // Redirection.
|
||||
apiRequestDuration.WithLabelValues("3xx").Observe(v)
|
||||
case status >= 200: // Success.
|
||||
apiRequestDuration.WithLabelValues("2xx").Observe(v)
|
||||
default: // Informational.
|
||||
apiRequestDuration.WithLabelValues("1xx").Observe(v)
|
||||
}
|
||||
}))
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
// Handle the request. Set status accordingly.
|
||||
// ...
|
||||
}
|
||||
|
||||
func ExampleTimer_complex() {
|
||||
http.HandleFunc("/api", handler)
|
||||
}
|
||||
48
vendor/github.com/prometheus/client_golang/prometheus/example_timer_gauge_test.go
сгенерированный
поставляемый
Обычный файл
48
vendor/github.com/prometheus/client_golang/prometheus/example_timer_gauge_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,48 @@
|
||||
// Copyright 2014 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package prometheus_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
// If a function is called rarely (i.e. not more often than scrapes
|
||||
// happen) or ideally only once (like in a batch job), it can make sense
|
||||
// to use a Gauge for timing the function call. For timing a batch job
|
||||
// and pushing the result to a Pushgateway, see also the comprehensive
|
||||
// example in the push package.
|
||||
funcDuration = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "example_function_duration_seconds",
|
||||
Help: "Duration of the last call of an example function.",
|
||||
})
|
||||
)
|
||||
|
||||
func run() error {
|
||||
// The Set method of the Gauge is used to observe the duration.
|
||||
timer := prometheus.NewTimer(prometheus.ObserverFunc(funcDuration.Set))
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
// Do something. Return errors as encountered. The use of 'defer' above
|
||||
// makes sure the function is still timed properly.
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExampleTimer_gauge() {
|
||||
if err := run(); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
40
vendor/github.com/prometheus/client_golang/prometheus/example_timer_test.go
сгенерированный
поставляемый
Обычный файл
40
vendor/github.com/prometheus/client_golang/prometheus/example_timer_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,40 @@
|
||||
// Copyright 2014 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package prometheus_test
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
requestDuration = prometheus.NewHistogram(prometheus.HistogramOpts{
|
||||
Name: "example_request_duration_seconds",
|
||||
Help: "Histogram for the runtime of a simple example function.",
|
||||
Buckets: prometheus.LinearBuckets(0.01, 0.01, 10),
|
||||
})
|
||||
)
|
||||
|
||||
func ExampleTimer() {
|
||||
// timer times this example function. It uses a Histogram, but a Summary
|
||||
// would also work, as both implement Observer. Check out
|
||||
// https://prometheus.io/docs/practices/histograms/ for differences.
|
||||
timer := prometheus.NewTimer(requestDuration)
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
// Do something here that takes time.
|
||||
time.Sleep(time.Duration(rand.NormFloat64()*10000+50000) * time.Microsecond)
|
||||
}
|
||||
17
vendor/github.com/prometheus/client_golang/prometheus/examples_test.go
сгенерированный
поставляемый
17
vendor/github.com/prometheus/client_golang/prometheus/examples_test.go
сгенерированный
поставляемый
@@ -113,7 +113,7 @@ func ExampleCounter() {
|
||||
pushComplete := make(chan struct{})
|
||||
// TODO: Start a goroutine that performs repository pushes and reports
|
||||
// each completion via the channel.
|
||||
for _ = range pushComplete {
|
||||
for range pushComplete {
|
||||
pushCounter.Inc()
|
||||
}
|
||||
// Output:
|
||||
@@ -169,8 +169,8 @@ func ExampleInstrumentHandler() {
|
||||
|
||||
func ExampleLabelPairSorter() {
|
||||
labelPairs := []*dto.LabelPair{
|
||||
&dto.LabelPair{Name: proto.String("status"), Value: proto.String("404")},
|
||||
&dto.LabelPair{Name: proto.String("method"), Value: proto.String("get")},
|
||||
{Name: proto.String("status"), Value: proto.String("404")},
|
||||
{Name: proto.String("method"), Value: proto.String("get")},
|
||||
}
|
||||
|
||||
sort.Sort(prometheus.LabelPairSorter(labelPairs))
|
||||
@@ -334,8 +334,9 @@ func ExampleRegister() {
|
||||
|
||||
func ExampleSummary() {
|
||||
temps := prometheus.NewSummary(prometheus.SummaryOpts{
|
||||
Name: "pond_temperature_celsius",
|
||||
Help: "The temperature of the frog pond.", // Sorry, we can't measure how badly it smells.
|
||||
Name: "pond_temperature_celsius",
|
||||
Help: "The temperature of the frog pond.",
|
||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||
})
|
||||
|
||||
// Simulate some observations.
|
||||
@@ -372,8 +373,9 @@ func ExampleSummary() {
|
||||
func ExampleSummaryVec() {
|
||||
temps := prometheus.NewSummaryVec(
|
||||
prometheus.SummaryOpts{
|
||||
Name: "pond_temperature_celsius",
|
||||
Help: "The temperature of the frog pond.", // Sorry, we can't measure how badly it smells.
|
||||
Name: "pond_temperature_celsius",
|
||||
Help: "The temperature of the frog pond.",
|
||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||
},
|
||||
[]string{"species"},
|
||||
)
|
||||
@@ -640,6 +642,7 @@ func ExampleAlreadyRegisteredError() {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
reqCounter.Inc()
|
||||
}
|
||||
|
||||
func ExampleGatherers() {
|
||||
|
||||
2
vendor/github.com/prometheus/client_golang/prometheus/expvar_collector_test.go
сгенерированный
поставляемый
2
vendor/github.com/prometheus/client_golang/prometheus/expvar_collector_test.go
сгенерированный
поставляемый
@@ -24,7 +24,7 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
func ExampleExpvarCollector() {
|
||||
func ExampleNewExpvarCollector() {
|
||||
expvarCollector := prometheus.NewExpvarCollector(map[string]*prometheus.Desc{
|
||||
"memstats": prometheus.NewDesc(
|
||||
"expvar_memstats",
|
||||
|
||||
13
vendor/github.com/prometheus/client_golang/prometheus/gauge.go
сгенерированный
поставляемый
13
vendor/github.com/prometheus/client_golang/prometheus/gauge.go
сгенерированный
поставляемый
@@ -27,16 +27,21 @@ type Gauge interface {
|
||||
|
||||
// Set sets the Gauge to an arbitrary value.
|
||||
Set(float64)
|
||||
// Inc increments the Gauge by 1.
|
||||
// Inc increments the Gauge by 1. Use Add to increment it by arbitrary
|
||||
// values.
|
||||
Inc()
|
||||
// Dec decrements the Gauge by 1.
|
||||
// Dec decrements the Gauge by 1. Use Sub to decrement it by arbitrary
|
||||
// values.
|
||||
Dec()
|
||||
// Add adds the given value to the Gauge. (The value can be
|
||||
// negative, resulting in a decrease of the Gauge.)
|
||||
// Add adds the given value to the Gauge. (The value can be negative,
|
||||
// resulting in a decrease of the Gauge.)
|
||||
Add(float64)
|
||||
// Sub subtracts the given value from the Gauge. (The value can be
|
||||
// negative, resulting in an increase of the Gauge.)
|
||||
Sub(float64)
|
||||
|
||||
// SetToCurrentTime sets the Gauge to the current Unix time in seconds.
|
||||
SetToCurrentTime()
|
||||
}
|
||||
|
||||
// GaugeOpts is an alias for Opts. See there for doc comments.
|
||||
|
||||
20
vendor/github.com/prometheus/client_golang/prometheus/gauge_test.go
сгенерированный
поставляемый
20
vendor/github.com/prometheus/client_golang/prometheus/gauge_test.go
сгенерированный
поставляемый
@@ -19,6 +19,7 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
"time"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
@@ -180,3 +181,22 @@ func TestGaugeFunc(t *testing.T) {
|
||||
t.Errorf("expected %q, got %q", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGaugeSetCurrentTime(t *testing.T) {
|
||||
g := NewGauge(GaugeOpts{
|
||||
Name: "test_name",
|
||||
Help: "test help",
|
||||
})
|
||||
g.SetToCurrentTime()
|
||||
unixTime := float64(time.Now().Unix())
|
||||
|
||||
m := &dto.Metric{}
|
||||
g.Write(m)
|
||||
|
||||
delta := unixTime - m.GetGauge().GetValue()
|
||||
// This is just a smoke test to make sure SetToCurrentTime is not
|
||||
// totally off. Tests with current time involved are hard...
|
||||
if math.Abs(delta) > 5 {
|
||||
t.Errorf("Gauge set to current time deviates from current time by more than 5s, delta is %f seconds", delta)
|
||||
}
|
||||
}
|
||||
|
||||
43
vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
сгенерированный
поставляемый
43
vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
сгенерированный
поставляемый
@@ -8,8 +8,9 @@ import (
|
||||
)
|
||||
|
||||
type goCollector struct {
|
||||
goroutines Gauge
|
||||
gcDesc *Desc
|
||||
goroutinesDesc *Desc
|
||||
threadsDesc *Desc
|
||||
gcDesc *Desc
|
||||
|
||||
// metrics to describe and collect
|
||||
metrics memStatsMetrics
|
||||
@@ -19,11 +20,14 @@ type goCollector struct {
|
||||
// go process.
|
||||
func NewGoCollector() Collector {
|
||||
return &goCollector{
|
||||
goroutines: NewGauge(GaugeOpts{
|
||||
Namespace: "go",
|
||||
Name: "goroutines",
|
||||
Help: "Number of goroutines that currently exist.",
|
||||
}),
|
||||
goroutinesDesc: NewDesc(
|
||||
"go_goroutines",
|
||||
"Number of goroutines that currently exist.",
|
||||
nil, nil),
|
||||
threadsDesc: NewDesc(
|
||||
"go_threads",
|
||||
"Number of OS threads created",
|
||||
nil, nil),
|
||||
gcDesc: NewDesc(
|
||||
"go_gc_duration_seconds",
|
||||
"A summary of the GC invocation durations.",
|
||||
@@ -48,7 +52,7 @@ func NewGoCollector() Collector {
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("sys_bytes"),
|
||||
"Number of bytes obtained by system. Sum of all system allocations.",
|
||||
"Number of bytes obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
|
||||
@@ -111,12 +115,12 @@ func NewGoCollector() Collector {
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_released_bytes_total"),
|
||||
"Total number of heap bytes released to OS.",
|
||||
memstatNamespace("heap_released_bytes"),
|
||||
"Number of heap bytes released to OS.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
|
||||
valType: CounterValue,
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_objects"),
|
||||
@@ -213,6 +217,14 @@ func NewGoCollector() Collector {
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.LastGC) / 1e9 },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("gc_cpu_fraction"),
|
||||
"The fraction of this program's available CPU time used by the GC since the program started.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction },
|
||||
valType: GaugeValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -224,9 +236,9 @@ func memstatNamespace(s string) string {
|
||||
|
||||
// Describe returns all descriptions of the collector.
|
||||
func (c *goCollector) Describe(ch chan<- *Desc) {
|
||||
ch <- c.goroutines.Desc()
|
||||
ch <- c.goroutinesDesc
|
||||
ch <- c.threadsDesc
|
||||
ch <- c.gcDesc
|
||||
|
||||
for _, i := range c.metrics {
|
||||
ch <- i.desc
|
||||
}
|
||||
@@ -234,8 +246,9 @@ func (c *goCollector) Describe(ch chan<- *Desc) {
|
||||
|
||||
// Collect returns the current state of all metrics of the collector.
|
||||
func (c *goCollector) Collect(ch chan<- Metric) {
|
||||
c.goroutines.Set(float64(runtime.NumGoroutine()))
|
||||
ch <- c.goroutines
|
||||
ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine()))
|
||||
n, _ := runtime.ThreadCreateProfile(nil)
|
||||
ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n))
|
||||
|
||||
var stats debug.GCStats
|
||||
stats.PauseQuantiles = make([]time.Duration, 5)
|
||||
|
||||
55
vendor/github.com/prometheus/client_golang/prometheus/go_collector_test.go
сгенерированный
поставляемый
55
vendor/github.com/prometheus/client_golang/prometheus/go_collector_test.go
сгенерированный
поставляемый
@@ -29,33 +29,36 @@ func TestGoCollector(t *testing.T) {
|
||||
|
||||
for {
|
||||
select {
|
||||
case metric := <-ch:
|
||||
switch m := metric.(type) {
|
||||
// Attention, this also catches Counter...
|
||||
case Gauge:
|
||||
pb := &dto.Metric{}
|
||||
m.Write(pb)
|
||||
if pb.GetGauge() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if old == -1 {
|
||||
old = int(pb.GetGauge().GetValue())
|
||||
close(waitc)
|
||||
continue
|
||||
}
|
||||
|
||||
if diff := int(pb.GetGauge().GetValue()) - old; diff != 1 {
|
||||
// TODO: This is flaky in highly concurrent situations.
|
||||
t.Errorf("want 1 new goroutine, got %d", diff)
|
||||
}
|
||||
|
||||
// GoCollector performs two sends per call.
|
||||
// On line 27 we need to receive the second send
|
||||
// to shut down cleanly.
|
||||
<-ch
|
||||
return
|
||||
case m := <-ch:
|
||||
// m can be Gauge or Counter,
|
||||
// currently just test the go_goroutines Gauge
|
||||
// and ignore others.
|
||||
if m.Desc().fqName != "go_goroutines" {
|
||||
continue
|
||||
}
|
||||
pb := &dto.Metric{}
|
||||
m.Write(pb)
|
||||
if pb.GetGauge() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if old == -1 {
|
||||
old = int(pb.GetGauge().GetValue())
|
||||
close(waitc)
|
||||
continue
|
||||
}
|
||||
|
||||
if diff := int(pb.GetGauge().GetValue()) - old; diff != 1 {
|
||||
// TODO: This is flaky in highly concurrent situations.
|
||||
t.Errorf("want 1 new goroutine, got %d", diff)
|
||||
}
|
||||
|
||||
// GoCollector performs three sends per call.
|
||||
// On line 27 we need to receive the second send
|
||||
// to shut down cleanly.
|
||||
<-ch
|
||||
<-ch
|
||||
return
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("expected collect timed out")
|
||||
}
|
||||
|
||||
280
vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge.go
сгенерированный
поставляемый
Обычный файл
280
vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,280 @@
|
||||
// Copyright 2016 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package graphite provides a bridge to push Prometheus metrics to a Graphite
|
||||
// server.
|
||||
package graphite
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/common/expfmt"
|
||||
"github.com/prometheus/common/model"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultInterval = 15 * time.Second
|
||||
millisecondsPerSecond = 1000
|
||||
)
|
||||
|
||||
// HandlerErrorHandling defines how a Handler serving metrics will handle
|
||||
// errors.
|
||||
type HandlerErrorHandling int
|
||||
|
||||
// These constants cause handlers serving metrics to behave as described if
|
||||
// errors are encountered.
|
||||
const (
|
||||
// Ignore errors and try to push as many metrics to Graphite as possible.
|
||||
ContinueOnError HandlerErrorHandling = iota
|
||||
|
||||
// Abort the push to Graphite upon the first error encountered.
|
||||
AbortOnError
|
||||
)
|
||||
|
||||
// Config defines the Graphite bridge config.
|
||||
type Config struct {
|
||||
// The url to push data to. Required.
|
||||
URL string
|
||||
|
||||
// The prefix for the pushed Graphite metrics. Defaults to empty string.
|
||||
Prefix string
|
||||
|
||||
// The interval to use for pushing data to Graphite. Defaults to 15 seconds.
|
||||
Interval time.Duration
|
||||
|
||||
// The timeout for pushing metrics to Graphite. Defaults to 15 seconds.
|
||||
Timeout time.Duration
|
||||
|
||||
// The Gatherer to use for metrics. Defaults to prometheus.DefaultGatherer.
|
||||
Gatherer prometheus.Gatherer
|
||||
|
||||
// The logger that messages are written to. Defaults to no logging.
|
||||
Logger Logger
|
||||
|
||||
// ErrorHandling defines how errors are handled. Note that errors are
|
||||
// logged regardless of the configured ErrorHandling provided Logger
|
||||
// is not nil.
|
||||
ErrorHandling HandlerErrorHandling
|
||||
}
|
||||
|
||||
// Bridge pushes metrics to the configured Graphite server.
|
||||
type Bridge struct {
|
||||
url string
|
||||
prefix string
|
||||
interval time.Duration
|
||||
timeout time.Duration
|
||||
|
||||
errorHandling HandlerErrorHandling
|
||||
logger Logger
|
||||
|
||||
g prometheus.Gatherer
|
||||
}
|
||||
|
||||
// Logger is the minimal interface Bridge needs for logging. Note that
|
||||
// log.Logger from the standard library implements this interface, and it is
|
||||
// easy to implement by custom loggers, if they don't do so already anyway.
|
||||
type Logger interface {
|
||||
Println(v ...interface{})
|
||||
}
|
||||
|
||||
// NewBridge returns a pointer to a new Bridge struct.
|
||||
func NewBridge(c *Config) (*Bridge, error) {
|
||||
b := &Bridge{}
|
||||
|
||||
if c.URL == "" {
|
||||
return nil, errors.New("missing URL")
|
||||
}
|
||||
b.url = c.URL
|
||||
|
||||
if c.Gatherer == nil {
|
||||
b.g = prometheus.DefaultGatherer
|
||||
} else {
|
||||
b.g = c.Gatherer
|
||||
}
|
||||
|
||||
if c.Logger != nil {
|
||||
b.logger = c.Logger
|
||||
}
|
||||
|
||||
if c.Prefix != "" {
|
||||
b.prefix = c.Prefix
|
||||
}
|
||||
|
||||
var z time.Duration
|
||||
if c.Interval == z {
|
||||
b.interval = defaultInterval
|
||||
} else {
|
||||
b.interval = c.Interval
|
||||
}
|
||||
|
||||
if c.Timeout == z {
|
||||
b.timeout = defaultInterval
|
||||
} else {
|
||||
b.timeout = c.Timeout
|
||||
}
|
||||
|
||||
b.errorHandling = c.ErrorHandling
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Run starts the event loop that pushes Prometheus metrics to Graphite at the
|
||||
// configured interval.
|
||||
func (b *Bridge) Run(ctx context.Context) {
|
||||
ticker := time.NewTicker(b.interval)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
if err := b.Push(); err != nil && b.logger != nil {
|
||||
b.logger.Println("error pushing to Graphite:", err)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Push pushes Prometheus metrics to the configured Graphite server.
|
||||
func (b *Bridge) Push() error {
|
||||
mfs, err := b.g.Gather()
|
||||
if err != nil || len(mfs) == 0 {
|
||||
switch b.errorHandling {
|
||||
case AbortOnError:
|
||||
return err
|
||||
case ContinueOnError:
|
||||
if b.logger != nil {
|
||||
b.logger.Println("continue on error:", err)
|
||||
}
|
||||
default:
|
||||
panic("unrecognized error handling value")
|
||||
}
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("tcp", b.url, b.timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
return writeMetrics(conn, mfs, b.prefix, model.Now())
|
||||
}
|
||||
|
||||
func writeMetrics(w io.Writer, mfs []*dto.MetricFamily, prefix string, now model.Time) error {
|
||||
vec, err := expfmt.ExtractSamples(&expfmt.DecodeOptions{
|
||||
Timestamp: now,
|
||||
}, mfs...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := bufio.NewWriter(w)
|
||||
for _, s := range vec {
|
||||
if err := writeSanitized(buf, prefix); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := buf.WriteByte('.'); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writeMetric(buf, s.Metric); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprintf(buf, " %g %d\n", s.Value, int64(s.Timestamp)/millisecondsPerSecond); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := buf.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeMetric(buf *bufio.Writer, m model.Metric) error {
|
||||
metricName, hasName := m[model.MetricNameLabel]
|
||||
numLabels := len(m) - 1
|
||||
if !hasName {
|
||||
numLabels = len(m)
|
||||
}
|
||||
|
||||
labelStrings := make([]string, 0, numLabels)
|
||||
for label, value := range m {
|
||||
if label != model.MetricNameLabel {
|
||||
labelStrings = append(labelStrings, fmt.Sprintf("%s %s", string(label), string(value)))
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
switch numLabels {
|
||||
case 0:
|
||||
if hasName {
|
||||
return writeSanitized(buf, string(metricName))
|
||||
}
|
||||
default:
|
||||
sort.Strings(labelStrings)
|
||||
if err = writeSanitized(buf, string(metricName)); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, s := range labelStrings {
|
||||
if err = buf.WriteByte('.'); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = writeSanitized(buf, s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeSanitized(buf *bufio.Writer, s string) error {
|
||||
prevUnderscore := false
|
||||
|
||||
for _, c := range s {
|
||||
c = replaceInvalidRune(c)
|
||||
if c == '_' {
|
||||
if prevUnderscore {
|
||||
continue
|
||||
}
|
||||
prevUnderscore = true
|
||||
} else {
|
||||
prevUnderscore = false
|
||||
}
|
||||
if _, err := buf.WriteRune(c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func replaceInvalidRune(c rune) rune {
|
||||
if c == ' ' {
|
||||
return '.'
|
||||
}
|
||||
if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == ':' || (c >= '0' && c <= '9')) {
|
||||
return '_'
|
||||
}
|
||||
return c
|
||||
}
|
||||
309
vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge_test.go
сгенерированный
поставляемый
Обычный файл
309
vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,309 @@
|
||||
package graphite
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
func TestSanitize(t *testing.T) {
|
||||
testCases := []struct {
|
||||
in, out string
|
||||
}{
|
||||
{in: "hello", out: "hello"},
|
||||
{in: "hE/l1o", out: "hE_l1o"},
|
||||
{in: "he,*ll(.o", out: "he_ll_o"},
|
||||
{in: "hello_there%^&", out: "hello_there_"},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
w := bufio.NewWriter(&buf)
|
||||
|
||||
for i, tc := range testCases {
|
||||
if err := writeSanitized(w, tc.in); err != nil {
|
||||
t.Fatalf("write failed: %v", err)
|
||||
}
|
||||
if err := w.Flush(); err != nil {
|
||||
t.Fatalf("flush failed: %v", err)
|
||||
}
|
||||
|
||||
if want, got := tc.out, buf.String(); want != got {
|
||||
t.Fatalf("test case index %d: got sanitized string %s, want %s", i, got, want)
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteSummary(t *testing.T) {
|
||||
sumVec := prometheus.NewSummaryVec(
|
||||
prometheus.SummaryOpts{
|
||||
Name: "name",
|
||||
Help: "docstring",
|
||||
ConstLabels: prometheus.Labels{"constname": "constvalue"},
|
||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||
},
|
||||
[]string{"labelname"},
|
||||
)
|
||||
|
||||
sumVec.WithLabelValues("val1").Observe(float64(10))
|
||||
sumVec.WithLabelValues("val1").Observe(float64(20))
|
||||
sumVec.WithLabelValues("val1").Observe(float64(30))
|
||||
sumVec.WithLabelValues("val2").Observe(float64(20))
|
||||
sumVec.WithLabelValues("val2").Observe(float64(30))
|
||||
sumVec.WithLabelValues("val2").Observe(float64(40))
|
||||
|
||||
reg := prometheus.NewRegistry()
|
||||
reg.MustRegister(sumVec)
|
||||
|
||||
mfs, err := reg.Gather()
|
||||
if err != nil {
|
||||
t.Fatalf("error: %v", err)
|
||||
}
|
||||
|
||||
now := model.Time(1477043083)
|
||||
var buf bytes.Buffer
|
||||
err = writeMetrics(&buf, mfs, "prefix", now)
|
||||
if err != nil {
|
||||
t.Fatalf("error: %v", err)
|
||||
}
|
||||
|
||||
want := `prefix.name.constname.constvalue.labelname.val1.quantile.0_5 20 1477043
|
||||
prefix.name.constname.constvalue.labelname.val1.quantile.0_9 30 1477043
|
||||
prefix.name.constname.constvalue.labelname.val1.quantile.0_99 30 1477043
|
||||
prefix.name_sum.constname.constvalue.labelname.val1 60 1477043
|
||||
prefix.name_count.constname.constvalue.labelname.val1 3 1477043
|
||||
prefix.name.constname.constvalue.labelname.val2.quantile.0_5 30 1477043
|
||||
prefix.name.constname.constvalue.labelname.val2.quantile.0_9 40 1477043
|
||||
prefix.name.constname.constvalue.labelname.val2.quantile.0_99 40 1477043
|
||||
prefix.name_sum.constname.constvalue.labelname.val2 90 1477043
|
||||
prefix.name_count.constname.constvalue.labelname.val2 3 1477043
|
||||
`
|
||||
|
||||
if got := buf.String(); want != got {
|
||||
t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteHistogram(t *testing.T) {
|
||||
histVec := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "name",
|
||||
Help: "docstring",
|
||||
ConstLabels: prometheus.Labels{"constname": "constvalue"},
|
||||
Buckets: []float64{0.01, 0.02, 0.05, 0.1},
|
||||
},
|
||||
[]string{"labelname"},
|
||||
)
|
||||
|
||||
histVec.WithLabelValues("val1").Observe(float64(10))
|
||||
histVec.WithLabelValues("val1").Observe(float64(20))
|
||||
histVec.WithLabelValues("val1").Observe(float64(30))
|
||||
histVec.WithLabelValues("val2").Observe(float64(20))
|
||||
histVec.WithLabelValues("val2").Observe(float64(30))
|
||||
histVec.WithLabelValues("val2").Observe(float64(40))
|
||||
|
||||
reg := prometheus.NewRegistry()
|
||||
reg.MustRegister(histVec)
|
||||
|
||||
mfs, err := reg.Gather()
|
||||
if err != nil {
|
||||
t.Fatalf("error: %v", err)
|
||||
}
|
||||
|
||||
now := model.Time(1477043083)
|
||||
var buf bytes.Buffer
|
||||
err = writeMetrics(&buf, mfs, "prefix", now)
|
||||
if err != nil {
|
||||
t.Fatalf("error: %v", err)
|
||||
}
|
||||
|
||||
want := `prefix.name_bucket.constname.constvalue.labelname.val1.le.0_01 0 1477043
|
||||
prefix.name_bucket.constname.constvalue.labelname.val1.le.0_02 0 1477043
|
||||
prefix.name_bucket.constname.constvalue.labelname.val1.le.0_05 0 1477043
|
||||
prefix.name_bucket.constname.constvalue.labelname.val1.le.0_1 0 1477043
|
||||
prefix.name_sum.constname.constvalue.labelname.val1 60 1477043
|
||||
prefix.name_count.constname.constvalue.labelname.val1 3 1477043
|
||||
prefix.name_bucket.constname.constvalue.labelname.val1.le._Inf 3 1477043
|
||||
prefix.name_bucket.constname.constvalue.labelname.val2.le.0_01 0 1477043
|
||||
prefix.name_bucket.constname.constvalue.labelname.val2.le.0_02 0 1477043
|
||||
prefix.name_bucket.constname.constvalue.labelname.val2.le.0_05 0 1477043
|
||||
prefix.name_bucket.constname.constvalue.labelname.val2.le.0_1 0 1477043
|
||||
prefix.name_sum.constname.constvalue.labelname.val2 90 1477043
|
||||
prefix.name_count.constname.constvalue.labelname.val2 3 1477043
|
||||
prefix.name_bucket.constname.constvalue.labelname.val2.le._Inf 3 1477043
|
||||
`
|
||||
if got := buf.String(); want != got {
|
||||
t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToReader(t *testing.T) {
|
||||
cntVec := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "name",
|
||||
Help: "docstring",
|
||||
ConstLabels: prometheus.Labels{"constname": "constvalue"},
|
||||
},
|
||||
[]string{"labelname"},
|
||||
)
|
||||
cntVec.WithLabelValues("val1").Inc()
|
||||
cntVec.WithLabelValues("val2").Inc()
|
||||
|
||||
reg := prometheus.NewRegistry()
|
||||
reg.MustRegister(cntVec)
|
||||
|
||||
want := `prefix.name.constname.constvalue.labelname.val1 1 1477043
|
||||
prefix.name.constname.constvalue.labelname.val2 1 1477043
|
||||
`
|
||||
mfs, err := reg.Gather()
|
||||
if err != nil {
|
||||
t.Fatalf("error: %v", err)
|
||||
}
|
||||
|
||||
now := model.Time(1477043083)
|
||||
var buf bytes.Buffer
|
||||
err = writeMetrics(&buf, mfs, "prefix", now)
|
||||
if err != nil {
|
||||
t.Fatalf("error: %v", err)
|
||||
}
|
||||
|
||||
if got := buf.String(); want != got {
|
||||
t.Fatalf("wanted \n%s\n, got \n%s\n", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPush(t *testing.T) {
|
||||
reg := prometheus.NewRegistry()
|
||||
cntVec := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "name",
|
||||
Help: "docstring",
|
||||
ConstLabels: prometheus.Labels{"constname": "constvalue"},
|
||||
},
|
||||
[]string{"labelname"},
|
||||
)
|
||||
cntVec.WithLabelValues("val1").Inc()
|
||||
cntVec.WithLabelValues("val2").Inc()
|
||||
reg.MustRegister(cntVec)
|
||||
|
||||
host := "localhost"
|
||||
port := ":56789"
|
||||
b, err := NewBridge(&Config{
|
||||
URL: host + port,
|
||||
Gatherer: reg,
|
||||
Prefix: "prefix",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("error creating bridge: %v", err)
|
||||
}
|
||||
|
||||
nmg, err := newMockGraphite(port)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating mock graphite: %v", err)
|
||||
}
|
||||
defer nmg.Close()
|
||||
|
||||
err = b.Push()
|
||||
if err != nil {
|
||||
t.Fatalf("error pushing: %v", err)
|
||||
}
|
||||
|
||||
wants := []string{
|
||||
"prefix.name.constname.constvalue.labelname.val1 1",
|
||||
"prefix.name.constname.constvalue.labelname.val2 1",
|
||||
}
|
||||
|
||||
select {
|
||||
case got := <-nmg.readc:
|
||||
for _, want := range wants {
|
||||
matched, err := regexp.MatchString(want, got)
|
||||
if err != nil {
|
||||
t.Fatalf("error pushing: %v", err)
|
||||
}
|
||||
if !matched {
|
||||
t.Fatalf("missing metric:\nno match for %s received by server:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
return
|
||||
case err := <-nmg.errc:
|
||||
t.Fatalf("error reading push: %v", err)
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
t.Fatalf("no result from graphite server")
|
||||
}
|
||||
}
|
||||
|
||||
func newMockGraphite(port string) (*mockGraphite, error) {
|
||||
readc := make(chan string)
|
||||
errc := make(chan error)
|
||||
ln, err := net.Listen("tcp", port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
errc <- err
|
||||
}
|
||||
var b bytes.Buffer
|
||||
io.Copy(&b, conn)
|
||||
readc <- b.String()
|
||||
}()
|
||||
|
||||
return &mockGraphite{
|
||||
readc: readc,
|
||||
errc: errc,
|
||||
Listener: ln,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type mockGraphite struct {
|
||||
readc chan string
|
||||
errc chan error
|
||||
|
||||
net.Listener
|
||||
}
|
||||
|
||||
func ExampleBridge() {
|
||||
b, err := NewBridge(&Config{
|
||||
URL: "graphite.example.org:3099",
|
||||
Gatherer: prometheus.DefaultGatherer,
|
||||
Prefix: "prefix",
|
||||
Interval: 15 * time.Second,
|
||||
Timeout: 10 * time.Second,
|
||||
ErrorHandling: AbortOnError,
|
||||
Logger: log.New(os.Stdout, "graphite bridge: ", log.Lshortfile),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
// Start something in a goroutine that uses metrics.
|
||||
}()
|
||||
|
||||
// Push initial metrics to Graphite. Fail fast if the push fails.
|
||||
if err := b.Push(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create a Context to control stopping the Run() loop that pushes
|
||||
// metrics to Graphite.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Start pushing metrics to Graphite in the Run() loop.
|
||||
b.Run(ctx)
|
||||
}
|
||||
24
vendor/github.com/prometheus/client_golang/prometheus/histogram.go
сгенерированный
поставляемый
24
vendor/github.com/prometheus/client_golang/prometheus/histogram.go
сгенерированный
поставляемый
@@ -308,23 +308,23 @@ func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
|
||||
}
|
||||
|
||||
// GetMetricWithLabelValues replaces the method of the same name in
|
||||
// MetricVec. The difference is that this method returns a Histogram and not a
|
||||
// Metric so that no type conversion is required.
|
||||
func (m *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Histogram, error) {
|
||||
// MetricVec. The difference is that this method returns an Observer and not a
|
||||
// Metric so that no type conversion to an Observer is required.
|
||||
func (m *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
|
||||
metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||
if metric != nil {
|
||||
return metric.(Histogram), err
|
||||
return metric.(Observer), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetMetricWith replaces the method of the same name in MetricVec. The
|
||||
// difference is that this method returns a Histogram and not a Metric so that no
|
||||
// type conversion is required.
|
||||
func (m *HistogramVec) GetMetricWith(labels Labels) (Histogram, error) {
|
||||
// difference is that this method returns an Observer and not a Metric so that no
|
||||
// type conversion to an Observer is required.
|
||||
func (m *HistogramVec) GetMetricWith(labels Labels) (Observer, error) {
|
||||
metric, err := m.MetricVec.GetMetricWith(labels)
|
||||
if metric != nil {
|
||||
return metric.(Histogram), err
|
||||
return metric.(Observer), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@@ -333,15 +333,15 @@ func (m *HistogramVec) GetMetricWith(labels Labels) (Histogram, error) {
|
||||
// GetMetricWithLabelValues would have returned an error. By not returning an
|
||||
// error, WithLabelValues allows shortcuts like
|
||||
// myVec.WithLabelValues("404", "GET").Observe(42.21)
|
||||
func (m *HistogramVec) WithLabelValues(lvs ...string) Histogram {
|
||||
return m.MetricVec.WithLabelValues(lvs...).(Histogram)
|
||||
func (m *HistogramVec) WithLabelValues(lvs ...string) Observer {
|
||||
return m.MetricVec.WithLabelValues(lvs...).(Observer)
|
||||
}
|
||||
|
||||
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
|
||||
// returned an error. By not returning an error, With allows shortcuts like
|
||||
// myVec.With(Labels{"code": "404", "method": "GET"}).Observe(42.21)
|
||||
func (m *HistogramVec) With(labels Labels) Histogram {
|
||||
return m.MetricVec.With(labels).(Histogram)
|
||||
func (m *HistogramVec) With(labels Labels) Observer {
|
||||
return m.MetricVec.With(labels).(Observer)
|
||||
}
|
||||
|
||||
type constHistogram struct {
|
||||
|
||||
24
vendor/github.com/prometheus/client_golang/prometheus/histogram_test.go
сгенерированный
поставляемый
24
vendor/github.com/prometheus/client_golang/prometheus/histogram_test.go
сгенерированный
поставляемый
@@ -119,6 +119,28 @@ func BenchmarkHistogramWrite8(b *testing.B) {
|
||||
benchmarkHistogramWrite(8, b)
|
||||
}
|
||||
|
||||
func TestHistogramNonMonotonicBuckets(t *testing.T) {
|
||||
testCases := map[string][]float64{
|
||||
"not strictly monotonic": {1, 2, 2, 3},
|
||||
"not monotonic at all": {1, 2, 4, 3, 5},
|
||||
"have +Inf in the middle": {1, 2, math.Inf(+1), 3},
|
||||
}
|
||||
for name, buckets := range testCases {
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("Buckets %v are %s but NewHistogram did not panic.", buckets, name)
|
||||
}
|
||||
}()
|
||||
_ = NewHistogram(HistogramOpts{
|
||||
Name: "test_histogram",
|
||||
Help: "helpless",
|
||||
Buckets: buckets,
|
||||
})
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// Intentionally adding +Inf here to test if that case is handled correctly.
|
||||
// Also, getCumulativeCounts depends on it.
|
||||
var testBuckets = []float64{-2, -1, -0.5, 0, 0.5, 1, 2, math.Inf(+1)}
|
||||
@@ -264,7 +286,7 @@ func TestHistogramVecConcurrency(t *testing.T) {
|
||||
for i := 0; i < vecLength; i++ {
|
||||
m := &dto.Metric{}
|
||||
s := his.WithLabelValues(string('A' + i))
|
||||
s.Write(m)
|
||||
s.(Histogram).Write(m)
|
||||
|
||||
if got, want := len(m.Histogram.Bucket), len(testBuckets)-1; got != want {
|
||||
t.Errorf("got %d buckets in protobuf, want %d", got, want)
|
||||
|
||||
108
vendor/github.com/prometheus/client_golang/prometheus/http.go
сгенерированный
поставляемый
108
vendor/github.com/prometheus/client_golang/prometheus/http.go
сгенерированный
поставляемый
@@ -62,7 +62,8 @@ func giveBuf(buf *bytes.Buffer) {
|
||||
//
|
||||
// Deprecated: Please note the issues described in the doc comment of
|
||||
// InstrumentHandler. You might want to consider using promhttp.Handler instead
|
||||
// (which is non instrumented).
|
||||
// (which is not instrumented, but can be instrumented with the tooling provided
|
||||
// in package promhttp).
|
||||
func Handler() http.Handler {
|
||||
return InstrumentHandler("prometheus", UninstrumentedHandler())
|
||||
}
|
||||
@@ -158,7 +159,8 @@ func nowSeries(t ...time.Time) nower {
|
||||
// value. http_requests_total is a metric vector partitioned by HTTP method
|
||||
// (label name "method") and HTTP status code (label name "code").
|
||||
//
|
||||
// Deprecated: InstrumentHandler has several issues:
|
||||
// Deprecated: InstrumentHandler has several issues. Use the tooling provided in
|
||||
// package promhttp instead. The issues are the following:
|
||||
//
|
||||
// - It uses Summaries rather than Histograms. Summaries are not useful if
|
||||
// aggregation across multiple instances is required.
|
||||
@@ -172,9 +174,8 @@ func nowSeries(t ...time.Time) nower {
|
||||
// httputil.ReverseProxy is a prominent example for a handler
|
||||
// performing such writes.
|
||||
//
|
||||
// Upcoming versions of this package will provide ways of instrumenting HTTP
|
||||
// handlers that are more flexible and have fewer issues. Please prefer direct
|
||||
// instrumentation in the meantime.
|
||||
// - It has additional issues with HTTP/2, cf.
|
||||
// https://github.com/prometheus/client_golang/issues/272.
|
||||
func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFunc {
|
||||
return InstrumentHandlerFunc(handlerName, handler.ServeHTTP)
|
||||
}
|
||||
@@ -184,12 +185,13 @@ func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFun
|
||||
// issues).
|
||||
//
|
||||
// Deprecated: InstrumentHandlerFunc is deprecated for the same reasons as
|
||||
// InstrumentHandler is.
|
||||
// InstrumentHandler is. Use the tooling provided in package promhttp instead.
|
||||
func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||
return InstrumentHandlerFuncWithOpts(
|
||||
SummaryOpts{
|
||||
Subsystem: "http",
|
||||
ConstLabels: Labels{"handler": handlerName},
|
||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||
},
|
||||
handlerFunc,
|
||||
)
|
||||
@@ -222,7 +224,7 @@ func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWri
|
||||
// SummaryOpts.
|
||||
//
|
||||
// Deprecated: InstrumentHandlerWithOpts is deprecated for the same reasons as
|
||||
// InstrumentHandler is.
|
||||
// InstrumentHandler is. Use the tooling provided in package promhttp instead.
|
||||
func InstrumentHandlerWithOpts(opts SummaryOpts, handler http.Handler) http.HandlerFunc {
|
||||
return InstrumentHandlerFuncWithOpts(opts, handler.ServeHTTP)
|
||||
}
|
||||
@@ -233,7 +235,7 @@ func InstrumentHandlerWithOpts(opts SummaryOpts, handler http.Handler) http.Hand
|
||||
// SummaryOpts are used.
|
||||
//
|
||||
// Deprecated: InstrumentHandlerFuncWithOpts is deprecated for the same reasons
|
||||
// as InstrumentHandler is.
|
||||
// as InstrumentHandler is. Use the tooling provided in package promhttp instead.
|
||||
func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||
reqCnt := NewCounterVec(
|
||||
CounterOpts{
|
||||
@@ -245,34 +247,52 @@ func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.Respo
|
||||
},
|
||||
instLabels,
|
||||
)
|
||||
if err := Register(reqCnt); err != nil {
|
||||
if are, ok := err.(AlreadyRegisteredError); ok {
|
||||
reqCnt = are.ExistingCollector.(*CounterVec)
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
opts.Name = "request_duration_microseconds"
|
||||
opts.Help = "The HTTP request latencies in microseconds."
|
||||
reqDur := NewSummary(opts)
|
||||
if err := Register(reqDur); err != nil {
|
||||
if are, ok := err.(AlreadyRegisteredError); ok {
|
||||
reqDur = are.ExistingCollector.(Summary)
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
opts.Name = "request_size_bytes"
|
||||
opts.Help = "The HTTP request sizes in bytes."
|
||||
reqSz := NewSummary(opts)
|
||||
if err := Register(reqSz); err != nil {
|
||||
if are, ok := err.(AlreadyRegisteredError); ok {
|
||||
reqSz = are.ExistingCollector.(Summary)
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
opts.Name = "response_size_bytes"
|
||||
opts.Help = "The HTTP response sizes in bytes."
|
||||
resSz := NewSummary(opts)
|
||||
|
||||
regReqCnt := MustRegisterOrGet(reqCnt).(*CounterVec)
|
||||
regReqDur := MustRegisterOrGet(reqDur).(Summary)
|
||||
regReqSz := MustRegisterOrGet(reqSz).(Summary)
|
||||
regResSz := MustRegisterOrGet(resSz).(Summary)
|
||||
if err := Register(resSz); err != nil {
|
||||
if are, ok := err.(AlreadyRegisteredError); ok {
|
||||
resSz = are.ExistingCollector.(Summary)
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
now := time.Now()
|
||||
|
||||
delegate := &responseWriterDelegator{ResponseWriter: w}
|
||||
out := make(chan int)
|
||||
urlLen := 0
|
||||
if r.URL != nil {
|
||||
urlLen = len(r.URL.String())
|
||||
}
|
||||
go computeApproximateRequestSize(r, out, urlLen)
|
||||
out := computeApproximateRequestSize(r)
|
||||
|
||||
_, cn := w.(http.CloseNotifier)
|
||||
_, fl := w.(http.Flusher)
|
||||
@@ -290,30 +310,44 @@ func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.Respo
|
||||
|
||||
method := sanitizeMethod(r.Method)
|
||||
code := sanitizeCode(delegate.status)
|
||||
regReqCnt.WithLabelValues(method, code).Inc()
|
||||
regReqDur.Observe(elapsed)
|
||||
regResSz.Observe(float64(delegate.written))
|
||||
regReqSz.Observe(float64(<-out))
|
||||
reqCnt.WithLabelValues(method, code).Inc()
|
||||
reqDur.Observe(elapsed)
|
||||
resSz.Observe(float64(delegate.written))
|
||||
reqSz.Observe(float64(<-out))
|
||||
})
|
||||
}
|
||||
|
||||
func computeApproximateRequestSize(r *http.Request, out chan int, s int) {
|
||||
s += len(r.Method)
|
||||
s += len(r.Proto)
|
||||
for name, values := range r.Header {
|
||||
s += len(name)
|
||||
for _, value := range values {
|
||||
s += len(value)
|
||||
func computeApproximateRequestSize(r *http.Request) <-chan int {
|
||||
// Get URL length in current go routine for avoiding a race condition.
|
||||
// HandlerFunc that runs in parallel may modify the URL.
|
||||
s := 0
|
||||
if r.URL != nil {
|
||||
s += len(r.URL.String())
|
||||
}
|
||||
|
||||
out := make(chan int, 1)
|
||||
|
||||
go func() {
|
||||
s += len(r.Method)
|
||||
s += len(r.Proto)
|
||||
for name, values := range r.Header {
|
||||
s += len(name)
|
||||
for _, value := range values {
|
||||
s += len(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
s += len(r.Host)
|
||||
s += len(r.Host)
|
||||
|
||||
// N.B. r.Form and r.MultipartForm are assumed to be included in r.URL.
|
||||
// N.B. r.Form and r.MultipartForm are assumed to be included in r.URL.
|
||||
|
||||
if r.ContentLength != -1 {
|
||||
s += int(r.ContentLength)
|
||||
}
|
||||
out <- s
|
||||
if r.ContentLength != -1 {
|
||||
s += int(r.ContentLength)
|
||||
}
|
||||
out <- s
|
||||
close(out)
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
type responseWriterDelegator struct {
|
||||
|
||||
43
vendor/github.com/prometheus/client_golang/prometheus/http_test.go
сгенерированный
поставляемый
43
vendor/github.com/prometheus/client_golang/prometheus/http_test.go
сгенерированный
поставляемый
@@ -44,9 +44,10 @@ func TestInstrumentHandler(t *testing.T) {
|
||||
opts := SummaryOpts{
|
||||
Subsystem: "http",
|
||||
ConstLabels: Labels{"handler": "test-handler"},
|
||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||
}
|
||||
|
||||
reqCnt := MustRegisterOrGet(NewCounterVec(
|
||||
reqCnt := NewCounterVec(
|
||||
CounterOpts{
|
||||
Namespace: opts.Namespace,
|
||||
Subsystem: opts.Subsystem,
|
||||
@@ -55,19 +56,51 @@ func TestInstrumentHandler(t *testing.T) {
|
||||
ConstLabels: opts.ConstLabels,
|
||||
},
|
||||
instLabels,
|
||||
)).(*CounterVec)
|
||||
)
|
||||
err := Register(reqCnt)
|
||||
if err == nil {
|
||||
t.Fatal("expected reqCnt to be registered already")
|
||||
}
|
||||
if are, ok := err.(AlreadyRegisteredError); ok {
|
||||
reqCnt = are.ExistingCollector.(*CounterVec)
|
||||
} else {
|
||||
t.Fatal("unexpected registration error:", err)
|
||||
}
|
||||
|
||||
opts.Name = "request_duration_microseconds"
|
||||
opts.Help = "The HTTP request latencies in microseconds."
|
||||
reqDur := MustRegisterOrGet(NewSummary(opts)).(Summary)
|
||||
reqDur := NewSummary(opts)
|
||||
err = Register(reqDur)
|
||||
if err == nil {
|
||||
t.Fatal("expected reqDur to be registered already")
|
||||
}
|
||||
if are, ok := err.(AlreadyRegisteredError); ok {
|
||||
reqDur = are.ExistingCollector.(Summary)
|
||||
} else {
|
||||
t.Fatal("unexpected registration error:", err)
|
||||
}
|
||||
|
||||
opts.Name = "request_size_bytes"
|
||||
opts.Help = "The HTTP request sizes in bytes."
|
||||
MustRegisterOrGet(NewSummary(opts))
|
||||
reqSz := NewSummary(opts)
|
||||
err = Register(reqSz)
|
||||
if err == nil {
|
||||
t.Fatal("expected reqSz to be registered already")
|
||||
}
|
||||
if _, ok := err.(AlreadyRegisteredError); !ok {
|
||||
t.Fatal("unexpected registration error:", err)
|
||||
}
|
||||
|
||||
opts.Name = "response_size_bytes"
|
||||
opts.Help = "The HTTP response sizes in bytes."
|
||||
MustRegisterOrGet(NewSummary(opts))
|
||||
resSz := NewSummary(opts)
|
||||
err = Register(resSz)
|
||||
if err == nil {
|
||||
t.Fatal("expected resSz to be registered already")
|
||||
}
|
||||
if _, ok := err.(AlreadyRegisteredError); !ok {
|
||||
t.Fatal("unexpected registration error:", err)
|
||||
}
|
||||
|
||||
reqCnt.Reset()
|
||||
|
||||
|
||||
50
vendor/github.com/prometheus/client_golang/prometheus/observer.go
сгенерированный
поставляемый
Обычный файл
50
vendor/github.com/prometheus/client_golang/prometheus/observer.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,50 @@
|
||||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package prometheus
|
||||
|
||||
// Observer is the interface that wraps the Observe method, which is used by
|
||||
// Histogram and Summary to add observations.
|
||||
type Observer interface {
|
||||
Observe(float64)
|
||||
}
|
||||
|
||||
// The ObserverFunc type is an adapter to allow the use of ordinary
|
||||
// functions as Observers. If f is a function with the appropriate
|
||||
// signature, ObserverFunc(f) is an Observer that calls f.
|
||||
//
|
||||
// This adapter is usually used in connection with the Timer type, and there are
|
||||
// two general use cases:
|
||||
//
|
||||
// The most common one is to use a Gauge as the Observer for a Timer.
|
||||
// See the "Gauge" Timer example.
|
||||
//
|
||||
// The more advanced use case is to create a function that dynamically decides
|
||||
// which Observer to use for observing the duration. See the "Complex" Timer
|
||||
// example.
|
||||
type ObserverFunc func(float64)
|
||||
|
||||
// Observe calls f(value). It implements Observer.
|
||||
func (f ObserverFunc) Observe(value float64) {
|
||||
f(value)
|
||||
}
|
||||
|
||||
// ObserverVec is an interface implemented by `HistogramVec` and `SummaryVec`.
|
||||
type ObserverVec interface {
|
||||
GetMetricWith(Labels) (Observer, error)
|
||||
GetMetricWithLabelValues(lvs ...string) (Observer, error)
|
||||
With(Labels) Observer
|
||||
WithLabelValues(...string) Observer
|
||||
|
||||
Collector
|
||||
}
|
||||
104
vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
сгенерированный
поставляемый
104
vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
сгенерированный
поставляемый
@@ -19,10 +19,10 @@ type processCollector struct {
|
||||
pid int
|
||||
collectFn func(chan<- Metric)
|
||||
pidFn func() (int, error)
|
||||
cpuTotal Counter
|
||||
openFDs, maxFDs Gauge
|
||||
vsize, rss Gauge
|
||||
startTime Gauge
|
||||
cpuTotal *Desc
|
||||
openFDs, maxFDs *Desc
|
||||
vsize, rss *Desc
|
||||
startTime *Desc
|
||||
}
|
||||
|
||||
// NewProcessCollector returns a collector which exports the current state of
|
||||
@@ -44,40 +44,45 @@ func NewProcessCollectorPIDFn(
|
||||
pidFn func() (int, error),
|
||||
namespace string,
|
||||
) Collector {
|
||||
ns := ""
|
||||
if len(namespace) > 0 {
|
||||
ns = namespace + "_"
|
||||
}
|
||||
|
||||
c := processCollector{
|
||||
pidFn: pidFn,
|
||||
collectFn: func(chan<- Metric) {},
|
||||
|
||||
cpuTotal: NewCounter(CounterOpts{
|
||||
Namespace: namespace,
|
||||
Name: "process_cpu_seconds_total",
|
||||
Help: "Total user and system CPU time spent in seconds.",
|
||||
}),
|
||||
openFDs: NewGauge(GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Name: "process_open_fds",
|
||||
Help: "Number of open file descriptors.",
|
||||
}),
|
||||
maxFDs: NewGauge(GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Name: "process_max_fds",
|
||||
Help: "Maximum number of open file descriptors.",
|
||||
}),
|
||||
vsize: NewGauge(GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Name: "process_virtual_memory_bytes",
|
||||
Help: "Virtual memory size in bytes.",
|
||||
}),
|
||||
rss: NewGauge(GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Name: "process_resident_memory_bytes",
|
||||
Help: "Resident memory size in bytes.",
|
||||
}),
|
||||
startTime: NewGauge(GaugeOpts{
|
||||
Namespace: namespace,
|
||||
Name: "process_start_time_seconds",
|
||||
Help: "Start time of the process since unix epoch in seconds.",
|
||||
}),
|
||||
cpuTotal: NewDesc(
|
||||
ns+"process_cpu_seconds_total",
|
||||
"Total user and system CPU time spent in seconds.",
|
||||
nil, nil,
|
||||
),
|
||||
openFDs: NewDesc(
|
||||
ns+"process_open_fds",
|
||||
"Number of open file descriptors.",
|
||||
nil, nil,
|
||||
),
|
||||
maxFDs: NewDesc(
|
||||
ns+"process_max_fds",
|
||||
"Maximum number of open file descriptors.",
|
||||
nil, nil,
|
||||
),
|
||||
vsize: NewDesc(
|
||||
ns+"process_virtual_memory_bytes",
|
||||
"Virtual memory size in bytes.",
|
||||
nil, nil,
|
||||
),
|
||||
rss: NewDesc(
|
||||
ns+"process_resident_memory_bytes",
|
||||
"Resident memory size in bytes.",
|
||||
nil, nil,
|
||||
),
|
||||
startTime: NewDesc(
|
||||
ns+"process_start_time_seconds",
|
||||
"Start time of the process since unix epoch in seconds.",
|
||||
nil, nil,
|
||||
),
|
||||
}
|
||||
|
||||
// Set up process metric collection if supported by the runtime.
|
||||
@@ -90,12 +95,12 @@ func NewProcessCollectorPIDFn(
|
||||
|
||||
// Describe returns all descriptions of the collector.
|
||||
func (c *processCollector) Describe(ch chan<- *Desc) {
|
||||
ch <- c.cpuTotal.Desc()
|
||||
ch <- c.openFDs.Desc()
|
||||
ch <- c.maxFDs.Desc()
|
||||
ch <- c.vsize.Desc()
|
||||
ch <- c.rss.Desc()
|
||||
ch <- c.startTime.Desc()
|
||||
ch <- c.cpuTotal
|
||||
ch <- c.openFDs
|
||||
ch <- c.maxFDs
|
||||
ch <- c.vsize
|
||||
ch <- c.rss
|
||||
ch <- c.startTime
|
||||
}
|
||||
|
||||
// Collect returns the current state of all metrics of the collector.
|
||||
@@ -117,26 +122,19 @@ func (c *processCollector) processCollect(ch chan<- Metric) {
|
||||
}
|
||||
|
||||
if stat, err := p.NewStat(); err == nil {
|
||||
c.cpuTotal.Set(stat.CPUTime())
|
||||
ch <- c.cpuTotal
|
||||
c.vsize.Set(float64(stat.VirtualMemory()))
|
||||
ch <- c.vsize
|
||||
c.rss.Set(float64(stat.ResidentMemory()))
|
||||
ch <- c.rss
|
||||
|
||||
ch <- MustNewConstMetric(c.cpuTotal, CounterValue, stat.CPUTime())
|
||||
ch <- MustNewConstMetric(c.vsize, GaugeValue, float64(stat.VirtualMemory()))
|
||||
ch <- MustNewConstMetric(c.rss, GaugeValue, float64(stat.ResidentMemory()))
|
||||
if startTime, err := stat.StartTime(); err == nil {
|
||||
c.startTime.Set(startTime)
|
||||
ch <- c.startTime
|
||||
ch <- MustNewConstMetric(c.startTime, GaugeValue, startTime)
|
||||
}
|
||||
}
|
||||
|
||||
if fds, err := p.FileDescriptorsLen(); err == nil {
|
||||
c.openFDs.Set(float64(fds))
|
||||
ch <- c.openFDs
|
||||
ch <- MustNewConstMetric(c.openFDs, GaugeValue, float64(fds))
|
||||
}
|
||||
|
||||
if limits, err := p.NewLimits(); err == nil {
|
||||
c.maxFDs.Set(float64(limits.OpenFiles))
|
||||
ch <- c.maxFDs
|
||||
ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(limits.OpenFiles))
|
||||
}
|
||||
}
|
||||
|
||||
24
vendor/github.com/prometheus/client_golang/prometheus/process_collector_test.go
сгенерированный
поставляемый
24
vendor/github.com/prometheus/client_golang/prometheus/process_collector_test.go
сгенерированный
поставляемый
@@ -38,18 +38,18 @@ func TestProcessCollector(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, re := range []*regexp.Regexp{
|
||||
regexp.MustCompile("process_cpu_seconds_total [0-9]"),
|
||||
regexp.MustCompile("process_max_fds [1-9]"),
|
||||
regexp.MustCompile("process_open_fds [1-9]"),
|
||||
regexp.MustCompile("process_virtual_memory_bytes [1-9]"),
|
||||
regexp.MustCompile("process_resident_memory_bytes [1-9]"),
|
||||
regexp.MustCompile("process_start_time_seconds [0-9.]{10,}"),
|
||||
regexp.MustCompile("foobar_process_cpu_seconds_total [0-9]"),
|
||||
regexp.MustCompile("foobar_process_max_fds [1-9]"),
|
||||
regexp.MustCompile("foobar_process_open_fds [1-9]"),
|
||||
regexp.MustCompile("foobar_process_virtual_memory_bytes [1-9]"),
|
||||
regexp.MustCompile("foobar_process_resident_memory_bytes [1-9]"),
|
||||
regexp.MustCompile("foobar_process_start_time_seconds [0-9.]{10,}"),
|
||||
regexp.MustCompile("\nprocess_cpu_seconds_total [0-9]"),
|
||||
regexp.MustCompile("\nprocess_max_fds [1-9]"),
|
||||
regexp.MustCompile("\nprocess_open_fds [1-9]"),
|
||||
regexp.MustCompile("\nprocess_virtual_memory_bytes [1-9]"),
|
||||
regexp.MustCompile("\nprocess_resident_memory_bytes [1-9]"),
|
||||
regexp.MustCompile("\nprocess_start_time_seconds [0-9.]{10,}"),
|
||||
regexp.MustCompile("\nfoobar_process_cpu_seconds_total [0-9]"),
|
||||
regexp.MustCompile("\nfoobar_process_max_fds [1-9]"),
|
||||
regexp.MustCompile("\nfoobar_process_open_fds [1-9]"),
|
||||
regexp.MustCompile("\nfoobar_process_virtual_memory_bytes [1-9]"),
|
||||
regexp.MustCompile("\nfoobar_process_resident_memory_bytes [1-9]"),
|
||||
regexp.MustCompile("\nfoobar_process_start_time_seconds [0-9.]{10,}"),
|
||||
} {
|
||||
if !re.Match(buf.Bytes()) {
|
||||
t.Errorf("want body to match %s\n%s", re, buf.String())
|
||||
|
||||
35
vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_7.go
сгенерированный
поставляемый
Обычный файл
35
vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_7.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,35 @@
|
||||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !go1.8
|
||||
|
||||
package promhttp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func newDelegator(w http.ResponseWriter) delegator {
|
||||
d := &responseWriterDelegator{ResponseWriter: w}
|
||||
|
||||
_, cn := w.(http.CloseNotifier)
|
||||
_, fl := w.(http.Flusher)
|
||||
_, hj := w.(http.Hijacker)
|
||||
_, rf := w.(io.ReaderFrom)
|
||||
if cn && fl && hj && rf {
|
||||
return &fancyDelegator{d}
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
70
vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go
сгенерированный
поставляемый
Обычный файл
70
vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,70 @@
|
||||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package promhttp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// newDelegator handles the four different methods of upgrading a
|
||||
// http.ResponseWriter to delegator.
|
||||
func newDelegator(w http.ResponseWriter) delegator {
|
||||
d := &responseWriterDelegator{ResponseWriter: w}
|
||||
|
||||
_, cn := w.(http.CloseNotifier)
|
||||
_, fl := w.(http.Flusher)
|
||||
_, hj := w.(http.Hijacker)
|
||||
_, ps := w.(http.Pusher)
|
||||
_, rf := w.(io.ReaderFrom)
|
||||
|
||||
// Check for the four most common combination of interfaces a
|
||||
// http.ResponseWriter might implement.
|
||||
switch {
|
||||
case cn && fl && hj && rf && ps:
|
||||
// All interfaces.
|
||||
return &fancyPushDelegator{
|
||||
fancyDelegator: &fancyDelegator{d},
|
||||
p: &pushDelegator{d},
|
||||
}
|
||||
case cn && fl && hj && rf:
|
||||
// All interfaces, except http.Pusher.
|
||||
return &fancyDelegator{d}
|
||||
case ps:
|
||||
// Just http.Pusher.
|
||||
return &pushDelegator{d}
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
type fancyPushDelegator struct {
|
||||
p *pushDelegator
|
||||
|
||||
*fancyDelegator
|
||||
}
|
||||
|
||||
func (f *fancyPushDelegator) Push(target string, opts *http.PushOptions) error {
|
||||
return f.p.Push(target, opts)
|
||||
}
|
||||
|
||||
type pushDelegator struct {
|
||||
*responseWriterDelegator
|
||||
}
|
||||
|
||||
func (f *pushDelegator) Push(target string, opts *http.PushOptions) error {
|
||||
return f.ResponseWriter.(http.Pusher).Push(target, opts)
|
||||
}
|
||||
29
vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
сгенерированный
поставляемый
29
vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
сгенерированный
поставляемый
@@ -11,21 +11,24 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Copyright (c) 2013, The Prometheus Authors
|
||||
// All rights reserved.
|
||||
// Package promhttp provides tooling around HTTP servers and clients.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
// Package promhttp contains functions to create http.Handler instances to
|
||||
// expose Prometheus metrics via HTTP. In later versions of this package, it
|
||||
// will also contain tooling to instrument instances of http.Handler and
|
||||
// http.RoundTripper.
|
||||
// First, the package allows the creation of http.Handler instances to expose
|
||||
// Prometheus metrics via HTTP. promhttp.Handler acts on the
|
||||
// prometheus.DefaultGatherer. With HandlerFor, you can create a handler for a
|
||||
// custom registry or anything that implements the Gatherer interface. It also
|
||||
// allows the creation of handlers that act differently on errors or allow to
|
||||
// log errors.
|
||||
//
|
||||
// promhttp.Handler acts on the prometheus.DefaultGatherer. With HandlerFor,
|
||||
// you can create a handler for a custom registry or anything that implements
|
||||
// the Gatherer interface. It also allows to create handlers that act
|
||||
// differently on errors or allow to log errors.
|
||||
// Second, the package provides tooling to instrument instances of http.Handler
|
||||
// via middleware. Middleware wrappers follow the naming scheme
|
||||
// InstrumentHandlerX, where X describes the intended use of the middleware.
|
||||
// See each function's doc comment for specific details.
|
||||
//
|
||||
// Finally, the package allows for an http.RoundTripper to be instrumented via
|
||||
// middleware. Middleware wrappers follow the naming scheme
|
||||
// InstrumentRoundTripperX, where X describes the intended use of the
|
||||
// middleware. See each function's doc comment for specific details.
|
||||
package promhttp
|
||||
|
||||
import (
|
||||
|
||||
6
vendor/github.com/prometheus/client_golang/prometheus/promhttp/http_test.go
сгенерированный
поставляемый
6
vendor/github.com/prometheus/client_golang/prometheus/promhttp/http_test.go
сгенерированный
поставляемый
@@ -11,12 +11,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Copyright (c) 2013, The Prometheus Authors
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
package promhttp
|
||||
|
||||
import (
|
||||
|
||||
95
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
сгенерированный
поставляемый
Обычный файл
95
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,95 @@
|
||||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package promhttp
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// The RoundTripperFunc type is an adapter to allow the use of ordinary
|
||||
// functions as RoundTrippers. If f is a function with the appropriate
|
||||
// signature, RountTripperFunc(f) is a RoundTripper that calls f.
|
||||
type RoundTripperFunc func(req *http.Request) (*http.Response, error)
|
||||
|
||||
// RoundTrip implements the RoundTripper interface.
|
||||
func (rt RoundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||
return rt(r)
|
||||
}
|
||||
|
||||
// InstrumentRoundTripperInFlight is a middleware that wraps the provided
|
||||
// http.RoundTripper. It sets the provided prometheus.Gauge to the number of
|
||||
// requests currently handled by the wrapped http.RoundTripper.
|
||||
//
|
||||
// See the example for ExampleInstrumentRoundTripperDuration for example usage.
|
||||
func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripper) RoundTripperFunc {
|
||||
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
||||
gauge.Inc()
|
||||
defer gauge.Dec()
|
||||
return next.RoundTrip(r)
|
||||
})
|
||||
}
|
||||
|
||||
// InstrumentRoundTripperCounter is a middleware that wraps the provided
|
||||
// http.RoundTripper to observe the request result with the provided CounterVec.
|
||||
// The CounterVec must have zero, one, or two labels. The only allowed label
|
||||
// names are "code" and "method". The function panics if any other instance
|
||||
// labels are provided. Partitioning of the CounterVec happens by HTTP status
|
||||
// code and/or HTTP method if the respective instance label names are present
|
||||
// in the CounterVec. For unpartitioned counting, use a CounterVec with
|
||||
// zero labels.
|
||||
//
|
||||
// If the wrapped RoundTripper panics or returns a non-nil error, the Counter
|
||||
// is not incremented.
|
||||
//
|
||||
// See the example for ExampleInstrumentRoundTripperDuration for example usage.
|
||||
func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper) RoundTripperFunc {
|
||||
code, method := checkLabels(counter)
|
||||
|
||||
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
||||
resp, err := next.RoundTrip(r)
|
||||
if err == nil {
|
||||
counter.With(labels(code, method, r.Method, resp.StatusCode)).Inc()
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
|
||||
// InstrumentRoundTripperDuration is a middleware that wraps the provided
|
||||
// http.RoundTripper to observe the request duration with the provided ObserverVec.
|
||||
// The ObserverVec must have zero, one, or two labels. The only allowed label
|
||||
// names are "code" and "method". The function panics if any other instance
|
||||
// labels are provided. The Observe method of the Observer in the ObserverVec
|
||||
// is called with the request duration in seconds. Partitioning happens by HTTP
|
||||
// status code and/or HTTP method if the respective instance label names are
|
||||
// present in the ObserverVec. For unpartitioned observations, use an
|
||||
// ObserverVec with zero labels. Note that partitioning of Histograms is
|
||||
// expensive and should be used judiciously.
|
||||
//
|
||||
// If the wrapped RoundTripper panics or returns a non-nil error, no values are
|
||||
// reported.
|
||||
func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper) RoundTripperFunc {
|
||||
code, method := checkLabels(obs)
|
||||
|
||||
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
||||
start := time.Now()
|
||||
resp, err := next.RoundTrip(r)
|
||||
if err == nil {
|
||||
obs.With(labels(code, method, r.Method, resp.StatusCode)).Observe(time.Since(start).Seconds())
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
}
|
||||
142
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go
сгенерированный
поставляемый
Обычный файл
142
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,142 @@
|
||||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package promhttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"net/http/httptrace"
|
||||
"time"
|
||||
)
|
||||
|
||||
// InstrumentTrace is used to offer flexibility in instrumenting the available
|
||||
// httptrace.ClientTrace hook functions. Each function is passed a float64
|
||||
// representing the time in seconds since the start of the http request. A user
|
||||
// may choose to use separately buckets Histograms, or implement custom
|
||||
// instance labels on a per function basis.
|
||||
type InstrumentTrace struct {
|
||||
GotConn func(float64)
|
||||
PutIdleConn func(float64)
|
||||
GotFirstResponseByte func(float64)
|
||||
Got100Continue func(float64)
|
||||
DNSStart func(float64)
|
||||
DNSDone func(float64)
|
||||
ConnectStart func(float64)
|
||||
ConnectDone func(float64)
|
||||
TLSHandshakeStart func(float64)
|
||||
TLSHandshakeDone func(float64)
|
||||
WroteHeaders func(float64)
|
||||
Wait100Continue func(float64)
|
||||
WroteRequest func(float64)
|
||||
}
|
||||
|
||||
// InstrumentRoundTripperTrace is a middleware that wraps the provided
|
||||
// RoundTripper and reports times to hook functions provided in the
|
||||
// InstrumentTrace struct. Hook functions that are not present in the provided
|
||||
// InstrumentTrace struct are ignored. Times reported to the hook functions are
|
||||
// time since the start of the request. Note that partitioning of Histograms
|
||||
// is expensive and should be used judiciously.
|
||||
//
|
||||
// For hook functions that receive an error as an argument, no observations are
|
||||
// made in the event of a non-nil error value.
|
||||
//
|
||||
// See the example for ExampleInstrumentRoundTripperDuration for example usage.
|
||||
func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc {
|
||||
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
||||
start := time.Now()
|
||||
|
||||
trace := &httptrace.ClientTrace{
|
||||
GotConn: func(_ httptrace.GotConnInfo) {
|
||||
if it.GotConn != nil {
|
||||
it.GotConn(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
PutIdleConn: func(err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if it.PutIdleConn != nil {
|
||||
it.PutIdleConn(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
DNSStart: func(_ httptrace.DNSStartInfo) {
|
||||
if it.DNSStart != nil {
|
||||
it.DNSStart(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
DNSDone: func(_ httptrace.DNSDoneInfo) {
|
||||
if it.DNSStart != nil {
|
||||
it.DNSStart(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
ConnectStart: func(_, _ string) {
|
||||
if it.ConnectStart != nil {
|
||||
it.ConnectStart(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
ConnectDone: func(_, _ string, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if it.ConnectDone != nil {
|
||||
it.ConnectDone(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
GotFirstResponseByte: func() {
|
||||
if it.GotFirstResponseByte != nil {
|
||||
it.GotFirstResponseByte(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
Got100Continue: func() {
|
||||
if it.Got100Continue != nil {
|
||||
it.Got100Continue(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
TLSHandshakeStart: func() {
|
||||
if it.TLSHandshakeStart != nil {
|
||||
it.TLSHandshakeStart(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
TLSHandshakeDone: func(_ tls.ConnectionState, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if it.TLSHandshakeDone != nil {
|
||||
it.TLSHandshakeDone(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
WroteHeaders: func() {
|
||||
if it.WroteHeaders != nil {
|
||||
it.WroteHeaders(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
Wait100Continue: func() {
|
||||
if it.Wait100Continue != nil {
|
||||
it.Wait100Continue(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
WroteRequest: func(_ httptrace.WroteRequestInfo) {
|
||||
if it.WroteRequest != nil {
|
||||
it.WroteRequest(time.Since(start).Seconds())
|
||||
}
|
||||
},
|
||||
}
|
||||
r = r.WithContext(httptrace.WithClientTrace(context.Background(), trace))
|
||||
|
||||
return next.RoundTrip(r)
|
||||
})
|
||||
}
|
||||
195
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8_test.go
сгенерированный
поставляемый
Обычный файл
195
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,195 @@
|
||||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package promhttp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
func TestClientMiddlewareAPI(t *testing.T) {
|
||||
client := http.DefaultClient
|
||||
client.Timeout = 1 * time.Second
|
||||
|
||||
reg := prometheus.NewRegistry()
|
||||
|
||||
inFlightGauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "client_in_flight_requests",
|
||||
Help: "A gauge of in-flight requests for the wrapped client.",
|
||||
})
|
||||
|
||||
counter := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "client_api_requests_total",
|
||||
Help: "A counter for requests from the wrapped client.",
|
||||
},
|
||||
[]string{"code", "method"},
|
||||
)
|
||||
|
||||
dnsLatencyVec := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "dns_duration_seconds",
|
||||
Help: "Trace dns latency histogram.",
|
||||
Buckets: []float64{.005, .01, .025, .05},
|
||||
},
|
||||
[]string{"event"},
|
||||
)
|
||||
|
||||
tlsLatencyVec := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "tls_duration_seconds",
|
||||
Help: "Trace tls latency histogram.",
|
||||
Buckets: []float64{.05, .1, .25, .5},
|
||||
},
|
||||
[]string{"event"},
|
||||
)
|
||||
|
||||
histVec := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "request_duration_seconds",
|
||||
Help: "A histogram of request latencies.",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
},
|
||||
[]string{"method"},
|
||||
)
|
||||
|
||||
reg.MustRegister(counter, tlsLatencyVec, dnsLatencyVec, histVec, inFlightGauge)
|
||||
|
||||
trace := &InstrumentTrace{
|
||||
DNSStart: func(t float64) {
|
||||
dnsLatencyVec.WithLabelValues("dns_start")
|
||||
},
|
||||
DNSDone: func(t float64) {
|
||||
dnsLatencyVec.WithLabelValues("dns_done")
|
||||
},
|
||||
TLSHandshakeStart: func(t float64) {
|
||||
tlsLatencyVec.WithLabelValues("tls_handshake_start")
|
||||
},
|
||||
TLSHandshakeDone: func(t float64) {
|
||||
tlsLatencyVec.WithLabelValues("tls_handshake_done")
|
||||
},
|
||||
}
|
||||
|
||||
client.Transport = InstrumentRoundTripperInFlight(inFlightGauge,
|
||||
InstrumentRoundTripperCounter(counter,
|
||||
InstrumentRoundTripperTrace(trace,
|
||||
InstrumentRoundTripperDuration(histVec, http.DefaultTransport),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
resp, err := client.Get("http://google.com")
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
func ExampleInstrumentRoundTripperDuration() {
|
||||
client := http.DefaultClient
|
||||
client.Timeout = 1 * time.Second
|
||||
|
||||
inFlightGauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "client_in_flight_requests",
|
||||
Help: "A gauge of in-flight requests for the wrapped client.",
|
||||
})
|
||||
|
||||
counter := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "client_api_requests_total",
|
||||
Help: "A counter for requests from the wrapped client.",
|
||||
},
|
||||
[]string{"code", "method"},
|
||||
)
|
||||
|
||||
// dnsLatencyVec uses custom buckets based on expected dns durations.
|
||||
// It has an instance label "event", which is set in the
|
||||
// DNSStart and DNSDonehook functions defined in the
|
||||
// InstrumentTrace struct below.
|
||||
dnsLatencyVec := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "dns_duration_seconds",
|
||||
Help: "Trace dns latency histogram.",
|
||||
Buckets: []float64{.005, .01, .025, .05},
|
||||
},
|
||||
[]string{"event"},
|
||||
)
|
||||
|
||||
// tlsLatencyVec uses custom buckets based on expected tls durations.
|
||||
// It has an instance label "event", which is set in the
|
||||
// TLSHandshakeStart and TLSHandshakeDone hook functions defined in the
|
||||
// InstrumentTrace struct below.
|
||||
tlsLatencyVec := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "tls_duration_seconds",
|
||||
Help: "Trace tls latency histogram.",
|
||||
Buckets: []float64{.05, .1, .25, .5},
|
||||
},
|
||||
[]string{"event"},
|
||||
)
|
||||
|
||||
// histVec has no labels, making it a zero-dimensional ObserverVec.
|
||||
histVec := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "request_duration_seconds",
|
||||
Help: "A histogram of request latencies.",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
},
|
||||
[]string{},
|
||||
)
|
||||
|
||||
// Register all of the metrics in the standard registry.
|
||||
prometheus.MustRegister(counter, tlsLatencyVec, dnsLatencyVec, histVec, inFlightGauge)
|
||||
|
||||
// Define functions for the available httptrace.ClientTrace hook
|
||||
// functions that we want to instrument.
|
||||
trace := &InstrumentTrace{
|
||||
DNSStart: func(t float64) {
|
||||
dnsLatencyVec.WithLabelValues("dns_start")
|
||||
},
|
||||
DNSDone: func(t float64) {
|
||||
dnsLatencyVec.WithLabelValues("dns_done")
|
||||
},
|
||||
TLSHandshakeStart: func(t float64) {
|
||||
tlsLatencyVec.WithLabelValues("tls_handshake_start")
|
||||
},
|
||||
TLSHandshakeDone: func(t float64) {
|
||||
tlsLatencyVec.WithLabelValues("tls_handshake_done")
|
||||
},
|
||||
}
|
||||
|
||||
// Wrap the default RoundTripper with middleware.
|
||||
roundTripper := InstrumentRoundTripperInFlight(inFlightGauge,
|
||||
InstrumentRoundTripperCounter(counter,
|
||||
InstrumentRoundTripperTrace(trace,
|
||||
InstrumentRoundTripperDuration(histVec, http.DefaultTransport),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
// Set the RoundTripper on our client.
|
||||
client.Transport = roundTripper
|
||||
|
||||
resp, err := client.Get("http://google.com")
|
||||
if err != nil {
|
||||
log.Printf("error: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
473
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
сгенерированный
поставляемый
Обычный файл
473
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,473 @@
|
||||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package promhttp
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// magicString is used for the hacky label test in checkLabels. Remove once fixed.
|
||||
const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa"
|
||||
|
||||
// InstrumentHandlerInFlight is a middleware that wraps the provided
|
||||
// http.Handler. It sets the provided prometheus.Gauge to the number of
|
||||
// requests currently handled by the wrapped http.Handler.
|
||||
//
|
||||
// See the example for InstrumentHandlerDuration for example usage.
|
||||
func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
g.Inc()
|
||||
defer g.Dec()
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// InstrumentHandlerDuration is a middleware that wraps the provided
|
||||
// http.Handler to observe the request duration with the provided ObserverVec.
|
||||
// The ObserverVec must have zero, one, or two labels. The only allowed label
|
||||
// names are "code" and "method". The function panics if any other instance
|
||||
// labels are provided. The Observe method of the Observer in the ObserverVec
|
||||
// is called with the request duration in seconds. Partitioning happens by HTTP
|
||||
// status code and/or HTTP method if the respective instance label names are
|
||||
// present in the ObserverVec. For unpartitioned observations, use an
|
||||
// ObserverVec with zero labels. Note that partitioning of Histograms is
|
||||
// expensive and should be used judiciously.
|
||||
//
|
||||
// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
|
||||
//
|
||||
// If the wrapped Handler panics, no values are reported.
|
||||
func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
|
||||
code, method := checkLabels(obs)
|
||||
|
||||
if code {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
now := time.Now()
|
||||
d := newDelegator(w)
|
||||
next.ServeHTTP(d, r)
|
||||
|
||||
obs.With(labels(code, method, r.Method, d.Status())).Observe(time.Since(now).Seconds())
|
||||
})
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
now := time.Now()
|
||||
next.ServeHTTP(w, r)
|
||||
obs.With(labels(code, method, r.Method, 0)).Observe(time.Since(now).Seconds())
|
||||
})
|
||||
}
|
||||
|
||||
// InstrumentHandlerCounter is a middleware that wraps the provided
|
||||
// http.Handler to observe the request result with the provided CounterVec.
|
||||
// The CounterVec must have zero, one, or two labels. The only allowed label
|
||||
// names are "code" and "method". The function panics if any other instance
|
||||
// labels are provided. Partitioning of the CounterVec happens by HTTP status
|
||||
// code and/or HTTP method if the respective instance label names are present
|
||||
// in the CounterVec. For unpartitioned counting, use a CounterVec with
|
||||
// zero labels.
|
||||
//
|
||||
// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
|
||||
//
|
||||
// If the wrapped Handler panics, the Counter is not incremented.
|
||||
//
|
||||
// See the example for InstrumentHandlerDuration for example usage.
|
||||
func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler) http.HandlerFunc {
|
||||
code, method := checkLabels(counter)
|
||||
|
||||
if code {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
d := newDelegator(w)
|
||||
next.ServeHTTP(d, r)
|
||||
counter.With(labels(code, method, r.Method, d.Status())).Inc()
|
||||
})
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
next.ServeHTTP(w, r)
|
||||
counter.With(labels(code, method, r.Method, 0)).Inc()
|
||||
})
|
||||
}
|
||||
|
||||
// InstrumentHandlerRequestSize is a middleware that wraps the provided
|
||||
// http.Handler to observe the request size with the provided ObserverVec.
|
||||
// The ObserverVec must have zero, one, or two labels. The only allowed label
|
||||
// names are "code" and "method". The function panics if any other instance
|
||||
// labels are provided. The Observe method of the Observer in the ObserverVec
|
||||
// is called with the request size in bytes. Partitioning happens by HTTP
|
||||
// status code and/or HTTP method if the respective instance label names are
|
||||
// present in the ObserverVec. For unpartitioned observations, use an
|
||||
// ObserverVec with zero labels. Note that partitioning of Histograms is
|
||||
// expensive and should be used judiciously.
|
||||
//
|
||||
// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
|
||||
//
|
||||
// If the wrapped Handler panics, no values are reported.
|
||||
//
|
||||
// See the example for InstrumentHandlerDuration for example usage.
|
||||
func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
|
||||
code, method := checkLabels(obs)
|
||||
|
||||
if code {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
d := newDelegator(w)
|
||||
next.ServeHTTP(d, r)
|
||||
size := computeApproximateRequestSize(r)
|
||||
obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(size))
|
||||
})
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
next.ServeHTTP(w, r)
|
||||
size := computeApproximateRequestSize(r)
|
||||
obs.With(labels(code, method, r.Method, 0)).Observe(float64(size))
|
||||
})
|
||||
}
|
||||
|
||||
// InstrumentHandlerResponseSize is a middleware that wraps the provided
|
||||
// http.Handler to observe the response size with the provided ObserverVec.
|
||||
// The ObserverVec must have zero, one, or two labels. The only allowed label
|
||||
// names are "code" and "method". The function panics if any other instance
|
||||
// labels are provided. The Observe method of the Observer in the ObserverVec
|
||||
// is called with the response size in bytes. Partitioning happens by HTTP
|
||||
// status code and/or HTTP method if the respective instance label names are
|
||||
// present in the ObserverVec. For unpartitioned observations, use an
|
||||
// ObserverVec with zero labels. Note that partitioning of Histograms is
|
||||
// expensive and should be used judiciously.
|
||||
//
|
||||
// If the wrapped Handler does not set a status code, a status code of 200 is assumed.
|
||||
//
|
||||
// If the wrapped Handler panics, no values are reported.
|
||||
//
|
||||
// See the example for InstrumentHandlerDuration for example usage.
|
||||
func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler) http.Handler {
|
||||
code, method := checkLabels(obs)
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
d := newDelegator(w)
|
||||
next.ServeHTTP(d, r)
|
||||
obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(d.Written()))
|
||||
})
|
||||
}
|
||||
|
||||
func checkLabels(c prometheus.Collector) (code bool, method bool) {
|
||||
// TODO(beorn7): Remove this hacky way to check for instance labels
|
||||
// once Descriptors can have their dimensionality queried.
|
||||
var (
|
||||
desc *prometheus.Desc
|
||||
pm dto.Metric
|
||||
)
|
||||
|
||||
descc := make(chan *prometheus.Desc, 1)
|
||||
c.Describe(descc)
|
||||
|
||||
select {
|
||||
case desc = <-descc:
|
||||
default:
|
||||
panic("no description provided by collector")
|
||||
}
|
||||
select {
|
||||
case <-descc:
|
||||
panic("more than one description provided by collector")
|
||||
default:
|
||||
}
|
||||
|
||||
close(descc)
|
||||
|
||||
if _, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0); err == nil {
|
||||
return
|
||||
}
|
||||
if m, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, magicString); err == nil {
|
||||
if err := m.Write(&pm); err != nil {
|
||||
panic("error checking metric for labels")
|
||||
}
|
||||
for _, label := range pm.Label {
|
||||
name, value := label.GetName(), label.GetValue()
|
||||
if value != magicString {
|
||||
continue
|
||||
}
|
||||
switch name {
|
||||
case "code":
|
||||
code = true
|
||||
case "method":
|
||||
method = true
|
||||
default:
|
||||
panic("metric partitioned with non-supported labels")
|
||||
}
|
||||
return
|
||||
}
|
||||
panic("previously set label not found – this must never happen")
|
||||
}
|
||||
if m, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, magicString, magicString); err == nil {
|
||||
if err := m.Write(&pm); err != nil {
|
||||
panic("error checking metric for labels")
|
||||
}
|
||||
for _, label := range pm.Label {
|
||||
name, value := label.GetName(), label.GetValue()
|
||||
if value != magicString {
|
||||
continue
|
||||
}
|
||||
if name == "code" || name == "method" {
|
||||
continue
|
||||
}
|
||||
panic("metric partitioned with non-supported labels")
|
||||
}
|
||||
code = true
|
||||
method = true
|
||||
return
|
||||
}
|
||||
panic("metric partitioned with non-supported labels")
|
||||
}
|
||||
|
||||
// emptyLabels is a one-time allocation for non-partitioned metrics to avoid
|
||||
// unnecessary allocations on each request.
|
||||
var emptyLabels = prometheus.Labels{}
|
||||
|
||||
func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
|
||||
if !(code || method) {
|
||||
return emptyLabels
|
||||
}
|
||||
labels := prometheus.Labels{}
|
||||
|
||||
if code {
|
||||
labels["code"] = sanitizeCode(status)
|
||||
}
|
||||
if method {
|
||||
labels["method"] = sanitizeMethod(reqMethod)
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
func computeApproximateRequestSize(r *http.Request) int {
|
||||
s := 0
|
||||
if r.URL != nil {
|
||||
s += len(r.URL.String())
|
||||
}
|
||||
|
||||
s += len(r.Method)
|
||||
s += len(r.Proto)
|
||||
for name, values := range r.Header {
|
||||
s += len(name)
|
||||
for _, value := range values {
|
||||
s += len(value)
|
||||
}
|
||||
}
|
||||
s += len(r.Host)
|
||||
|
||||
// N.B. r.Form and r.MultipartForm are assumed to be included in r.URL.
|
||||
|
||||
if r.ContentLength != -1 {
|
||||
s += int(r.ContentLength)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func sanitizeMethod(m string) string {
|
||||
switch m {
|
||||
case "GET", "get":
|
||||
return "get"
|
||||
case "PUT", "put":
|
||||
return "put"
|
||||
case "HEAD", "head":
|
||||
return "head"
|
||||
case "POST", "post":
|
||||
return "post"
|
||||
case "DELETE", "delete":
|
||||
return "delete"
|
||||
case "CONNECT", "connect":
|
||||
return "connect"
|
||||
case "OPTIONS", "options":
|
||||
return "options"
|
||||
case "NOTIFY", "notify":
|
||||
return "notify"
|
||||
default:
|
||||
return strings.ToLower(m)
|
||||
}
|
||||
}
|
||||
|
||||
// If the wrapped http.Handler has not set a status code, i.e. the value is
|
||||
// currently 0, santizeCode will return 200, for consistency with behavior in
|
||||
// the stdlib.
|
||||
func sanitizeCode(s int) string {
|
||||
switch s {
|
||||
case 100:
|
||||
return "100"
|
||||
case 101:
|
||||
return "101"
|
||||
|
||||
case 200, 0:
|
||||
return "200"
|
||||
case 201:
|
||||
return "201"
|
||||
case 202:
|
||||
return "202"
|
||||
case 203:
|
||||
return "203"
|
||||
case 204:
|
||||
return "204"
|
||||
case 205:
|
||||
return "205"
|
||||
case 206:
|
||||
return "206"
|
||||
|
||||
case 300:
|
||||
return "300"
|
||||
case 301:
|
||||
return "301"
|
||||
case 302:
|
||||
return "302"
|
||||
case 304:
|
||||
return "304"
|
||||
case 305:
|
||||
return "305"
|
||||
case 307:
|
||||
return "307"
|
||||
|
||||
case 400:
|
||||
return "400"
|
||||
case 401:
|
||||
return "401"
|
||||
case 402:
|
||||
return "402"
|
||||
case 403:
|
||||
return "403"
|
||||
case 404:
|
||||
return "404"
|
||||
case 405:
|
||||
return "405"
|
||||
case 406:
|
||||
return "406"
|
||||
case 407:
|
||||
return "407"
|
||||
case 408:
|
||||
return "408"
|
||||
case 409:
|
||||
return "409"
|
||||
case 410:
|
||||
return "410"
|
||||
case 411:
|
||||
return "411"
|
||||
case 412:
|
||||
return "412"
|
||||
case 413:
|
||||
return "413"
|
||||
case 414:
|
||||
return "414"
|
||||
case 415:
|
||||
return "415"
|
||||
case 416:
|
||||
return "416"
|
||||
case 417:
|
||||
return "417"
|
||||
case 418:
|
||||
return "418"
|
||||
|
||||
case 500:
|
||||
return "500"
|
||||
case 501:
|
||||
return "501"
|
||||
case 502:
|
||||
return "502"
|
||||
case 503:
|
||||
return "503"
|
||||
case 504:
|
||||
return "504"
|
||||
case 505:
|
||||
return "505"
|
||||
|
||||
case 428:
|
||||
return "428"
|
||||
case 429:
|
||||
return "429"
|
||||
case 431:
|
||||
return "431"
|
||||
case 511:
|
||||
return "511"
|
||||
|
||||
default:
|
||||
return strconv.Itoa(s)
|
||||
}
|
||||
}
|
||||
|
||||
type delegator interface {
|
||||
Status() int
|
||||
Written() int64
|
||||
|
||||
http.ResponseWriter
|
||||
}
|
||||
|
||||
type responseWriterDelegator struct {
|
||||
http.ResponseWriter
|
||||
|
||||
handler, method string
|
||||
status int
|
||||
written int64
|
||||
wroteHeader bool
|
||||
}
|
||||
|
||||
func (r *responseWriterDelegator) Status() int {
|
||||
return r.status
|
||||
}
|
||||
|
||||
func (r *responseWriterDelegator) Written() int64 {
|
||||
return r.written
|
||||
}
|
||||
|
||||
func (r *responseWriterDelegator) WriteHeader(code int) {
|
||||
r.status = code
|
||||
r.wroteHeader = true
|
||||
r.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
func (r *responseWriterDelegator) Write(b []byte) (int, error) {
|
||||
if !r.wroteHeader {
|
||||
r.WriteHeader(http.StatusOK)
|
||||
}
|
||||
n, err := r.ResponseWriter.Write(b)
|
||||
r.written += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
type fancyDelegator struct {
|
||||
*responseWriterDelegator
|
||||
}
|
||||
|
||||
func (r *fancyDelegator) CloseNotify() <-chan bool {
|
||||
return r.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
|
||||
func (r *fancyDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return r.ResponseWriter.(http.Hijacker).Hijack()
|
||||
}
|
||||
|
||||
func (r *fancyDelegator) Flush() {
|
||||
r.ResponseWriter.(http.Flusher).Flush()
|
||||
}
|
||||
|
||||
func (r *fancyDelegator) ReadFrom(re io.Reader) (int64, error) {
|
||||
if !r.wroteHeader {
|
||||
r.WriteHeader(http.StatusOK)
|
||||
}
|
||||
n, err := r.ResponseWriter.(io.ReaderFrom).ReadFrom(re)
|
||||
r.written += n
|
||||
return n, err
|
||||
}
|
||||
164
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server_test.go
сгенерированный
поставляемый
Обычный файл
164
vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,164 @@
|
||||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package promhttp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
func TestMiddlewareAPI(t *testing.T) {
|
||||
reg := prometheus.NewRegistry()
|
||||
|
||||
inFlightGauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "in_flight_requests",
|
||||
Help: "A gauge of requests currently being served by the wrapped handler.",
|
||||
})
|
||||
|
||||
counter := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "api_requests_total",
|
||||
Help: "A counter for requests to the wrapped handler.",
|
||||
},
|
||||
[]string{"code", "method"},
|
||||
)
|
||||
|
||||
histVec := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "response_duration_seconds",
|
||||
Help: "A histogram of request latencies.",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
ConstLabels: prometheus.Labels{"handler": "api"},
|
||||
},
|
||||
[]string{"method"},
|
||||
)
|
||||
|
||||
responseSize := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "push_request_size_bytes",
|
||||
Help: "A histogram of request sizes for requests.",
|
||||
Buckets: []float64{200, 500, 900, 1500},
|
||||
},
|
||||
[]string{},
|
||||
)
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("OK"))
|
||||
})
|
||||
|
||||
reg.MustRegister(inFlightGauge, counter, histVec, responseSize)
|
||||
|
||||
chain := InstrumentHandlerInFlight(inFlightGauge,
|
||||
InstrumentHandlerCounter(counter,
|
||||
InstrumentHandlerDuration(histVec,
|
||||
InstrumentHandlerResponseSize(responseSize, handler),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
r, _ := http.NewRequest("GET", "www.example.com", nil)
|
||||
w := httptest.NewRecorder()
|
||||
chain.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func ExampleInstrumentHandlerDuration() {
|
||||
inFlightGauge := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "in_flight_requests",
|
||||
Help: "A gauge of requests currently being served by the wrapped handler.",
|
||||
})
|
||||
|
||||
counter := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "api_requests_total",
|
||||
Help: "A counter for requests to the wrapped handler.",
|
||||
},
|
||||
[]string{"code", "method"},
|
||||
)
|
||||
|
||||
// pushVec and pullVec are partitioned by the HTTP method and use custom
|
||||
// buckets based on the expected request duration. ConstLabels are used
|
||||
// to set a handler label to mark pushVec as tracking the durations for
|
||||
// pushes and pullVec as tracking the durations for pulls. Note that
|
||||
// Name, Help, and Buckets need to be the same for consistency, so we
|
||||
// use the same HistogramOpts after just modifying the ConstLabels.
|
||||
histogramOpts := prometheus.HistogramOpts{
|
||||
Name: "request_duration_seconds",
|
||||
Help: "A histogram of latencies for requests.",
|
||||
Buckets: []float64{.25, .5, 1, 2.5, 5, 10},
|
||||
ConstLabels: prometheus.Labels{"handler": "push"},
|
||||
}
|
||||
pushVec := prometheus.NewHistogramVec(
|
||||
histogramOpts,
|
||||
[]string{"method"},
|
||||
)
|
||||
histogramOpts.ConstLabels = prometheus.Labels{"handler": "pull"}
|
||||
pullVec := prometheus.NewHistogramVec(
|
||||
histogramOpts,
|
||||
[]string{"method"},
|
||||
)
|
||||
|
||||
// responseSize has no labels, making it a zero-dimensional
|
||||
// ObserverVec.
|
||||
responseSize := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "response_size_bytes",
|
||||
Help: "A histogram of response sizes for requests.",
|
||||
Buckets: []float64{200, 500, 900, 1500},
|
||||
},
|
||||
[]string{},
|
||||
)
|
||||
|
||||
// Create the handlers that will be wrapped by the middleware.
|
||||
pushHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("Push"))
|
||||
})
|
||||
pullHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("Pull"))
|
||||
})
|
||||
|
||||
// Register all of the metrics in the standard registry.
|
||||
prometheus.MustRegister(inFlightGauge, counter, pullVec, pushVec, responseSize)
|
||||
|
||||
// Wrap the pushHandler with our shared middleware, but use the
|
||||
// endpoint-specific pushVec with InstrumentHandlerDuration.
|
||||
pushChain := InstrumentHandlerInFlight(inFlightGauge,
|
||||
InstrumentHandlerCounter(counter,
|
||||
InstrumentHandlerDuration(pushVec,
|
||||
InstrumentHandlerResponseSize(responseSize, pushHandler),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
// Wrap the pushHandler with the shared middleware, but use the
|
||||
// endpoint-specific pullVec with InstrumentHandlerDuration.
|
||||
pullChain := InstrumentHandlerInFlight(inFlightGauge,
|
||||
InstrumentHandlerCounter(counter,
|
||||
InstrumentHandlerDuration(pullVec,
|
||||
InstrumentHandlerResponseSize(responseSize, pullHandler),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
http.Handle("/metrics", Handler())
|
||||
http.Handle("/push", pushChain)
|
||||
http.Handle("/pull", pullChain)
|
||||
|
||||
if err := http.ListenAndServe(":3000", nil); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
83
vendor/github.com/prometheus/client_golang/prometheus/push/example_add_from_gatherer_test.go
сгенерированный
поставляемый
Обычный файл
83
vendor/github.com/prometheus/client_golang/prometheus/push/example_add_from_gatherer_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,83 @@
|
||||
// Copyright 2016 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Copyright (c) 2013, The Prometheus Authors
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file.
|
||||
|
||||
package push_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/push"
|
||||
)
|
||||
|
||||
var (
|
||||
completionTime = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "db_backup_last_completion_timestamp_seconds",
|
||||
Help: "The timestamp of the last completion of a DB backup, successful or not.",
|
||||
})
|
||||
successTime = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "db_backup_last_success_timestamp_seconds",
|
||||
Help: "The timestamp of the last successful completion of a DB backup.",
|
||||
})
|
||||
duration = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "db_backup_duration_seconds",
|
||||
Help: "The duration of the last DB backup in seconds.",
|
||||
})
|
||||
records = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "db_backup_records_processed",
|
||||
Help: "The number of records processed in the last DB backup.",
|
||||
})
|
||||
)
|
||||
|
||||
func performBackup() (int, error) {
|
||||
// Perform the backup and return the number of backed up records and any
|
||||
// applicable error.
|
||||
// ...
|
||||
return 42, nil
|
||||
}
|
||||
|
||||
func ExampleAddFromGatherer() {
|
||||
registry := prometheus.NewRegistry()
|
||||
registry.MustRegister(completionTime, duration, records)
|
||||
// Note that successTime is not registered at this time.
|
||||
|
||||
start := time.Now()
|
||||
n, err := performBackup()
|
||||
records.Set(float64(n))
|
||||
duration.Set(time.Since(start).Seconds())
|
||||
completionTime.SetToCurrentTime()
|
||||
if err != nil {
|
||||
fmt.Println("DB backup failed:", err)
|
||||
} else {
|
||||
// Only now register successTime.
|
||||
registry.MustRegister(successTime)
|
||||
successTime.SetToCurrentTime()
|
||||
}
|
||||
// AddFromGatherer is used here rather than FromGatherer to not delete a
|
||||
// previously pushed success timestamp in case of a failure of this
|
||||
// backup.
|
||||
if err := push.AddFromGatherer(
|
||||
"db_backup", nil,
|
||||
"http://pushgateway:9091",
|
||||
registry,
|
||||
); err != nil {
|
||||
fmt.Println("Could not push to Pushgateway:", err)
|
||||
}
|
||||
}
|
||||
24
vendor/github.com/prometheus/client_golang/prometheus/push/examples_test.go
сгенерированный
поставляемый
24
vendor/github.com/prometheus/client_golang/prometheus/push/examples_test.go
сгенерированный
поставляемый
@@ -15,7 +15,6 @@ package push_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/push"
|
||||
@@ -24,9 +23,9 @@ import (
|
||||
func ExampleCollectors() {
|
||||
completionTime := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "db_backup_last_completion_timestamp_seconds",
|
||||
Help: "The timestamp of the last succesful completion of a DB backup.",
|
||||
Help: "The timestamp of the last successful completion of a DB backup.",
|
||||
})
|
||||
completionTime.Set(float64(time.Now().Unix()))
|
||||
completionTime.SetToCurrentTime()
|
||||
if err := push.Collectors(
|
||||
"db_backup", push.HostnameGroupingKey(),
|
||||
"http://pushgateway:9091",
|
||||
@@ -35,22 +34,3 @@ func ExampleCollectors() {
|
||||
fmt.Println("Could not push completion time to Pushgateway:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleRegistry() {
|
||||
registry := prometheus.NewRegistry()
|
||||
|
||||
completionTime := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "db_backup_last_completion_timestamp_seconds",
|
||||
Help: "The timestamp of the last succesful completion of a DB backup.",
|
||||
})
|
||||
registry.MustRegister(completionTime)
|
||||
|
||||
completionTime.Set(float64(time.Now().Unix()))
|
||||
if err := push.FromGatherer(
|
||||
"db_backup", push.HostnameGroupingKey(),
|
||||
"http://pushgateway:9091",
|
||||
registry,
|
||||
); err != nil {
|
||||
fmt.Println("Could not push completion time to Pushgateway:", err)
|
||||
}
|
||||
}
|
||||
|
||||
2
vendor/github.com/prometheus/client_golang/prometheus/push/push.go
сгенерированный
поставляемый
2
vendor/github.com/prometheus/client_golang/prometheus/push/push.go
сгенерированный
поставляемый
@@ -84,7 +84,7 @@ func push(job string, grouping map[string]string, pushURL string, g prometheus.G
|
||||
}
|
||||
urlComponents := []string{url.QueryEscape(job)}
|
||||
for ln, lv := range grouping {
|
||||
if !model.LabelNameRE.MatchString(ln) {
|
||||
if !model.LabelName(ln).IsValid() {
|
||||
return fmt.Errorf("grouping label has invalid name: %s", ln)
|
||||
}
|
||||
if strings.Contains(lv, "/") {
|
||||
|
||||
57
vendor/github.com/prometheus/client_golang/prometheus/registry.go
сгенерированный
поставляемый
57
vendor/github.com/prometheus/client_golang/prometheus/registry.go
сгенерированный
поставляемый
@@ -152,38 +152,6 @@ func MustRegister(cs ...Collector) {
|
||||
DefaultRegisterer.MustRegister(cs...)
|
||||
}
|
||||
|
||||
// RegisterOrGet registers the provided Collector with the DefaultRegisterer and
|
||||
// returns the Collector, unless an equal Collector was registered before, in
|
||||
// which case that Collector is returned.
|
||||
//
|
||||
// Deprecated: RegisterOrGet is merely a convenience function for the
|
||||
// implementation as described in the documentation for
|
||||
// AlreadyRegisteredError. As the use case is relatively rare, this function
|
||||
// will be removed in a future version of this package to clean up the
|
||||
// namespace.
|
||||
func RegisterOrGet(c Collector) (Collector, error) {
|
||||
if err := Register(c); err != nil {
|
||||
if are, ok := err.(AlreadyRegisteredError); ok {
|
||||
return are.ExistingCollector, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// MustRegisterOrGet behaves like RegisterOrGet but panics instead of returning
|
||||
// an error.
|
||||
//
|
||||
// Deprecated: This is deprecated for the same reason RegisterOrGet is. See
|
||||
// there for details.
|
||||
func MustRegisterOrGet(c Collector) Collector {
|
||||
c, err := RegisterOrGet(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Unregister removes the registration of the provided Collector from the
|
||||
// DefaultRegisterer.
|
||||
//
|
||||
@@ -201,25 +169,6 @@ func (gf GathererFunc) Gather() ([]*dto.MetricFamily, error) {
|
||||
return gf()
|
||||
}
|
||||
|
||||
// SetMetricFamilyInjectionHook replaces the DefaultGatherer with one that
|
||||
// gathers from the previous DefaultGatherers but then merges the MetricFamily
|
||||
// protobufs returned from the provided hook function with the MetricFamily
|
||||
// protobufs returned from the original DefaultGatherer.
|
||||
//
|
||||
// Deprecated: This function manipulates the DefaultGatherer variable. Consider
|
||||
// the implications, i.e. don't do this concurrently with any uses of the
|
||||
// DefaultGatherer. In the rare cases where you need to inject MetricFamily
|
||||
// protobufs directly, it is recommended to use a custom Registry and combine it
|
||||
// with a custom Gatherer using the Gatherers type (see
|
||||
// there). SetMetricFamilyInjectionHook only exists for compatibility reasons
|
||||
// with previous versions of this package.
|
||||
func SetMetricFamilyInjectionHook(hook func() []*dto.MetricFamily) {
|
||||
DefaultGatherer = Gatherers{
|
||||
DefaultGatherer,
|
||||
GathererFunc(func() ([]*dto.MetricFamily, error) { return hook(), nil }),
|
||||
}
|
||||
}
|
||||
|
||||
// AlreadyRegisteredError is returned by the Register method if the Collector to
|
||||
// be registered has already been registered before, or a different Collector
|
||||
// that collects the same metrics has been registered before. Registration fails
|
||||
@@ -294,7 +243,7 @@ func (r *Registry) Register(c Collector) error {
|
||||
}()
|
||||
r.mtx.Lock()
|
||||
defer r.mtx.Unlock()
|
||||
// Coduct various tests...
|
||||
// Conduct various tests...
|
||||
for desc := range descChan {
|
||||
|
||||
// Is the descriptor valid at all?
|
||||
@@ -447,7 +396,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
|
||||
|
||||
// Drain metricChan in case of premature return.
|
||||
defer func() {
|
||||
for _ = range metricChan {
|
||||
for range metricChan {
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -683,7 +632,7 @@ func (s metricSorter) Less(i, j int) bool {
|
||||
return s[i].GetTimestampMs() < s[j].GetTimestampMs()
|
||||
}
|
||||
|
||||
// normalizeMetricFamilies returns a MetricFamily slice whith empty
|
||||
// normalizeMetricFamilies returns a MetricFamily slice with empty
|
||||
// MetricFamilies pruned and the remaining MetricFamilies sorted by name within
|
||||
// the slice, with the contained Metrics sorted within each MetricFamily.
|
||||
func normalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily {
|
||||
|
||||
23
vendor/github.com/prometheus/client_golang/prometheus/registry_test.go
сгенерированный
поставляемый
23
vendor/github.com/prometheus/client_golang/prometheus/registry_test.go
сгенерированный
поставляемый
@@ -526,20 +526,21 @@ func TestRegisterWithOrGet(t *testing.T) {
|
||||
},
|
||||
[]string{"foo", "bar"},
|
||||
)
|
||||
if err := prometheus.Register(original); err != nil {
|
||||
var err error
|
||||
if err = prometheus.Register(original); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := prometheus.Register(equalButNotSame); err == nil {
|
||||
if err = prometheus.Register(equalButNotSame); err == nil {
|
||||
t.Fatal("expected error when registringe equal collector")
|
||||
}
|
||||
existing, err := prometheus.RegisterOrGet(equalButNotSame)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if existing != original {
|
||||
t.Error("expected original collector but got something else")
|
||||
}
|
||||
if existing == equalButNotSame {
|
||||
t.Error("expected original callector but got new one")
|
||||
if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
|
||||
if are.ExistingCollector != original {
|
||||
t.Error("expected original collector but got something else")
|
||||
}
|
||||
if are.ExistingCollector == equalButNotSame {
|
||||
t.Error("expected original callector but got new one")
|
||||
}
|
||||
} else {
|
||||
t.Error("unexpected error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
43
vendor/github.com/prometheus/client_golang/prometheus/summary.go
сгенерированный
поставляемый
43
vendor/github.com/prometheus/client_golang/prometheus/summary.go
сгенерированный
поставляемый
@@ -54,6 +54,9 @@ type Summary interface {
|
||||
}
|
||||
|
||||
// DefObjectives are the default Summary quantile values.
|
||||
//
|
||||
// Deprecated: DefObjectives will not be used as the default objectives in
|
||||
// v0.10 of the library. The default Summary will have no quantiles then.
|
||||
var (
|
||||
DefObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}
|
||||
|
||||
@@ -113,9 +116,15 @@ type SummaryOpts struct {
|
||||
ConstLabels Labels
|
||||
|
||||
// Objectives defines the quantile rank estimates with their respective
|
||||
// absolute error. If Objectives[q] = e, then the value reported
|
||||
// for q will be the φ-quantile value for some φ between q-e and q+e.
|
||||
// The default value is DefObjectives.
|
||||
// absolute error. If Objectives[q] = e, then the value reported for q
|
||||
// will be the φ-quantile value for some φ between q-e and q+e. The
|
||||
// default value is DefObjectives. It is used if Objectives is left at
|
||||
// its zero value (i.e. nil). To create a Summary without Objectives,
|
||||
// set it to an empty map (i.e. map[float64]float64{}).
|
||||
//
|
||||
// Deprecated: Note that the current value of DefObjectives is
|
||||
// deprecated. It will be replaced by an empty map in v0.10 of the
|
||||
// library. Please explicitly set Objectives to the desired value.
|
||||
Objectives map[float64]float64
|
||||
|
||||
// MaxAge defines the duration for which an observation stays relevant
|
||||
@@ -183,7 +192,7 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts.Objectives) == 0 {
|
||||
if opts.Objectives == nil {
|
||||
opts.Objectives = DefObjectives
|
||||
}
|
||||
|
||||
@@ -410,24 +419,24 @@ func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
|
||||
}
|
||||
}
|
||||
|
||||
// GetMetricWithLabelValues replaces the method of the same name in
|
||||
// MetricVec. The difference is that this method returns a Summary and not a
|
||||
// Metric so that no type conversion is required.
|
||||
func (m *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Summary, error) {
|
||||
// GetMetricWithLabelValues replaces the method of the same name in MetricVec.
|
||||
// The difference is that this method returns an Observer and not a Metric so
|
||||
// that no type conversion to an Observer is required.
|
||||
func (m *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) {
|
||||
metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||
if metric != nil {
|
||||
return metric.(Summary), err
|
||||
return metric.(Observer), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetMetricWith replaces the method of the same name in MetricVec. The
|
||||
// difference is that this method returns a Summary and not a Metric so that no
|
||||
// type conversion is required.
|
||||
func (m *SummaryVec) GetMetricWith(labels Labels) (Summary, error) {
|
||||
// difference is that this method returns an Observer and not a Metric so that
|
||||
// no type conversion to an Observer is required.
|
||||
func (m *SummaryVec) GetMetricWith(labels Labels) (Observer, error) {
|
||||
metric, err := m.MetricVec.GetMetricWith(labels)
|
||||
if metric != nil {
|
||||
return metric.(Summary), err
|
||||
return metric.(Observer), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@@ -436,15 +445,15 @@ func (m *SummaryVec) GetMetricWith(labels Labels) (Summary, error) {
|
||||
// GetMetricWithLabelValues would have returned an error. By not returning an
|
||||
// error, WithLabelValues allows shortcuts like
|
||||
// myVec.WithLabelValues("404", "GET").Observe(42.21)
|
||||
func (m *SummaryVec) WithLabelValues(lvs ...string) Summary {
|
||||
return m.MetricVec.WithLabelValues(lvs...).(Summary)
|
||||
func (m *SummaryVec) WithLabelValues(lvs ...string) Observer {
|
||||
return m.MetricVec.WithLabelValues(lvs...).(Observer)
|
||||
}
|
||||
|
||||
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
|
||||
// returned an error. By not returning an error, With allows shortcuts like
|
||||
// myVec.With(Labels{"code": "404", "method": "GET"}).Observe(42.21)
|
||||
func (m *SummaryVec) With(labels Labels) Summary {
|
||||
return m.MetricVec.With(labels).(Summary)
|
||||
func (m *SummaryVec) With(labels Labels) Observer {
|
||||
return m.MetricVec.With(labels).(Observer)
|
||||
}
|
||||
|
||||
type constSummary struct {
|
||||
|
||||
53
vendor/github.com/prometheus/client_golang/prometheus/summary_test.go
сгенерированный
поставляемый
53
vendor/github.com/prometheus/client_golang/prometheus/summary_test.go
сгенерированный
поставляемый
@@ -25,6 +25,45 @@ import (
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
func TestSummaryWithDefaultObjectives(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
summaryWithDefaultObjectives := NewSummary(SummaryOpts{
|
||||
Name: "default_objectives",
|
||||
Help: "Test help.",
|
||||
})
|
||||
if err := reg.Register(summaryWithDefaultObjectives); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
m := &dto.Metric{}
|
||||
if err := summaryWithDefaultObjectives.Write(m); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(m.GetSummary().Quantile) != len(DefObjectives) {
|
||||
t.Error("expected default objectives in summary")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSummaryWithoutObjectives(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
summaryWithEmptyObjectives := NewSummary(SummaryOpts{
|
||||
Name: "empty_objectives",
|
||||
Help: "Test help.",
|
||||
Objectives: map[float64]float64{},
|
||||
})
|
||||
if err := reg.Register(summaryWithEmptyObjectives); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
m := &dto.Metric{}
|
||||
if err := summaryWithEmptyObjectives.Write(m); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(m.GetSummary().Quantile) != 0 {
|
||||
t.Error("expected no objectives in summary")
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkSummaryObserve(w int, b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
@@ -136,8 +175,9 @@ func TestSummaryConcurrency(t *testing.T) {
|
||||
end.Add(concLevel)
|
||||
|
||||
sum := NewSummary(SummaryOpts{
|
||||
Name: "test_summary",
|
||||
Help: "helpless",
|
||||
Name: "test_summary",
|
||||
Help: "helpless",
|
||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||
})
|
||||
|
||||
allVars := make([]float64, total)
|
||||
@@ -223,8 +263,9 @@ func TestSummaryVecConcurrency(t *testing.T) {
|
||||
|
||||
sum := NewSummaryVec(
|
||||
SummaryOpts{
|
||||
Name: "test_summary",
|
||||
Help: "helpless",
|
||||
Name: "test_summary",
|
||||
Help: "helpless",
|
||||
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
|
||||
},
|
||||
[]string{"label"},
|
||||
)
|
||||
@@ -260,7 +301,7 @@ func TestSummaryVecConcurrency(t *testing.T) {
|
||||
for i := 0; i < vecLength; i++ {
|
||||
m := &dto.Metric{}
|
||||
s := sum.WithLabelValues(string('A' + i))
|
||||
s.Write(m)
|
||||
s.(Summary).Write(m)
|
||||
if got, want := int(*m.Summary.SampleCount), len(allVars[i]); got != want {
|
||||
t.Errorf("got sample count %d for label %c, want %d", got, 'A'+i, want)
|
||||
}
|
||||
@@ -305,7 +346,7 @@ func TestSummaryDecay(t *testing.T) {
|
||||
m := &dto.Metric{}
|
||||
i := 0
|
||||
tick := time.NewTicker(time.Millisecond)
|
||||
for _ = range tick.C {
|
||||
for range tick.C {
|
||||
i++
|
||||
sum.Observe(float64(i))
|
||||
if i%10 == 0 {
|
||||
|
||||
48
vendor/github.com/prometheus/client_golang/prometheus/timer.go
сгенерированный
поставляемый
Обычный файл
48
vendor/github.com/prometheus/client_golang/prometheus/timer.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,48 @@
|
||||
// Copyright 2016 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package prometheus
|
||||
|
||||
import "time"
|
||||
|
||||
// Timer is a helper type to time functions. Use NewTimer to create new
|
||||
// instances.
|
||||
type Timer struct {
|
||||
begin time.Time
|
||||
observer Observer
|
||||
}
|
||||
|
||||
// NewTimer creates a new Timer. The provided Observer is used to observe a
|
||||
// duration in seconds. Timer is usually used to time a function call in the
|
||||
// following way:
|
||||
// func TimeMe() {
|
||||
// timer := NewTimer(myHistogram)
|
||||
// defer timer.ObserveDuration()
|
||||
// // Do actual work.
|
||||
// }
|
||||
func NewTimer(o Observer) *Timer {
|
||||
return &Timer{
|
||||
begin: time.Now(),
|
||||
observer: o,
|
||||
}
|
||||
}
|
||||
|
||||
// ObserveDuration records the duration passed since the Timer was created with
|
||||
// NewTimer. It calls the Observe method of the Observer provided during
|
||||
// construction with the duration in seconds as an argument. ObserveDuration is
|
||||
// usually called with a defer statement.
|
||||
func (t *Timer) ObserveDuration() {
|
||||
if t.observer != nil {
|
||||
t.observer.Observe(time.Since(t.begin).Seconds())
|
||||
}
|
||||
}
|
||||
152
vendor/github.com/prometheus/client_golang/prometheus/timer_test.go
сгенерированный
поставляемый
Обычный файл
152
vendor/github.com/prometheus/client_golang/prometheus/timer_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,152 @@
|
||||
// Copyright 2016 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
func TestTimerObserve(t *testing.T) {
|
||||
var (
|
||||
his = NewHistogram(HistogramOpts{Name: "test_histogram"})
|
||||
sum = NewSummary(SummaryOpts{Name: "test_summary"})
|
||||
gauge = NewGauge(GaugeOpts{Name: "test_gauge"})
|
||||
)
|
||||
|
||||
func() {
|
||||
hisTimer := NewTimer(his)
|
||||
sumTimer := NewTimer(sum)
|
||||
gaugeTimer := NewTimer(ObserverFunc(gauge.Set))
|
||||
defer hisTimer.ObserveDuration()
|
||||
defer sumTimer.ObserveDuration()
|
||||
defer gaugeTimer.ObserveDuration()
|
||||
}()
|
||||
|
||||
m := &dto.Metric{}
|
||||
his.Write(m)
|
||||
if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got {
|
||||
t.Errorf("want %d observations for histogram, got %d", want, got)
|
||||
}
|
||||
m.Reset()
|
||||
sum.Write(m)
|
||||
if want, got := uint64(1), m.GetSummary().GetSampleCount(); want != got {
|
||||
t.Errorf("want %d observations for summary, got %d", want, got)
|
||||
}
|
||||
m.Reset()
|
||||
gauge.Write(m)
|
||||
if got := m.GetGauge().GetValue(); got <= 0 {
|
||||
t.Errorf("want value > 0 for gauge, got %f", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimerEmpty(t *testing.T) {
|
||||
emptyTimer := NewTimer(nil)
|
||||
emptyTimer.ObserveDuration()
|
||||
// Do nothing, just demonstrate it works without panic.
|
||||
}
|
||||
|
||||
func TestTimerConditionalTiming(t *testing.T) {
|
||||
var (
|
||||
his = NewHistogram(HistogramOpts{
|
||||
Name: "test_histogram",
|
||||
})
|
||||
timeMe = true
|
||||
m = &dto.Metric{}
|
||||
)
|
||||
|
||||
timedFunc := func() {
|
||||
timer := NewTimer(ObserverFunc(func(v float64) {
|
||||
if timeMe {
|
||||
his.Observe(v)
|
||||
}
|
||||
}))
|
||||
defer timer.ObserveDuration()
|
||||
}
|
||||
|
||||
timedFunc() // This will time.
|
||||
his.Write(m)
|
||||
if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got {
|
||||
t.Errorf("want %d observations for histogram, got %d", want, got)
|
||||
}
|
||||
|
||||
timeMe = false
|
||||
timedFunc() // This will not time again.
|
||||
m.Reset()
|
||||
his.Write(m)
|
||||
if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got {
|
||||
t.Errorf("want %d observations for histogram, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimerByOutcome(t *testing.T) {
|
||||
var (
|
||||
his = NewHistogramVec(
|
||||
HistogramOpts{Name: "test_histogram"},
|
||||
[]string{"outcome"},
|
||||
)
|
||||
outcome = "foo"
|
||||
m = &dto.Metric{}
|
||||
)
|
||||
|
||||
timedFunc := func() {
|
||||
timer := NewTimer(ObserverFunc(func(v float64) {
|
||||
his.WithLabelValues(outcome).Observe(v)
|
||||
}))
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
if outcome == "foo" {
|
||||
outcome = "bar"
|
||||
return
|
||||
}
|
||||
outcome = "foo"
|
||||
}
|
||||
|
||||
timedFunc()
|
||||
his.WithLabelValues("foo").(Histogram).Write(m)
|
||||
if want, got := uint64(0), m.GetHistogram().GetSampleCount(); want != got {
|
||||
t.Errorf("want %d observations for 'foo' histogram, got %d", want, got)
|
||||
}
|
||||
m.Reset()
|
||||
his.WithLabelValues("bar").(Histogram).Write(m)
|
||||
if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got {
|
||||
t.Errorf("want %d observations for 'bar' histogram, got %d", want, got)
|
||||
}
|
||||
|
||||
timedFunc()
|
||||
m.Reset()
|
||||
his.WithLabelValues("foo").(Histogram).Write(m)
|
||||
if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got {
|
||||
t.Errorf("want %d observations for 'foo' histogram, got %d", want, got)
|
||||
}
|
||||
m.Reset()
|
||||
his.WithLabelValues("bar").(Histogram).Write(m)
|
||||
if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got {
|
||||
t.Errorf("want %d observations for 'bar' histogram, got %d", want, got)
|
||||
}
|
||||
|
||||
timedFunc()
|
||||
m.Reset()
|
||||
his.WithLabelValues("foo").(Histogram).Write(m)
|
||||
if want, got := uint64(1), m.GetHistogram().GetSampleCount(); want != got {
|
||||
t.Errorf("want %d observations for 'foo' histogram, got %d", want, got)
|
||||
}
|
||||
m.Reset()
|
||||
his.WithLabelValues("bar").(Histogram).Write(m)
|
||||
if want, got := uint64(2), m.GetHistogram().GetSampleCount(); want != got {
|
||||
t.Errorf("want %d observations for 'bar' histogram, got %d", want, got)
|
||||
}
|
||||
|
||||
}
|
||||
5
vendor/github.com/prometheus/client_golang/prometheus/untyped.go
сгенерированный
поставляемый
5
vendor/github.com/prometheus/client_golang/prometheus/untyped.go
сгенерированный
поставляемый
@@ -20,6 +20,11 @@ package prometheus
|
||||
// no type information is implied.
|
||||
//
|
||||
// To create Untyped instances, use NewUntyped.
|
||||
//
|
||||
// Deprecated: The Untyped type is deprecated because it doesn't make sense in
|
||||
// direct instrumentation. If you need to mirror an external metric of unknown
|
||||
// type (usually while writing exporters), Use MustNewConstMetric to create an
|
||||
// untyped metric instance on the fly.
|
||||
type Untyped interface {
|
||||
Metric
|
||||
Collector
|
||||
|
||||
7
vendor/github.com/prometheus/client_golang/prometheus/value.go
сгенерированный
поставляемый
7
vendor/github.com/prometheus/client_golang/prometheus/value.go
сгенерированный
поставляемый
@@ -19,6 +19,7 @@ import (
|
||||
"math"
|
||||
"sort"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
@@ -43,7 +44,7 @@ var errInconsistentCardinality = errors.New("inconsistent label cardinality")
|
||||
// ValueType. This is a low-level building block used by the library to back the
|
||||
// implementations of Counter, Gauge, and Untyped.
|
||||
type value struct {
|
||||
// valBits containst the bits of the represented float64 value. It has
|
||||
// valBits contains the bits of the represented float64 value. It has
|
||||
// to go first in the struct to guarantee alignment for atomic
|
||||
// operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG
|
||||
valBits uint64
|
||||
@@ -80,6 +81,10 @@ func (v *value) Set(val float64) {
|
||||
atomic.StoreUint64(&v.valBits, math.Float64bits(val))
|
||||
}
|
||||
|
||||
func (v *value) SetToCurrentTime() {
|
||||
v.Set(float64(time.Now().UnixNano()) / 1e9)
|
||||
}
|
||||
|
||||
func (v *value) Inc() {
|
||||
v.Add(1)
|
||||
}
|
||||
|
||||
4
vendor/github.com/prometheus/client_golang/prometheus/vec_test.go
сгенерированный
поставляемый
4
vendor/github.com/prometheus/client_golang/prometheus/vec_test.go
сгенерированный
поставляемый
@@ -241,8 +241,8 @@ func TestCounterVecEndToEndWithCollision(t *testing.T) {
|
||||
|
||||
func BenchmarkMetricVecWithLabelValuesBasic(b *testing.B) {
|
||||
benchmarkMetricVecWithLabelValues(b, map[string][]string{
|
||||
"l1": []string{"onevalue"},
|
||||
"l2": []string{"twovalue"},
|
||||
"l1": {"onevalue"},
|
||||
"l2": {"twovalue"},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user