mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-06 17:57:51 +00:00
Add vendor folder to git
This commit is contained in:
parent
66cf5eaafb
commit
183585f56f
6916 changed files with 2629581 additions and 1 deletions
26
vendor/github.com/prometheus/client_golang/.gitignore
generated
vendored
Normal file
26
vendor/github.com/prometheus/client_golang/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
|
||||
*~
|
||||
*#
|
||||
.build
|
||||
8
vendor/github.com/prometheus/client_golang/.travis.yml
generated
vendored
Normal file
8
vendor/github.com/prometheus/client_golang/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
sudo: false
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4
|
||||
|
||||
script:
|
||||
- go test -short ./...
|
||||
18
vendor/github.com/prometheus/client_golang/AUTHORS.md
generated
vendored
Normal file
18
vendor/github.com/prometheus/client_golang/AUTHORS.md
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
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@soundcloud.com>
|
||||
* Matt T. Proud <matt.proud@gmail.com>
|
||||
* Tobias Schmidt <ts@soundcloud.com>
|
||||
|
||||
86
vendor/github.com/prometheus/client_golang/CHANGELOG.md
generated
vendored
Normal file
86
vendor/github.com/prometheus/client_golang/CHANGELOG.md
generated
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
## 0.7.0 / 2015-07-27
|
||||
* [CHANGE] Rename ExporterLabelPrefix to ExportedLabelPrefix.
|
||||
* [BUGFIX] Closed gaps in metric consistency check.
|
||||
* [BUGFIX] Validate LabelName/LabelSet on JSON unmarshaling.
|
||||
* [ENHANCEMENT] Document the possibility to create "empty" metrics in
|
||||
a metric vector.
|
||||
* [ENHANCEMENT] Fix and clarify various doc comments and the README.md.
|
||||
* [ENHANCEMENT] (Kind of) solve "The Proxy Problem" of http.InstrumentHandler.
|
||||
* [ENHANCEMENT] Change responseWriterDelegator.written to int64.
|
||||
|
||||
## 0.6.0 / 2015-06-01
|
||||
* [CHANGE] Rename process_goroutines to go_goroutines.
|
||||
* [ENHANCEMENT] Validate label names during YAML decoding.
|
||||
* [ENHANCEMENT] Add LabelName regular expression.
|
||||
* [BUGFIX] Ensure alignment of struct members for 32-bit systems.
|
||||
|
||||
## 0.5.0 / 2015-05-06
|
||||
* [BUGFIX] Removed a weakness in the fingerprinting aka signature code.
|
||||
This makes fingerprinting slower and more allocation-heavy, but the
|
||||
weakness was too severe to be tolerated.
|
||||
* [CHANGE] As a result of the above, Metric.Fingerprint is now returning
|
||||
a different fingerprint. To keep the same fingerprint, the new method
|
||||
Metric.FastFingerprint was introduced, which will be used by the
|
||||
Prometheus server for storage purposes (implying that a collision
|
||||
detection has to be added, too).
|
||||
* [ENHANCEMENT] The Metric.Equal and Metric.Before do not depend on
|
||||
fingerprinting anymore, removing the possibility of an undetected
|
||||
fingerprint collision.
|
||||
* [FEATURE] The Go collector in the exposition library includes garbage
|
||||
collection stats.
|
||||
* [FEATURE] The exposition library allows to create constant "throw-away"
|
||||
summaries and histograms.
|
||||
* [CHANGE] A number of new reserved labels and prefixes.
|
||||
|
||||
## 0.4.0 / 2015-04-08
|
||||
* [CHANGE] Return NaN when Summaries have no observations yet.
|
||||
* [BUGFIX] Properly handle Summary decay upon Write().
|
||||
* [BUGFIX] Fix the documentation link to the consumption library.
|
||||
* [FEATURE] Allow the metric family injection hook to merge with existing
|
||||
metric families.
|
||||
* [ENHANCEMENT] Removed cgo dependency and conditional compilation of procfs.
|
||||
* [MAINTENANCE] Adjusted to changes in matttproud/golang_protobuf_extensions.
|
||||
|
||||
## 0.3.2 / 2015-03-11
|
||||
* [BUGFIX] Fixed the receiver type of COWMetric.Set(). This method is
|
||||
only used by the Prometheus server internally.
|
||||
* [CLEANUP] Added licenses of vendored code left out by godep.
|
||||
|
||||
## 0.3.1 / 2015-03-04
|
||||
* [ENHANCEMENT] Switched fingerprinting functions from own free list to
|
||||
sync.Pool.
|
||||
* [CHANGE] Makefile uses Go 1.4.2 now (only relevant for examples and tests).
|
||||
|
||||
## 0.3.0 / 2015-03-03
|
||||
* [CHANGE] Changed the fingerprinting for metrics. THIS WILL INVALIDATE ALL
|
||||
PERSISTED FINGERPRINTS. IF YOU COMPILE THE PROMETHEUS SERVER WITH THIS
|
||||
VERSION, YOU HAVE TO WIPE THE PREVIOUSLY CREATED STORAGE.
|
||||
* [CHANGE] LabelValuesToSignature removed. (Nobody had used it, and it was
|
||||
arguably broken.)
|
||||
* [CHANGE] Vendored dependencies. Those are only used by the Makefile. If
|
||||
client_golang is used as a library, the vendoring will stay out of your way.
|
||||
* [BUGFIX] Remove a weakness in the fingerprinting for metrics. (This made
|
||||
the fingerprinting change above necessary.)
|
||||
* [FEATURE] Added new fingerprinting functions SignatureForLabels and
|
||||
SignatureWithoutLabels to be used by the Prometheus server. These functions
|
||||
require fewer allocations than the ones currently used by the server.
|
||||
|
||||
## 0.2.0 / 2015-02-23
|
||||
* [FEATURE] Introduce new Histagram metric type.
|
||||
* [CHANGE] Ignore process collector errors for now (better error handling
|
||||
pending).
|
||||
* [CHANGE] Use clear error interface for process pidFn.
|
||||
* [BUGFIX] Fix Go download links for several archs and OSes.
|
||||
* [ENHANCEMENT] Massively improve Gauge and Counter performance.
|
||||
* [ENHANCEMENT] Catch illegal label names for summaries in histograms.
|
||||
* [ENHANCEMENT] Reduce allocations during fingerprinting.
|
||||
* [ENHANCEMENT] Remove cgo dependency. procfs package will only be included if
|
||||
both cgo is available and the build is for an OS with procfs.
|
||||
* [CLEANUP] Clean up code style issues.
|
||||
* [CLEANUP] Mark slow test as such and exclude them from travis.
|
||||
* [CLEANUP] Update protobuf library package name.
|
||||
* [CLEANUP] Updated vendoring of beorn7/perks.
|
||||
|
||||
## 0.1.0 / 2015-02-02
|
||||
* [CLEANUP] Introduced semantic versioning and changelog. From now on,
|
||||
changes will be reported in this file.
|
||||
18
vendor/github.com/prometheus/client_golang/CONTRIBUTING.md
generated
vendored
Normal file
18
vendor/github.com/prometheus/client_golang/CONTRIBUTING.md
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Contributing
|
||||
|
||||
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 plan to do something more involved, first discuss your ideas
|
||||
on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers).
|
||||
This will avoid unnecessary work and surely give you and us a good deal
|
||||
of inspiration.
|
||||
|
||||
* Relevant coding style guidelines are the [Go Code Review
|
||||
Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments)
|
||||
and the _Formatting and style_ section of Peter Bourgon's [Go: Best
|
||||
Practices for Production
|
||||
Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style).
|
||||
201
vendor/github.com/prometheus/client_golang/LICENSE
generated
vendored
Normal file
201
vendor/github.com/prometheus/client_golang/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
28
vendor/github.com/prometheus/client_golang/NOTICE
generated
vendored
Normal file
28
vendor/github.com/prometheus/client_golang/NOTICE
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
Prometheus instrumentation library for Go applications
|
||||
Copyright 2012-2015 The Prometheus Authors
|
||||
|
||||
This product includes software developed at
|
||||
SoundCloud Ltd. (http://soundcloud.com/).
|
||||
|
||||
|
||||
The following components are included in this product:
|
||||
|
||||
goautoneg
|
||||
http://bitbucket.org/ww/goautoneg
|
||||
Copyright 2011, Open Knowledge Foundation Ltd.
|
||||
See README.txt for license details.
|
||||
|
||||
perks - a fork of https://github.com/bmizerany/perks
|
||||
https://github.com/beorn7/perks
|
||||
Copyright 2013-2015 Blake Mizerany, Björn Rabenstein
|
||||
See https://github.com/beorn7/perks/blob/master/README.md for license details.
|
||||
|
||||
Go support for Protocol Buffers - Google's data interchange format
|
||||
http://github.com/golang/protobuf/
|
||||
Copyright 2010 The Go Authors
|
||||
See source code for license details.
|
||||
|
||||
Support for streaming Protocol Buffer messages for the Go language (golang).
|
||||
https://github.com/matttproud/golang_protobuf_extensions
|
||||
Copyright 2013 Matt T. Proud
|
||||
Licensed under the Apache License, Version 2.0
|
||||
45
vendor/github.com/prometheus/client_golang/README.md
generated
vendored
Normal file
45
vendor/github.com/prometheus/client_golang/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Prometheus Go client library
|
||||
|
||||
[](https://travis-ci.org/prometheus/client_golang)
|
||||
|
||||
This is the [Go](http://golang.org) client library for
|
||||
[Prometheus](http://prometheus.io). It has two separate parts, one for
|
||||
instrumenting application code, and one for creating clients that talk to the
|
||||
Prometheus HTTP API.
|
||||
|
||||
## Instrumenting applications
|
||||
|
||||
[](http://gocover.io/github.com/prometheus/client_golang/prometheus) [](https://godoc.org/github.com/prometheus/client_golang/prometheus)
|
||||
|
||||
The
|
||||
[`prometheus` directory](https://github.com/prometheus/client_golang/tree/master/prometheus)
|
||||
contains the instrumentation library. See the
|
||||
[best practices section](http://prometheus.io/docs/practices/naming/) of the
|
||||
Prometheus documentation to learn more about instrumenting applications.
|
||||
|
||||
The
|
||||
[`examples` directory](https://github.com/prometheus/client_golang/tree/master/examples)
|
||||
contains simple examples of instrumented code.
|
||||
|
||||
## Client for the Prometheus HTTP API
|
||||
|
||||
[](http://gocover.io/github.com/prometheus/client_golang/api/prometheus) [](https://godoc.org/github.com/prometheus/client_golang/api/prometheus)
|
||||
|
||||
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.
|
||||
|
||||
## Where is `model`, `extraction`, and `text`?
|
||||
|
||||
The `model` packages has been moved to
|
||||
[`prometheus/common/model`](https://github.com/prometheus/common/tree/master/model).
|
||||
|
||||
The `extraction` and `text` packages are now contained in
|
||||
[`prometheus/common/expfmt`](https://github.com/prometheus/common/tree/master/expfmt).
|
||||
|
||||
## Contributing and community
|
||||
|
||||
See the [contributing guidelines](CONTRIBUTING.md) and the
|
||||
[Community section](http://prometheus.io/community/) of the homepage.
|
||||
1
vendor/github.com/prometheus/client_golang/VERSION
generated
vendored
Normal file
1
vendor/github.com/prometheus/client_golang/VERSION
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
0.7.0
|
||||
341
vendor/github.com/prometheus/client_golang/api/prometheus/api.go
generated
vendored
Normal file
341
vendor/github.com/prometheus/client_golang/api/prometheus/api.go
generated
vendored
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
// 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.
|
||||
|
||||
// Package prometheus provides bindings to the Prometheus HTTP API:
|
||||
// http://prometheus.io/docs/querying/api/
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
type ErrorType string
|
||||
|
||||
const (
|
||||
// The different API error types.
|
||||
ErrBadData ErrorType = "bad_data"
|
||||
ErrTimeout = "timeout"
|
||||
ErrCanceled = "canceled"
|
||||
ErrExec = "execution"
|
||||
ErrBadResponse = "bad_response"
|
||||
)
|
||||
|
||||
// Error is an error returned by the API.
|
||||
type Error struct {
|
||||
Type ErrorType
|
||||
Msg string
|
||||
}
|
||||
|
||||
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.
|
||||
func New(cfg Config) (Client, error) {
|
||||
u, err := url.Parse(cfg.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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.
|
||||
Start, End time.Time
|
||||
// The maximum time between two slices within the boundaries.
|
||||
Step time.Duration
|
||||
}
|
||||
|
||||
// queryResult contains result data for a query.
|
||||
type queryResult struct {
|
||||
Type model.ValueType `json:"resultType"`
|
||||
Result interface{} `json:"result"`
|
||||
|
||||
// The decoded value.
|
||||
v model.Value
|
||||
}
|
||||
|
||||
func (qr *queryResult) UnmarshalJSON(b []byte) error {
|
||||
v := struct {
|
||||
Type model.ValueType `json:"resultType"`
|
||||
Result json.RawMessage `json:"result"`
|
||||
}{}
|
||||
|
||||
err := json.Unmarshal(b, &v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch v.Type {
|
||||
case model.ValScalar:
|
||||
var sv model.Scalar
|
||||
err = json.Unmarshal(v.Result, &sv)
|
||||
qr.v = &sv
|
||||
|
||||
case model.ValVector:
|
||||
var vv model.Vector
|
||||
err = json.Unmarshal(v.Result, &vv)
|
||||
qr.v = vv
|
||||
|
||||
case model.ValMatrix:
|
||||
var mv model.Matrix
|
||||
err = json.Unmarshal(v.Result, &mv)
|
||||
qr.v = mv
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("unexpected value type %q", v.Type)
|
||||
}
|
||||
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.
|
||||
func NewQueryAPI(c Client) QueryAPI {
|
||||
return &httpQueryAPI{client: apiClient{c}}
|
||||
}
|
||||
|
||||
type httpQueryAPI struct {
|
||||
client Client
|
||||
}
|
||||
|
||||
func (h *httpQueryAPI) 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)
|
||||
q.Set("time", ts.Format(time.RFC3339Nano))
|
||||
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
req, _ := http.NewRequest("GET", u.String(), nil)
|
||||
|
||||
_, body, err := h.client.do(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var qres queryResult
|
||||
err = json.Unmarshal(body, &qres)
|
||||
|
||||
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)
|
||||
q := u.Query()
|
||||
|
||||
var (
|
||||
start = r.Start.Format(time.RFC3339Nano)
|
||||
end = r.End.Format(time.RFC3339Nano)
|
||||
step = strconv.FormatFloat(r.Step.Seconds(), 'f', 3, 64)
|
||||
)
|
||||
|
||||
q.Set("query", query)
|
||||
q.Set("start", start)
|
||||
q.Set("end", end)
|
||||
q.Set("step", step)
|
||||
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
req, _ := http.NewRequest("GET", u.String(), nil)
|
||||
|
||||
_, body, err := h.client.do(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var qres queryResult
|
||||
err = json.Unmarshal(body, &qres)
|
||||
|
||||
return model.Value(qres.v), err
|
||||
}
|
||||
453
vendor/github.com/prometheus/client_golang/api/prometheus/api_test.go
generated
vendored
Normal file
453
vendor/github.com/prometheus/client_golang/api/prometheus/api_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
// 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.
|
||||
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"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")
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type testClient struct {
|
||||
*testing.T
|
||||
|
||||
ch chan apiClientTest
|
||||
req *http.Request
|
||||
}
|
||||
|
||||
type apiClientTest struct {
|
||||
code int
|
||||
response interface{}
|
||||
expected string
|
||||
err *Error
|
||||
}
|
||||
|
||||
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) {
|
||||
if ctx == nil {
|
||||
c.Fatalf("context was not passed down")
|
||||
}
|
||||
if req != c.req {
|
||||
c.Fatalf("request was not passed down")
|
||||
}
|
||||
|
||||
test := <-c.ch
|
||||
|
||||
var b []byte
|
||||
var err error
|
||||
|
||||
switch v := test.response.(type) {
|
||||
case string:
|
||||
b = []byte(v)
|
||||
default:
|
||||
b, err = json.Marshal(v)
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
resp := &http.Response{
|
||||
StatusCode: test.code,
|
||||
}
|
||||
|
||||
return resp, b, nil
|
||||
}
|
||||
|
||||
func TestAPIClientDo(t *testing.T) {
|
||||
tests := []apiClientTest{
|
||||
{
|
||||
response: &apiResponse{
|
||||
Status: "error",
|
||||
Data: json.RawMessage(`null`),
|
||||
ErrorType: ErrBadData,
|
||||
Error: "failed",
|
||||
},
|
||||
err: &Error{
|
||||
Type: ErrBadData,
|
||||
Msg: "failed",
|
||||
},
|
||||
code: statusAPIError,
|
||||
expected: `null`,
|
||||
},
|
||||
{
|
||||
response: &apiResponse{
|
||||
Status: "error",
|
||||
Data: json.RawMessage(`"test"`),
|
||||
ErrorType: ErrTimeout,
|
||||
Error: "timed out",
|
||||
},
|
||||
err: &Error{
|
||||
Type: ErrTimeout,
|
||||
Msg: "timed out",
|
||||
},
|
||||
code: statusAPIError,
|
||||
expected: `test`,
|
||||
},
|
||||
{
|
||||
response: "bad json",
|
||||
err: &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: "bad response code 400",
|
||||
},
|
||||
code: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
response: "bad json",
|
||||
err: &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: "invalid character 'b' looking for beginning of value",
|
||||
},
|
||||
code: statusAPIError,
|
||||
},
|
||||
{
|
||||
response: &apiResponse{
|
||||
Status: "success",
|
||||
Data: json.RawMessage(`"test"`),
|
||||
},
|
||||
err: &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: "inconsistent body for response code",
|
||||
},
|
||||
code: statusAPIError,
|
||||
},
|
||||
{
|
||||
response: &apiResponse{
|
||||
Status: "success",
|
||||
Data: json.RawMessage(`"test"`),
|
||||
ErrorType: ErrTimeout,
|
||||
Error: "timed out",
|
||||
},
|
||||
err: &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: "inconsistent body for response code",
|
||||
},
|
||||
code: statusAPIError,
|
||||
},
|
||||
{
|
||||
response: &apiResponse{
|
||||
Status: "error",
|
||||
Data: json.RawMessage(`"test"`),
|
||||
ErrorType: ErrTimeout,
|
||||
Error: "timed out",
|
||||
},
|
||||
err: &Error{
|
||||
Type: ErrBadResponse,
|
||||
Msg: "inconsistent body for response code",
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
tc := &testClient{
|
||||
T: t,
|
||||
ch: make(chan apiClientTest, 1),
|
||||
req: &http.Request{},
|
||||
}
|
||||
client := &apiClient{tc}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
tc.ch <- test
|
||||
|
||||
_, body, err := client.do(context.Background(), tc.req)
|
||||
|
||||
if test.err != nil {
|
||||
if err == nil {
|
||||
t.Errorf("expected error %q but got none", test.err)
|
||||
continue
|
||||
}
|
||||
if test.err.Error() != err.Error() {
|
||||
t.Errorf("unexpected error: want %q, got %q", test.err, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("unexpeceted error %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
want, got := test.expected, string(body)
|
||||
if want != got {
|
||||
t.Errorf("unexpected body: want %q, got %q", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
103
vendor/github.com/prometheus/client_golang/examples/random/main.go
generated
vendored
Normal file
103
vendor/github.com/prometheus/client_golang/examples/random/main.go
generated
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// 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.
|
||||
|
||||
// A simple example exposing fictional RPC latencies with different types of
|
||||
// random distributions (uniform, normal, and exponential) as Prometheus
|
||||
// metrics.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
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.")
|
||||
oscillationPeriod = flag.Duration("oscillation-period", 10*time.Minute, "The duration of the rate oscillation period.")
|
||||
)
|
||||
|
||||
var (
|
||||
// Create a summary to track fictional interservice RPC latencies for three
|
||||
// distinct services with different latency distributions. These services are
|
||||
// differentiated via a "service" label.
|
||||
rpcDurations = prometheus.NewSummaryVec(
|
||||
prometheus.SummaryOpts{
|
||||
Name: "rpc_durations_microseconds",
|
||||
Help: "RPC latency distributions.",
|
||||
},
|
||||
[]string{"service"},
|
||||
)
|
||||
// The same as above, but now as a histogram, and only for the normal
|
||||
// distribution. The buckets are targeted to the parameters of the
|
||||
// normal distribution, with 20 buckets centered on the mean, each
|
||||
// half-sigma wide.
|
||||
rpcDurationsHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
|
||||
Name: "rpc_durations_histogram_microseconds",
|
||||
Help: "RPC latency distributions.",
|
||||
Buckets: prometheus.LinearBuckets(*normMean-5**normDomain, .5**normDomain, 20),
|
||||
})
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Register the summary and the histogram with Prometheus's default registry.
|
||||
prometheus.MustRegister(rpcDurations)
|
||||
prometheus.MustRegister(rpcDurationsHistogram)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
start := time.Now()
|
||||
|
||||
oscillationFactor := func() float64 {
|
||||
return 2 + math.Sin(math.Sin(2*math.Pi*float64(time.Since(start))/float64(*oscillationPeriod)))
|
||||
}
|
||||
|
||||
// Periodically record some sample latencies for the three services.
|
||||
go func() {
|
||||
for {
|
||||
v := rand.Float64() * *uniformDomain
|
||||
rpcDurations.WithLabelValues("uniform").Observe(v)
|
||||
time.Sleep(time.Duration(100*oscillationFactor()) * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
v := (rand.NormFloat64() * *normDomain) + *normMean
|
||||
rpcDurations.WithLabelValues("normal").Observe(v)
|
||||
rpcDurationsHistogram.Observe(v)
|
||||
time.Sleep(time.Duration(75*oscillationFactor()) * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
v := rand.ExpFloat64()
|
||||
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)
|
||||
}
|
||||
30
vendor/github.com/prometheus/client_golang/examples/simple/main.go
generated
vendored
Normal file
30
vendor/github.com/prometheus/client_golang/examples/simple/main.go
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// 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.
|
||||
|
||||
// A minimal example of how to include Prometheus instrumentation.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
1
vendor/github.com/prometheus/client_golang/prometheus/.gitignore
generated
vendored
Normal file
1
vendor/github.com/prometheus/client_golang/prometheus/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
command-line-arguments.test
|
||||
53
vendor/github.com/prometheus/client_golang/prometheus/README.md
generated
vendored
Normal file
53
vendor/github.com/prometheus/client_golang/prometheus/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# Overview
|
||||
This is the [Prometheus](http://www.prometheus.io) telemetric
|
||||
instrumentation client [Go](http://golang.org) client library. It
|
||||
enable authors to define process-space metrics for their servers and
|
||||
expose them through a web service interface for extraction,
|
||||
aggregation, and a whole slew of other post processing techniques.
|
||||
|
||||
# Installing
|
||||
$ go get github.com/prometheus/client_golang/prometheus
|
||||
|
||||
# Example
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
indexed = prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Namespace: "my_company",
|
||||
Subsystem: "indexer",
|
||||
Name: "documents_indexed",
|
||||
Help: "The number of documents indexed.",
|
||||
})
|
||||
size = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "my_company",
|
||||
Subsystem: "storage",
|
||||
Name: "documents_total_size_bytes",
|
||||
Help: "The total size of all documents in the storage.",
|
||||
})
|
||||
)
|
||||
|
||||
func main() {
|
||||
http.Handle("/metrics", prometheus.Handler())
|
||||
|
||||
indexed.Inc()
|
||||
size.Set(5)
|
||||
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
|
||||
func init() {
|
||||
prometheus.MustRegister(indexed)
|
||||
prometheus.MustRegister(size)
|
||||
}
|
||||
```
|
||||
|
||||
# Documentation
|
||||
|
||||
[](https://godoc.org/github.com/prometheus/client_golang)
|
||||
159
vendor/github.com/prometheus/client_golang/prometheus/benchmark_test.go
generated
vendored
Normal file
159
vendor/github.com/prometheus/client_golang/prometheus/benchmark_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkCounterWithLabelValues(b *testing.B) {
|
||||
m := NewCounterVec(
|
||||
CounterOpts{
|
||||
Name: "benchmark_counter",
|
||||
Help: "A counter to benchmark it.",
|
||||
},
|
||||
[]string{"one", "two", "three"},
|
||||
)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.WithLabelValues("eins", "zwei", "drei").Inc()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCounterWithMappedLabels(b *testing.B) {
|
||||
m := NewCounterVec(
|
||||
CounterOpts{
|
||||
Name: "benchmark_counter",
|
||||
Help: "A counter to benchmark it.",
|
||||
},
|
||||
[]string{"one", "two", "three"},
|
||||
)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.With(Labels{"two": "zwei", "one": "eins", "three": "drei"}).Inc()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCounterWithPreparedMappedLabels(b *testing.B) {
|
||||
m := NewCounterVec(
|
||||
CounterOpts{
|
||||
Name: "benchmark_counter",
|
||||
Help: "A counter to benchmark it.",
|
||||
},
|
||||
[]string{"one", "two", "three"},
|
||||
)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
labels := Labels{"two": "zwei", "one": "eins", "three": "drei"}
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.With(labels).Inc()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCounterNoLabels(b *testing.B) {
|
||||
m := NewCounter(CounterOpts{
|
||||
Name: "benchmark_counter",
|
||||
Help: "A counter to benchmark it.",
|
||||
})
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.Inc()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGaugeWithLabelValues(b *testing.B) {
|
||||
m := NewGaugeVec(
|
||||
GaugeOpts{
|
||||
Name: "benchmark_gauge",
|
||||
Help: "A gauge to benchmark it.",
|
||||
},
|
||||
[]string{"one", "two", "three"},
|
||||
)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.WithLabelValues("eins", "zwei", "drei").Set(3.1415)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGaugeNoLabels(b *testing.B) {
|
||||
m := NewGauge(GaugeOpts{
|
||||
Name: "benchmark_gauge",
|
||||
Help: "A gauge to benchmark it.",
|
||||
})
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.Set(3.1415)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSummaryWithLabelValues(b *testing.B) {
|
||||
m := NewSummaryVec(
|
||||
SummaryOpts{
|
||||
Name: "benchmark_summary",
|
||||
Help: "A summary to benchmark it.",
|
||||
},
|
||||
[]string{"one", "two", "three"},
|
||||
)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.WithLabelValues("eins", "zwei", "drei").Observe(3.1415)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSummaryNoLabels(b *testing.B) {
|
||||
m := NewSummary(SummaryOpts{
|
||||
Name: "benchmark_summary",
|
||||
Help: "A summary to benchmark it.",
|
||||
},
|
||||
)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.Observe(3.1415)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHistogramWithLabelValues(b *testing.B) {
|
||||
m := NewHistogramVec(
|
||||
HistogramOpts{
|
||||
Name: "benchmark_histogram",
|
||||
Help: "A histogram to benchmark it.",
|
||||
},
|
||||
[]string{"one", "two", "three"},
|
||||
)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.WithLabelValues("eins", "zwei", "drei").Observe(3.1415)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHistogramNoLabels(b *testing.B) {
|
||||
m := NewHistogram(HistogramOpts{
|
||||
Name: "benchmark_histogram",
|
||||
Help: "A histogram to benchmark it.",
|
||||
},
|
||||
)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
m.Observe(3.1415)
|
||||
}
|
||||
}
|
||||
75
vendor/github.com/prometheus/client_golang/prometheus/collector.go
generated
vendored
Normal file
75
vendor/github.com/prometheus/client_golang/prometheus/collector.go
generated
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// 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
|
||||
|
||||
// Collector is the interface implemented by anything that can be used by
|
||||
// Prometheus to collect metrics. A Collector has to be registered for
|
||||
// collection. See Register, MustRegister, RegisterOrGet, and MustRegisterOrGet.
|
||||
//
|
||||
// The stock metrics provided by this package (like Gauge, Counter, Summary) are
|
||||
// also Collectors (which only ever collect one metric, namely itself). An
|
||||
// implementer of Collector may, however, collect multiple metrics in a
|
||||
// coordinated fashion and/or create metrics on the fly. Examples for collectors
|
||||
// already implemented in this library are the metric vectors (i.e. collection
|
||||
// of multiple instances of the same Metric but with different label values)
|
||||
// like GaugeVec or SummaryVec, and the ExpvarCollector.
|
||||
type Collector interface {
|
||||
// Describe sends the super-set of all possible descriptors of metrics
|
||||
// collected by this Collector to the provided channel and returns once
|
||||
// the last descriptor has been sent. The sent descriptors fulfill the
|
||||
// consistency and uniqueness requirements described in the Desc
|
||||
// documentation. (It is valid if one and the same Collector sends
|
||||
// duplicate descriptors. Those duplicates are simply ignored. However,
|
||||
// two different Collectors must not send duplicate descriptors.) This
|
||||
// method idempotently sends the same descriptors throughout the
|
||||
// lifetime of the Collector. If a Collector encounters an error while
|
||||
// executing this method, it must send an invalid descriptor (created
|
||||
// with NewInvalidDesc) to signal the error to the registry.
|
||||
Describe(chan<- *Desc)
|
||||
// Collect is called by Prometheus when collecting metrics. The
|
||||
// implementation sends each collected metric via the provided channel
|
||||
// and returns once the last metric has been sent. The descriptor of
|
||||
// each sent metric is one of those returned by Describe. Returned
|
||||
// metrics that share the same descriptor must differ in their variable
|
||||
// label values. This method may be called concurrently and must
|
||||
// therefore be implemented in a concurrency safe way. Blocking occurs
|
||||
// at the expense of total performance of rendering all registered
|
||||
// metrics. Ideally, Collector implementations support concurrent
|
||||
// readers.
|
||||
Collect(chan<- Metric)
|
||||
}
|
||||
|
||||
// SelfCollector implements Collector for a single Metric so that that the
|
||||
// Metric collects itself. Add it as an anonymous field to a struct that
|
||||
// implements Metric, and call Init with the Metric itself as an argument.
|
||||
type SelfCollector struct {
|
||||
self Metric
|
||||
}
|
||||
|
||||
// Init provides the SelfCollector with a reference to the metric it is supposed
|
||||
// to collect. It is usually called within the factory function to create a
|
||||
// metric. See example.
|
||||
func (c *SelfCollector) Init(self Metric) {
|
||||
c.self = self
|
||||
}
|
||||
|
||||
// Describe implements Collector.
|
||||
func (c *SelfCollector) Describe(ch chan<- *Desc) {
|
||||
ch <- c.self.Desc()
|
||||
}
|
||||
|
||||
// Collect implements Collector.
|
||||
func (c *SelfCollector) Collect(ch chan<- Metric) {
|
||||
ch <- c.self
|
||||
}
|
||||
175
vendor/github.com/prometheus/client_golang/prometheus/counter.go
generated
vendored
Normal file
175
vendor/github.com/prometheus/client_golang/prometheus/counter.go
generated
vendored
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"hash/fnv"
|
||||
)
|
||||
|
||||
// Counter is a Metric that represents a single numerical value that only ever
|
||||
// goes up. That implies that it cannot be used to count items whose number can
|
||||
// also go down, e.g. the number of currently running goroutines. Those
|
||||
// "counters" are represented by Gauges.
|
||||
//
|
||||
// A Counter is typically used to count requests served, tasks completed, errors
|
||||
// occurred, etc.
|
||||
//
|
||||
// To create Counter instances, use NewCounter.
|
||||
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).
|
||||
Set(float64)
|
||||
// Inc increments the counter by 1.
|
||||
Inc()
|
||||
// Add adds the given value to the counter. It panics if the value is <
|
||||
// 0.
|
||||
Add(float64)
|
||||
}
|
||||
|
||||
// CounterOpts is an alias for Opts. See there for doc comments.
|
||||
type CounterOpts Opts
|
||||
|
||||
// NewCounter creates a new Counter based on the provided CounterOpts.
|
||||
func NewCounter(opts CounterOpts) Counter {
|
||||
desc := NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
nil,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
result := &counter{value: value{desc: desc, valType: CounterValue, labelPairs: desc.constLabelPairs}}
|
||||
result.Init(result) // Init self-collection.
|
||||
return result
|
||||
}
|
||||
|
||||
type counter struct {
|
||||
value
|
||||
}
|
||||
|
||||
func (c *counter) Add(v float64) {
|
||||
if v < 0 {
|
||||
panic(errors.New("counter cannot decrease in value"))
|
||||
}
|
||||
c.value.Add(v)
|
||||
}
|
||||
|
||||
// CounterVec is a Collector that bundles a set of Counters that all share the
|
||||
// same Desc, but have different values for their variable labels. This is used
|
||||
// if you want to count the same thing partitioned by various dimensions
|
||||
// (e.g. number of HTTP requests, partitioned by response code and
|
||||
// method). Create instances with NewCounterVec.
|
||||
//
|
||||
// CounterVec embeds MetricVec. See there for a full list of methods with
|
||||
// detailed documentation.
|
||||
type CounterVec struct {
|
||||
MetricVec
|
||||
}
|
||||
|
||||
// NewCounterVec creates a new CounterVec based on the provided CounterOpts and
|
||||
// partitioned by the given label names. At least one label name must be
|
||||
// provided.
|
||||
func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
|
||||
desc := NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
labelNames,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
return &CounterVec{
|
||||
MetricVec: MetricVec{
|
||||
children: map[uint64]Metric{},
|
||||
desc: desc,
|
||||
hash: fnv.New64a(),
|
||||
newMetric: func(lvs ...string) Metric {
|
||||
result := &counter{value: value{
|
||||
desc: desc,
|
||||
valType: CounterValue,
|
||||
labelPairs: makeLabelPairs(desc, lvs),
|
||||
}}
|
||||
result.Init(result) // Init self-collection.
|
||||
return result
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetMetricWithLabelValues replaces the method of the same name in
|
||||
// MetricVec. The difference is that this method returns a Counter and not a
|
||||
// Metric so that no type conversion is required.
|
||||
func (m *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
|
||||
metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||
if metric != nil {
|
||||
return metric.(Counter), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetMetricWith replaces the method of the same name in MetricVec. The
|
||||
// difference is that this method returns a Counter and not a Metric so that no
|
||||
// type conversion is required.
|
||||
func (m *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
|
||||
metric, err := m.MetricVec.GetMetricWith(labels)
|
||||
if metric != nil {
|
||||
return metric.(Counter), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
||||
// GetMetricWithLabelValues would have returned an error. By not returning an
|
||||
// error, WithLabelValues allows shortcuts like
|
||||
// myVec.WithLabelValues("404", "GET").Add(42)
|
||||
func (m *CounterVec) WithLabelValues(lvs ...string) Counter {
|
||||
return m.MetricVec.WithLabelValues(lvs...).(Counter)
|
||||
}
|
||||
|
||||
// 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"}).Add(42)
|
||||
func (m *CounterVec) With(labels Labels) Counter {
|
||||
return m.MetricVec.With(labels).(Counter)
|
||||
}
|
||||
|
||||
// CounterFunc is a Counter whose value is determined at collect time by calling a
|
||||
// provided function.
|
||||
//
|
||||
// To create CounterFunc instances, use NewCounterFunc.
|
||||
type CounterFunc interface {
|
||||
Metric
|
||||
Collector
|
||||
}
|
||||
|
||||
// NewCounterFunc creates a new CounterFunc based on the provided
|
||||
// CounterOpts. The value reported is determined by calling the given function
|
||||
// from within the Write method. Take into account that metric collection may
|
||||
// happen concurrently. If that results in concurrent calls to Write, like in
|
||||
// the case where a CounterFunc is directly registered with Prometheus, the
|
||||
// provided function must be concurrency-safe. The function should also honor
|
||||
// the contract for a Counter (values only go up, not down), but compliance will
|
||||
// not be checked.
|
||||
func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc {
|
||||
return newValueFunc(NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
nil,
|
||||
opts.ConstLabels,
|
||||
), CounterValue, function)
|
||||
}
|
||||
58
vendor/github.com/prometheus/client_golang/prometheus/counter_test.go
generated
vendored
Normal file
58
vendor/github.com/prometheus/client_golang/prometheus/counter_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
func TestCounterAdd(t *testing.T) {
|
||||
counter := NewCounter(CounterOpts{
|
||||
Name: "test",
|
||||
Help: "test help",
|
||||
ConstLabels: Labels{"a": "1", "b": "2"},
|
||||
}).(*counter)
|
||||
counter.Inc()
|
||||
if expected, got := 1., math.Float64frombits(counter.valBits); expected != got {
|
||||
t.Errorf("Expected %f, got %f.", expected, got)
|
||||
}
|
||||
counter.Add(42)
|
||||
if expected, got := 43., math.Float64frombits(counter.valBits); expected != got {
|
||||
t.Errorf("Expected %f, got %f.", expected, got)
|
||||
}
|
||||
|
||||
if expected, got := "counter cannot decrease in value", decreaseCounter(counter).Error(); expected != got {
|
||||
t.Errorf("Expected error %q, got %q.", expected, got)
|
||||
}
|
||||
|
||||
m := &dto.Metric{}
|
||||
counter.Write(m)
|
||||
|
||||
if expected, got := `label:<name:"a" value:"1" > label:<name:"b" value:"2" > counter:<value:43 > `, m.String(); expected != got {
|
||||
t.Errorf("expected %q, got %q", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func decreaseCounter(c *counter) (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = e.(error)
|
||||
}
|
||||
}()
|
||||
c.Add(-1)
|
||||
return nil
|
||||
}
|
||||
201
vendor/github.com/prometheus/client_golang/prometheus/desc.go
generated
vendored
Normal file
201
vendor/github.com/prometheus/client_golang/prometheus/desc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
package prometheus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
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 = "__"
|
||||
|
||||
// Labels represents a collection of label name -> value mappings. This type is
|
||||
// commonly used with the With(Labels) and GetMetricWith(Labels) methods of
|
||||
// metric vector Collectors, e.g.:
|
||||
// myVec.With(Labels{"code": "404", "method": "GET"}).Add(42)
|
||||
//
|
||||
// The other use-case is the specification of constant label pairs in Opts or to
|
||||
// create a Desc.
|
||||
type Labels map[string]string
|
||||
|
||||
// Desc is the descriptor used by every Prometheus Metric. It is essentially
|
||||
// the immutable meta-data of a Metric. The normal Metric implementations
|
||||
// included in this package manage their Desc under the hood. Users only have to
|
||||
// deal with Desc if they use advanced features like the ExpvarCollector or
|
||||
// custom Collectors and Metrics.
|
||||
//
|
||||
// Descriptors registered with the same registry have to fulfill certain
|
||||
// consistency and uniqueness criteria if they share the same fully-qualified
|
||||
// name: They must have the same help string and the same label names (aka label
|
||||
// dimensions) in each, constLabels and variableLabels, but they must differ in
|
||||
// the values of the constLabels.
|
||||
//
|
||||
// Descriptors that share the same fully-qualified names and the same label
|
||||
// values of their constLabels are considered equal.
|
||||
//
|
||||
// Use NewDesc to create new Desc instances.
|
||||
type Desc struct {
|
||||
// fqName has been built from Namespace, Subsystem, and Name.
|
||||
fqName string
|
||||
// help provides some helpful information about this metric.
|
||||
help string
|
||||
// constLabelPairs contains precalculated DTO label pairs based on
|
||||
// the constant labels.
|
||||
constLabelPairs []*dto.LabelPair
|
||||
// VariableLabels contains names of labels for which the metric
|
||||
// maintains variable values.
|
||||
variableLabels []string
|
||||
// id is a hash of the values of the ConstLabels and fqName. This
|
||||
// must be unique among all registered descriptors and can therefore be
|
||||
// used as an identifier of the descriptor.
|
||||
id uint64
|
||||
// dimHash is a hash of the label names (preset and variable) and the
|
||||
// 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
|
||||
// registration time.
|
||||
err error
|
||||
}
|
||||
|
||||
// NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc
|
||||
// and will be reported on registration time. variableLabels and constLabels can
|
||||
// be nil if no such labels should be set. fqName and help must not be empty.
|
||||
//
|
||||
// variableLabels only contain the label names. Their label values are variable
|
||||
// and therefore not part of the Desc. (They are managed within the Metric.)
|
||||
//
|
||||
// For constLabels, the label values are constant. Therefore, they are fully
|
||||
// specified in the Desc. See the Opts documentation for the implications of
|
||||
// constant labels.
|
||||
func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *Desc {
|
||||
d := &Desc{
|
||||
fqName: fqName,
|
||||
help: help,
|
||||
variableLabels: variableLabels,
|
||||
}
|
||||
if help == "" {
|
||||
d.err = errors.New("empty help string")
|
||||
return d
|
||||
}
|
||||
if !metricNameRE.MatchString(fqName) {
|
||||
d.err = fmt.Errorf("%q is not a valid metric name", fqName)
|
||||
return d
|
||||
}
|
||||
// labelValues contains the label values of const labels (in order of
|
||||
// their sorted label names) plus the fqName (at position 0).
|
||||
labelValues := make([]string, 1, len(constLabels)+1)
|
||||
labelValues[0] = fqName
|
||||
labelNames := make([]string, 0, len(constLabels)+len(variableLabels))
|
||||
labelNameSet := map[string]struct{}{}
|
||||
// First add only the const label names and sort them...
|
||||
for labelName := range constLabels {
|
||||
if !checkLabelName(labelName) {
|
||||
d.err = fmt.Errorf("%q is not a valid label name", labelName)
|
||||
return d
|
||||
}
|
||||
labelNames = append(labelNames, labelName)
|
||||
labelNameSet[labelName] = struct{}{}
|
||||
}
|
||||
sort.Strings(labelNames)
|
||||
// ... so that we can now add const label values in the order of their names.
|
||||
for _, labelName := range labelNames {
|
||||
labelValues = append(labelValues, constLabels[labelName])
|
||||
}
|
||||
// Now add the variable label names, but prefix them with something that
|
||||
// cannot be in a regular label name. That prevents matching the label
|
||||
// dimension with a different mix between preset and variable labels.
|
||||
for _, labelName := range variableLabels {
|
||||
if !checkLabelName(labelName) {
|
||||
d.err = fmt.Errorf("%q is not a valid label name", labelName)
|
||||
return d
|
||||
}
|
||||
labelNames = append(labelNames, "$"+labelName)
|
||||
labelNameSet[labelName] = struct{}{}
|
||||
}
|
||||
if len(labelNames) != len(labelNameSet) {
|
||||
d.err = errors.New("duplicate label names")
|
||||
return d
|
||||
}
|
||||
h := fnv.New64a()
|
||||
var b bytes.Buffer // To copy string contents into, avoiding []byte allocations.
|
||||
for _, val := range labelValues {
|
||||
b.Reset()
|
||||
b.WriteString(val)
|
||||
b.WriteByte(separatorByte)
|
||||
h.Write(b.Bytes())
|
||||
}
|
||||
d.id = h.Sum64()
|
||||
// Sort labelNames so that order doesn't matter for the hash.
|
||||
sort.Strings(labelNames)
|
||||
// Now hash together (in this order) the help string and the sorted
|
||||
// label names.
|
||||
h.Reset()
|
||||
b.Reset()
|
||||
b.WriteString(help)
|
||||
b.WriteByte(separatorByte)
|
||||
h.Write(b.Bytes())
|
||||
for _, labelName := range labelNames {
|
||||
b.Reset()
|
||||
b.WriteString(labelName)
|
||||
b.WriteByte(separatorByte)
|
||||
h.Write(b.Bytes())
|
||||
}
|
||||
d.dimHash = h.Sum64()
|
||||
|
||||
d.constLabelPairs = make([]*dto.LabelPair, 0, len(constLabels))
|
||||
for n, v := range constLabels {
|
||||
d.constLabelPairs = append(d.constLabelPairs, &dto.LabelPair{
|
||||
Name: proto.String(n),
|
||||
Value: proto.String(v),
|
||||
})
|
||||
}
|
||||
sort.Sort(LabelPairSorter(d.constLabelPairs))
|
||||
return d
|
||||
}
|
||||
|
||||
// NewInvalidDesc returns an invalid descriptor, i.e. a descriptor with the
|
||||
// provided error set. If a collector returning such a descriptor is registered,
|
||||
// registration will fail with the provided error. NewInvalidDesc can be used by
|
||||
// a Collector to signal inability to describe itself.
|
||||
func NewInvalidDesc(err error) *Desc {
|
||||
return &Desc{
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Desc) String() string {
|
||||
lpStrings := make([]string, 0, len(d.constLabelPairs))
|
||||
for _, lp := range d.constLabelPairs {
|
||||
lpStrings = append(
|
||||
lpStrings,
|
||||
fmt.Sprintf("%s=%q", lp.GetName(), lp.GetValue()),
|
||||
)
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"Desc{fqName: %q, help: %q, constLabels: {%s}, variableLabels: %v}",
|
||||
d.fqName,
|
||||
d.help,
|
||||
strings.Join(lpStrings, ","),
|
||||
d.variableLabels,
|
||||
)
|
||||
}
|
||||
|
||||
func checkLabelName(l string) bool {
|
||||
return labelNameRE.MatchString(l) &&
|
||||
!strings.HasPrefix(l, reservedLabelPrefix)
|
||||
}
|
||||
109
vendor/github.com/prometheus/client_golang/prometheus/doc.go
generated
vendored
Normal file
109
vendor/github.com/prometheus/client_golang/prometheus/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
// 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 provides embeddable metric primitives for servers and
|
||||
// standardized exposition of telemetry through a web services interface.
|
||||
//
|
||||
// All exported functions and methods are safe to be used concurrently unless
|
||||
// specified otherwise.
|
||||
//
|
||||
// To expose metrics registered with the Prometheus registry, an HTTP server
|
||||
// needs to know about the Prometheus handler. The usual endpoint is "/metrics".
|
||||
//
|
||||
// http.Handle("/metrics", prometheus.Handler())
|
||||
//
|
||||
// As a starting point a very basic usage example:
|
||||
//
|
||||
// package main
|
||||
//
|
||||
// import (
|
||||
// "net/http"
|
||||
//
|
||||
// "github.com/prometheus/client_golang/prometheus"
|
||||
// )
|
||||
//
|
||||
// var (
|
||||
// cpuTemp = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
// Name: "cpu_temperature_celsius",
|
||||
// Help: "Current temperature of the CPU.",
|
||||
// })
|
||||
// hdFailures = prometheus.NewCounter(prometheus.CounterOpts{
|
||||
// Name: "hd_errors_total",
|
||||
// Help: "Number of hard-disk errors.",
|
||||
// })
|
||||
// )
|
||||
//
|
||||
// func init() {
|
||||
// prometheus.MustRegister(cpuTemp)
|
||||
// prometheus.MustRegister(hdFailures)
|
||||
// }
|
||||
//
|
||||
// func main() {
|
||||
// cpuTemp.Set(65.3)
|
||||
// hdFailures.Inc()
|
||||
//
|
||||
// http.Handle("/metrics", prometheus.Handler())
|
||||
// http.ListenAndServe(":8080", nil)
|
||||
// }
|
||||
//
|
||||
//
|
||||
// This is a complete program that exports two metrics, a Gauge and a Counter.
|
||||
// It also exports some stats about the HTTP usage of the /metrics
|
||||
// endpoint. (See the Handler function for more detail.)
|
||||
//
|
||||
// Two more advanced metric types are the Summary and Histogram.
|
||||
//
|
||||
// In addition to the fundamental metric types Gauge, Counter, Summary, and
|
||||
// Histogram, a very important part of the Prometheus data model is the
|
||||
// partitioning of samples along dimensions called labels, which results in
|
||||
// metric vectors. The fundamental types are GaugeVec, CounterVec, SummaryVec,
|
||||
// and HistogramVec.
|
||||
//
|
||||
// Those are all the parts needed for basic usage. Detailed documentation and
|
||||
// examples are provided below.
|
||||
//
|
||||
// Everything else this package offers is essentially for "power users" only. A
|
||||
// few pointers to "power user features":
|
||||
//
|
||||
// All the various ...Opts structs have a ConstLabels field for labels that
|
||||
// never change their value (which is only useful under special circumstances,
|
||||
// see documentation of the Opts type).
|
||||
//
|
||||
// The Untyped metric behaves like a Gauge, but signals the Prometheus server
|
||||
// not to assume anything about its type.
|
||||
//
|
||||
// Functions to fine-tune how the metric registry works: EnableCollectChecks,
|
||||
// PanicOnCollectError, Register, Unregister, SetMetricFamilyInjectionHook.
|
||||
//
|
||||
// For custom metric collection, there are two entry points: Custom Metric
|
||||
// implementations and custom Collector implementations. A Metric is the
|
||||
// fundamental unit in the Prometheus data model: a sample at a point in time
|
||||
// together with its meta-data (like its fully-qualified name and any number of
|
||||
// pairs of label name and label value) that knows how to marshal itself into a
|
||||
// data transfer object (aka DTO, implemented as a protocol buffer). A Collector
|
||||
// gets registered with the Prometheus registry and manages the collection of
|
||||
// one or more Metrics. Many parts of this package are building blocks for
|
||||
// Metrics and Collectors. Desc is the metric descriptor, actually used by all
|
||||
// metrics under the hood, and by Collectors to describe the Metrics to be
|
||||
// collected, but only to be dealt with by users if they implement their own
|
||||
// Metrics or Collectors. To create a Desc, the BuildFQName function will come
|
||||
// in handy. Other useful components for Metric and Collector implementation
|
||||
// include: LabelPairSorter to sort the DTO version of label pairs,
|
||||
// NewConstMetric and MustNewConstMetric to create "throw away" Metrics at
|
||||
// collection time, MetricVec to bundle custom Metrics into a metric vector
|
||||
// Collector, SelfCollector to make a custom Metric collect itself.
|
||||
//
|
||||
// A good example for a custom Collector is the ExpVarCollector included in this
|
||||
// package, which exports variables exported via the "expvar" package as
|
||||
// Prometheus metrics.
|
||||
package prometheus
|
||||
130
vendor/github.com/prometheus/client_golang/prometheus/example_clustermanager_test.go
generated
vendored
Normal file
130
vendor/github.com/prometheus/client_golang/prometheus/example_clustermanager_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
// 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 (
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// ClusterManager is an example for a system that might have been built without
|
||||
// Prometheus in mind. It models a central manager of jobs running in a
|
||||
// cluster. To turn it into something that collects Prometheus metrics, we
|
||||
// simply add the two methods required for the Collector interface.
|
||||
//
|
||||
// An additional challenge is that multiple instances of the ClusterManager are
|
||||
// run within the same binary, each in charge of a different zone. We need to
|
||||
// make use of ConstLabels to be able to register each ClusterManager instance
|
||||
// with Prometheus.
|
||||
type ClusterManager struct {
|
||||
Zone string
|
||||
OOMCount *prometheus.CounterVec
|
||||
RAMUsage *prometheus.GaugeVec
|
||||
mtx sync.Mutex // Protects OOMCount and RAMUsage.
|
||||
// ... many more fields
|
||||
}
|
||||
|
||||
// ReallyExpensiveAssessmentOfTheSystemState is a mock for the data gathering a
|
||||
// real cluster manager would have to do. Since it may actually be really
|
||||
// expensive, it must only be called once per collection. This implementation,
|
||||
// obviously, only returns some made-up data.
|
||||
func (c *ClusterManager) ReallyExpensiveAssessmentOfTheSystemState() (
|
||||
oomCountByHost map[string]int, ramUsageByHost map[string]float64,
|
||||
) {
|
||||
// Just example fake data.
|
||||
oomCountByHost = map[string]int{
|
||||
"foo.example.org": 42,
|
||||
"bar.example.org": 2001,
|
||||
}
|
||||
ramUsageByHost = map[string]float64{
|
||||
"foo.example.org": 6.023e23,
|
||||
"bar.example.org": 3.14,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Describe faces the interesting challenge that the two metric vectors that are
|
||||
// used in this example are already Collectors themselves. However, thanks to
|
||||
// the use of channels, it is really easy to "chain" Collectors. Here we simply
|
||||
// call the Describe methods of the two metric vectors.
|
||||
func (c *ClusterManager) Describe(ch chan<- *prometheus.Desc) {
|
||||
c.OOMCount.Describe(ch)
|
||||
c.RAMUsage.Describe(ch)
|
||||
}
|
||||
|
||||
// Collect first triggers the ReallyExpensiveAssessmentOfTheSystemState. Then it
|
||||
// sets the retrieved values in the two metric vectors and then sends all their
|
||||
// metrics to the channel (again using a chaining technique as in the Describe
|
||||
// method). Since Collect could be called multiple times concurrently, that part
|
||||
// is protected by a mutex.
|
||||
func (c *ClusterManager) Collect(ch chan<- prometheus.Metric) {
|
||||
oomCountByHost, ramUsageByHost := c.ReallyExpensiveAssessmentOfTheSystemState()
|
||||
c.mtx.Lock()
|
||||
defer c.mtx.Unlock()
|
||||
for host, oomCount := range oomCountByHost {
|
||||
c.OOMCount.WithLabelValues(host).Set(float64(oomCount))
|
||||
}
|
||||
for host, ramUsage := range ramUsageByHost {
|
||||
c.RAMUsage.WithLabelValues(host).Set(ramUsage)
|
||||
}
|
||||
c.OOMCount.Collect(ch)
|
||||
c.RAMUsage.Collect(ch)
|
||||
// All metrics in OOMCount and RAMUsage are sent to the channel now. We
|
||||
// can safely reset the two metric vectors now, so that we can start
|
||||
// fresh in the next Collect cycle. (Imagine a host disappears from the
|
||||
// cluster. If we did not reset here, its Metric would stay in the
|
||||
// metric vectors forever.)
|
||||
c.OOMCount.Reset()
|
||||
c.RAMUsage.Reset()
|
||||
}
|
||||
|
||||
// NewClusterManager creates the two metric vectors OOMCount and RAMUsage. Note
|
||||
// that the zone is set as a ConstLabel. (It's different in each instance of the
|
||||
// ClusterManager, but constant over the lifetime of an instance.) The reported
|
||||
// values are partitioned by host, which is therefore a variable label.
|
||||
func NewClusterManager(zone string) *ClusterManager {
|
||||
return &ClusterManager{
|
||||
Zone: zone,
|
||||
OOMCount: prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Subsystem: "clustermanager",
|
||||
Name: "oom_count",
|
||||
Help: "number of OOM crashes",
|
||||
ConstLabels: prometheus.Labels{"zone": zone},
|
||||
},
|
||||
[]string{"host"},
|
||||
),
|
||||
RAMUsage: prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Subsystem: "clustermanager",
|
||||
Name: "ram_usage_bytes",
|
||||
Help: "RAM usage as reported to the cluster manager",
|
||||
ConstLabels: prometheus.Labels{"zone": zone},
|
||||
},
|
||||
[]string{"host"},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleCollector_clustermanager() {
|
||||
workerDB := NewClusterManager("db")
|
||||
workerCA := NewClusterManager("ca")
|
||||
prometheus.MustRegister(workerDB)
|
||||
prometheus.MustRegister(workerCA)
|
||||
|
||||
// Since we are dealing with custom Collector implementations, it might
|
||||
// be a good idea to enable the collect checks in the registry.
|
||||
prometheus.EnableCollectChecks(true)
|
||||
}
|
||||
87
vendor/github.com/prometheus/client_golang/prometheus/example_memstats_test.go
generated
vendored
Normal file
87
vendor/github.com/prometheus/client_golang/prometheus/example_memstats_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// 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 (
|
||||
"runtime"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
allocDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("", "memstats", "alloc_bytes"),
|
||||
"bytes allocated and still in use",
|
||||
nil, nil,
|
||||
)
|
||||
totalAllocDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("", "memstats", "total_alloc_bytes"),
|
||||
"bytes allocated (even if freed)",
|
||||
nil, nil,
|
||||
)
|
||||
numGCDesc = prometheus.NewDesc(
|
||||
prometheus.BuildFQName("", "memstats", "num_gc_total"),
|
||||
"number of GCs run",
|
||||
nil, nil,
|
||||
)
|
||||
)
|
||||
|
||||
// MemStatsCollector is an example for a custom Collector that solves the
|
||||
// problem of feeding into multiple metrics at the same time. The
|
||||
// runtime.ReadMemStats should happen only once, and then the results need to be
|
||||
// fed into a number of separate Metrics. In this example, only a few of the
|
||||
// values reported by ReadMemStats are used. For each, there is a Desc provided
|
||||
// as a var, so the MemStatsCollector itself needs nothing else in the
|
||||
// struct. Only the methods need to be implemented.
|
||||
type MemStatsCollector struct{}
|
||||
|
||||
// Describe just sends the three Desc objects for the Metrics we intend to
|
||||
// collect.
|
||||
func (_ MemStatsCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||
ch <- allocDesc
|
||||
ch <- totalAllocDesc
|
||||
ch <- numGCDesc
|
||||
}
|
||||
|
||||
// Collect does the trick by calling ReadMemStats once and then constructing
|
||||
// three different Metrics on the fly.
|
||||
func (_ MemStatsCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
var ms runtime.MemStats
|
||||
runtime.ReadMemStats(&ms)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
allocDesc,
|
||||
prometheus.GaugeValue,
|
||||
float64(ms.Alloc),
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
totalAllocDesc,
|
||||
prometheus.GaugeValue,
|
||||
float64(ms.TotalAlloc),
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
numGCDesc,
|
||||
prometheus.CounterValue,
|
||||
float64(ms.NumGC),
|
||||
)
|
||||
// To avoid new allocations on each collection, you could also keep
|
||||
// metric objects around and return the same objects each time, just
|
||||
// with new values set.
|
||||
}
|
||||
|
||||
func ExampleCollector_memstats() {
|
||||
prometheus.MustRegister(&MemStatsCollector{})
|
||||
// Since we are dealing with custom Collector implementations, it might
|
||||
// be a good idea to enable the collect checks in the registry.
|
||||
prometheus.EnableCollectChecks(true)
|
||||
}
|
||||
69
vendor/github.com/prometheus/client_golang/prometheus/example_selfcollector_test.go
generated
vendored
Normal file
69
vendor/github.com/prometheus/client_golang/prometheus/example_selfcollector_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// 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 (
|
||||
"runtime"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
func NewCallbackMetric(desc *prometheus.Desc, callback func() float64) *CallbackMetric {
|
||||
result := &CallbackMetric{desc: desc, callback: callback}
|
||||
result.Init(result) // Initialize the SelfCollector.
|
||||
return result
|
||||
}
|
||||
|
||||
// TODO: Come up with a better example.
|
||||
|
||||
// CallbackMetric is an example for a user-defined Metric that exports the
|
||||
// result of a function call as a metric of type "untyped" without any
|
||||
// labels. It uses SelfCollector to turn the Metric into a Collector so that it
|
||||
// can be registered with Prometheus.
|
||||
//
|
||||
// Note that this example is pretty much academic as the prometheus package
|
||||
// already provides an UntypedFunc type.
|
||||
type CallbackMetric struct {
|
||||
prometheus.SelfCollector
|
||||
|
||||
desc *prometheus.Desc
|
||||
callback func() float64
|
||||
}
|
||||
|
||||
func (cm *CallbackMetric) Desc() *prometheus.Desc {
|
||||
return cm.desc
|
||||
}
|
||||
|
||||
func (cm *CallbackMetric) Write(m *dto.Metric) error {
|
||||
m.Untyped = &dto.Untyped{Value: proto.Float64(cm.callback())}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExampleSelfCollector() {
|
||||
m := NewCallbackMetric(
|
||||
prometheus.NewDesc(
|
||||
"runtime_goroutines_count",
|
||||
"Total number of goroutines that currently exist.",
|
||||
nil, nil, // No labels, these must be nil.
|
||||
),
|
||||
func() float64 {
|
||||
return float64(runtime.NumGoroutine())
|
||||
},
|
||||
)
|
||||
prometheus.MustRegister(m)
|
||||
}
|
||||
649
vendor/github.com/prometheus/client_golang/prometheus/examples_test.go
generated
vendored
Normal file
649
vendor/github.com/prometheus/client_golang/prometheus/examples_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,649 @@
|
|||
// 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 (
|
||||
"flag"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
func ExampleGauge() {
|
||||
opsQueued := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: "our_company",
|
||||
Subsystem: "blob_storage",
|
||||
Name: "ops_queued",
|
||||
Help: "Number of blob storage operations waiting to be processed.",
|
||||
})
|
||||
prometheus.MustRegister(opsQueued)
|
||||
|
||||
// 10 operations queued by the goroutine managing incoming requests.
|
||||
opsQueued.Add(10)
|
||||
// A worker goroutine has picked up a waiting operation.
|
||||
opsQueued.Dec()
|
||||
// And once more...
|
||||
opsQueued.Dec()
|
||||
}
|
||||
|
||||
func ExampleGaugeVec() {
|
||||
binaryVersion := flag.String("binary_version", "debug", "Version of the binary: debug, canary, production.")
|
||||
flag.Parse()
|
||||
|
||||
opsQueued := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: "our_company",
|
||||
Subsystem: "blob_storage",
|
||||
Name: "ops_queued",
|
||||
Help: "Number of blob storage operations waiting to be processed, partitioned by user and type.",
|
||||
ConstLabels: prometheus.Labels{"binary_version": *binaryVersion},
|
||||
},
|
||||
[]string{
|
||||
// Which user has requested the operation?
|
||||
"user",
|
||||
// Of what type is the operation?
|
||||
"type",
|
||||
},
|
||||
)
|
||||
prometheus.MustRegister(opsQueued)
|
||||
|
||||
// Increase a value using compact (but order-sensitive!) WithLabelValues().
|
||||
opsQueued.WithLabelValues("bob", "put").Add(4)
|
||||
// Increase a value with a map using WithLabels. More verbose, but order
|
||||
// doesn't matter anymore.
|
||||
opsQueued.With(prometheus.Labels{"type": "delete", "user": "alice"}).Inc()
|
||||
}
|
||||
|
||||
func ExampleGaugeFunc() {
|
||||
if err := prometheus.Register(prometheus.NewGaugeFunc(
|
||||
prometheus.GaugeOpts{
|
||||
Subsystem: "runtime",
|
||||
Name: "goroutines_count",
|
||||
Help: "Number of goroutines that currently exist.",
|
||||
},
|
||||
func() float64 { return float64(runtime.NumGoroutine()) },
|
||||
)); err == nil {
|
||||
fmt.Println("GaugeFunc 'goroutines_count' registered.")
|
||||
}
|
||||
// Note that the count of goroutines is a gauge (and not a counter) as
|
||||
// it can go up and down.
|
||||
|
||||
// Output:
|
||||
// GaugeFunc 'goroutines_count' registered.
|
||||
}
|
||||
|
||||
func ExampleCounter() {
|
||||
pushCounter := prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Name: "repository_pushes", // Note: No help string...
|
||||
})
|
||||
err := prometheus.Register(pushCounter) // ... so this will return an error.
|
||||
if err != nil {
|
||||
fmt.Println("Push counter couldn't be registered, no counting will happen:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Try it once more, this time with a help string.
|
||||
pushCounter = prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Name: "repository_pushes",
|
||||
Help: "Number of pushes to external repository.",
|
||||
})
|
||||
err = prometheus.Register(pushCounter)
|
||||
if err != nil {
|
||||
fmt.Println("Push counter couldn't be registered AGAIN, no counting will happen:", err)
|
||||
return
|
||||
}
|
||||
|
||||
pushComplete := make(chan struct{})
|
||||
// TODO: Start a goroutine that performs repository pushes and reports
|
||||
// each completion via the channel.
|
||||
for _ = range pushComplete {
|
||||
pushCounter.Inc()
|
||||
}
|
||||
// Output:
|
||||
// Push counter couldn't be registered, no counting will happen: descriptor Desc{fqName: "repository_pushes", help: "", constLabels: {}, variableLabels: []} is invalid: empty help string
|
||||
}
|
||||
|
||||
func ExampleCounterVec() {
|
||||
binaryVersion := flag.String("environment", "test", "Execution environment: test, staging, production.")
|
||||
flag.Parse()
|
||||
|
||||
httpReqs := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "http_requests_total",
|
||||
Help: "How many HTTP requests processed, partitioned by status code and HTTP method.",
|
||||
ConstLabels: prometheus.Labels{"env": *binaryVersion},
|
||||
},
|
||||
[]string{"code", "method"},
|
||||
)
|
||||
prometheus.MustRegister(httpReqs)
|
||||
|
||||
httpReqs.WithLabelValues("404", "POST").Add(42)
|
||||
|
||||
// If you have to access the same set of labels very frequently, it
|
||||
// might be good to retrieve the metric only once and keep a handle to
|
||||
// it. But beware of deletion of that metric, see below!
|
||||
m := httpReqs.WithLabelValues("200", "GET")
|
||||
for i := 0; i < 1000000; i++ {
|
||||
m.Inc()
|
||||
}
|
||||
// Delete a metric from the vector. If you have previously kept a handle
|
||||
// to that metric (as above), future updates via that handle will go
|
||||
// unseen (even if you re-create a metric with the same label set
|
||||
// later).
|
||||
httpReqs.DeleteLabelValues("200", "GET")
|
||||
// Same thing with the more verbose Labels syntax.
|
||||
httpReqs.Delete(prometheus.Labels{"method": "GET", "code": "200"})
|
||||
}
|
||||
|
||||
func ExampleInstrumentHandler() {
|
||||
// Handle the "/doc" endpoint with the standard http.FileServer handler.
|
||||
// By wrapping the handler with InstrumentHandler, request count,
|
||||
// request and response sizes, and request latency are automatically
|
||||
// exported to Prometheus, partitioned by HTTP status code and method
|
||||
// and by the handler name (here "fileserver").
|
||||
http.Handle("/doc", prometheus.InstrumentHandler(
|
||||
"fileserver", http.FileServer(http.Dir("/usr/share/doc")),
|
||||
))
|
||||
// The Prometheus handler still has to be registered to handle the
|
||||
// "/metrics" endpoint. The handler returned by prometheus.Handler() is
|
||||
// already instrumented - with "prometheus" as the handler name. In this
|
||||
// example, we want the handler name to be "metrics", so we instrument
|
||||
// the uninstrumented Prometheus handler ourselves.
|
||||
http.Handle("/metrics", prometheus.InstrumentHandler(
|
||||
"metrics", prometheus.UninstrumentedHandler(),
|
||||
))
|
||||
}
|
||||
|
||||
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")},
|
||||
}
|
||||
|
||||
sort.Sort(prometheus.LabelPairSorter(labelPairs))
|
||||
|
||||
fmt.Println(labelPairs)
|
||||
// Output:
|
||||
// [name:"method" value:"get" name:"status" value:"404" ]
|
||||
}
|
||||
|
||||
func ExampleRegister() {
|
||||
// Imagine you have a worker pool and want to count the tasks completed.
|
||||
taskCounter := prometheus.NewCounter(prometheus.CounterOpts{
|
||||
Subsystem: "worker_pool",
|
||||
Name: "completed_tasks_total",
|
||||
Help: "Total number of tasks completed.",
|
||||
})
|
||||
// This will register fine.
|
||||
if err := prometheus.Register(taskCounter); err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Println("taskCounter registered.")
|
||||
}
|
||||
// Don't forget to tell the HTTP server about the Prometheus handler.
|
||||
// (In a real program, you still need to start the HTTP server...)
|
||||
http.Handle("/metrics", prometheus.Handler())
|
||||
|
||||
// Now you can start workers and give every one of them a pointer to
|
||||
// taskCounter and let it increment it whenever it completes a task.
|
||||
taskCounter.Inc() // This has to happen somewhere in the worker code.
|
||||
|
||||
// But wait, you want to see how individual workers perform. So you need
|
||||
// a vector of counters, with one element for each worker.
|
||||
taskCounterVec := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Subsystem: "worker_pool",
|
||||
Name: "completed_tasks_total",
|
||||
Help: "Total number of tasks completed.",
|
||||
},
|
||||
[]string{"worker_id"},
|
||||
)
|
||||
|
||||
// Registering will fail because we already have a metric of that name.
|
||||
if err := prometheus.Register(taskCounterVec); err != nil {
|
||||
fmt.Println("taskCounterVec not registered:", err)
|
||||
} else {
|
||||
fmt.Println("taskCounterVec registered.")
|
||||
}
|
||||
|
||||
// To fix, first unregister the old taskCounter.
|
||||
if prometheus.Unregister(taskCounter) {
|
||||
fmt.Println("taskCounter unregistered.")
|
||||
}
|
||||
|
||||
// Try registering taskCounterVec again.
|
||||
if err := prometheus.Register(taskCounterVec); err != nil {
|
||||
fmt.Println("taskCounterVec not registered:", err)
|
||||
} else {
|
||||
fmt.Println("taskCounterVec registered.")
|
||||
}
|
||||
// Bummer! Still doesn't work.
|
||||
|
||||
// Prometheus will not allow you to ever export metrics with
|
||||
// inconsistent help strings or label names. After unregistering, the
|
||||
// unregistered metrics will cease to show up in the /metrics HTTP
|
||||
// response, but the registry still remembers that those metrics had
|
||||
// been exported before. For this example, we will now choose a
|
||||
// different name. (In a real program, you would obviously not export
|
||||
// the obsolete metric in the first place.)
|
||||
taskCounterVec = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Subsystem: "worker_pool",
|
||||
Name: "completed_tasks_by_id",
|
||||
Help: "Total number of tasks completed.",
|
||||
},
|
||||
[]string{"worker_id"},
|
||||
)
|
||||
if err := prometheus.Register(taskCounterVec); err != nil {
|
||||
fmt.Println("taskCounterVec not registered:", err)
|
||||
} else {
|
||||
fmt.Println("taskCounterVec registered.")
|
||||
}
|
||||
// Finally it worked!
|
||||
|
||||
// The workers have to tell taskCounterVec their id to increment the
|
||||
// right element in the metric vector.
|
||||
taskCounterVec.WithLabelValues("42").Inc() // Code from worker 42.
|
||||
|
||||
// Each worker could also keep a reference to their own counter element
|
||||
// around. Pick the counter at initialization time of the worker.
|
||||
myCounter := taskCounterVec.WithLabelValues("42") // From worker 42 initialization code.
|
||||
myCounter.Inc() // Somewhere in the code of that worker.
|
||||
|
||||
// Note that something like WithLabelValues("42", "spurious arg") would
|
||||
// panic (because you have provided too many label values). If you want
|
||||
// to get an error instead, use GetMetricWithLabelValues(...) instead.
|
||||
notMyCounter, err := taskCounterVec.GetMetricWithLabelValues("42", "spurious arg")
|
||||
if err != nil {
|
||||
fmt.Println("Worker initialization failed:", err)
|
||||
}
|
||||
if notMyCounter == nil {
|
||||
fmt.Println("notMyCounter is nil.")
|
||||
}
|
||||
|
||||
// A different (and somewhat tricky) approach is to use
|
||||
// ConstLabels. ConstLabels are pairs of label names and label values
|
||||
// that never change. You might ask what those labels are good for (and
|
||||
// rightfully so - if they never change, they could as well be part of
|
||||
// the metric name). There are essentially two use-cases: The first is
|
||||
// if labels are constant throughout the lifetime of a binary execution,
|
||||
// but they vary over time or between different instances of a running
|
||||
// binary. The second is what we have here: Each worker creates and
|
||||
// registers an own Counter instance where the only difference is in the
|
||||
// value of the ConstLabels. Those Counters can all be registered
|
||||
// because the different ConstLabel values guarantee that each worker
|
||||
// will increment a different Counter metric.
|
||||
counterOpts := prometheus.CounterOpts{
|
||||
Subsystem: "worker_pool",
|
||||
Name: "completed_tasks",
|
||||
Help: "Total number of tasks completed.",
|
||||
ConstLabels: prometheus.Labels{"worker_id": "42"},
|
||||
}
|
||||
taskCounterForWorker42 := prometheus.NewCounter(counterOpts)
|
||||
if err := prometheus.Register(taskCounterForWorker42); err != nil {
|
||||
fmt.Println("taskCounterVForWorker42 not registered:", err)
|
||||
} else {
|
||||
fmt.Println("taskCounterForWorker42 registered.")
|
||||
}
|
||||
// Obviously, in real code, taskCounterForWorker42 would be a member
|
||||
// variable of a worker struct, and the "42" would be retrieved with a
|
||||
// GetId() method or something. The Counter would be created and
|
||||
// registered in the initialization code of the worker.
|
||||
|
||||
// For the creation of the next Counter, we can recycle
|
||||
// counterOpts. Just change the ConstLabels.
|
||||
counterOpts.ConstLabels = prometheus.Labels{"worker_id": "2001"}
|
||||
taskCounterForWorker2001 := prometheus.NewCounter(counterOpts)
|
||||
if err := prometheus.Register(taskCounterForWorker2001); err != nil {
|
||||
fmt.Println("taskCounterVForWorker2001 not registered:", err)
|
||||
} else {
|
||||
fmt.Println("taskCounterForWorker2001 registered.")
|
||||
}
|
||||
|
||||
taskCounterForWorker2001.Inc()
|
||||
taskCounterForWorker42.Inc()
|
||||
taskCounterForWorker2001.Inc()
|
||||
|
||||
// Yet another approach would be to turn the workers themselves into
|
||||
// Collectors and register them. See the Collector example for details.
|
||||
|
||||
// Output:
|
||||
// taskCounter registered.
|
||||
// taskCounterVec not registered: a previously registered descriptor with the same fully-qualified name as Desc{fqName: "worker_pool_completed_tasks_total", help: "Total number of tasks completed.", constLabels: {}, variableLabels: [worker_id]} has different label names or a different help string
|
||||
// taskCounter unregistered.
|
||||
// taskCounterVec not registered: a previously registered descriptor with the same fully-qualified name as Desc{fqName: "worker_pool_completed_tasks_total", help: "Total number of tasks completed.", constLabels: {}, variableLabels: [worker_id]} has different label names or a different help string
|
||||
// taskCounterVec registered.
|
||||
// Worker initialization failed: inconsistent label cardinality
|
||||
// notMyCounter is nil.
|
||||
// taskCounterForWorker42 registered.
|
||||
// taskCounterForWorker2001 registered.
|
||||
}
|
||||
|
||||
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.
|
||||
})
|
||||
|
||||
// Simulate some observations.
|
||||
for i := 0; i < 1000; i++ {
|
||||
temps.Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10)
|
||||
}
|
||||
|
||||
// Just for demonstration, let's check the state of the summary by
|
||||
// (ab)using its Write method (which is usually only used by Prometheus
|
||||
// internally).
|
||||
metric := &dto.Metric{}
|
||||
temps.Write(metric)
|
||||
fmt.Println(proto.MarshalTextString(metric))
|
||||
|
||||
// Output:
|
||||
// summary: <
|
||||
// sample_count: 1000
|
||||
// sample_sum: 29969.50000000001
|
||||
// quantile: <
|
||||
// quantile: 0.5
|
||||
// value: 31.1
|
||||
// >
|
||||
// quantile: <
|
||||
// quantile: 0.9
|
||||
// value: 41.3
|
||||
// >
|
||||
// quantile: <
|
||||
// quantile: 0.99
|
||||
// value: 41.9
|
||||
// >
|
||||
// >
|
||||
}
|
||||
|
||||
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.
|
||||
},
|
||||
[]string{"species"},
|
||||
)
|
||||
|
||||
// Simulate some observations.
|
||||
for i := 0; i < 1000; i++ {
|
||||
temps.WithLabelValues("litoria-caerulea").Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10)
|
||||
temps.WithLabelValues("lithobates-catesbeianus").Observe(32 + math.Floor(100*math.Cos(float64(i)*0.11))/10)
|
||||
}
|
||||
|
||||
// Create a Summary without any observations.
|
||||
temps.WithLabelValues("leiopelma-hochstetteri")
|
||||
|
||||
// Just for demonstration, let's check the state of the summary vector
|
||||
// by (ab)using its Collect method and the Write method of its elements
|
||||
// (which is usually only used by Prometheus internally - code like the
|
||||
// following will never appear in your own code).
|
||||
metricChan := make(chan prometheus.Metric)
|
||||
go func() {
|
||||
defer close(metricChan)
|
||||
temps.Collect(metricChan)
|
||||
}()
|
||||
|
||||
metricStrings := []string{}
|
||||
for metric := range metricChan {
|
||||
dtoMetric := &dto.Metric{}
|
||||
metric.Write(dtoMetric)
|
||||
metricStrings = append(metricStrings, proto.MarshalTextString(dtoMetric))
|
||||
}
|
||||
sort.Strings(metricStrings) // For reproducible print order.
|
||||
fmt.Println(metricStrings)
|
||||
|
||||
// Output:
|
||||
// [label: <
|
||||
// name: "species"
|
||||
// value: "leiopelma-hochstetteri"
|
||||
// >
|
||||
// summary: <
|
||||
// sample_count: 0
|
||||
// sample_sum: 0
|
||||
// quantile: <
|
||||
// quantile: 0.5
|
||||
// value: nan
|
||||
// >
|
||||
// quantile: <
|
||||
// quantile: 0.9
|
||||
// value: nan
|
||||
// >
|
||||
// quantile: <
|
||||
// quantile: 0.99
|
||||
// value: nan
|
||||
// >
|
||||
// >
|
||||
// label: <
|
||||
// name: "species"
|
||||
// value: "lithobates-catesbeianus"
|
||||
// >
|
||||
// summary: <
|
||||
// sample_count: 1000
|
||||
// sample_sum: 31956.100000000017
|
||||
// quantile: <
|
||||
// quantile: 0.5
|
||||
// value: 32.4
|
||||
// >
|
||||
// quantile: <
|
||||
// quantile: 0.9
|
||||
// value: 41.4
|
||||
// >
|
||||
// quantile: <
|
||||
// quantile: 0.99
|
||||
// value: 41.9
|
||||
// >
|
||||
// >
|
||||
// label: <
|
||||
// name: "species"
|
||||
// value: "litoria-caerulea"
|
||||
// >
|
||||
// summary: <
|
||||
// sample_count: 1000
|
||||
// sample_sum: 29969.50000000001
|
||||
// quantile: <
|
||||
// quantile: 0.5
|
||||
// value: 31.1
|
||||
// >
|
||||
// quantile: <
|
||||
// quantile: 0.9
|
||||
// value: 41.3
|
||||
// >
|
||||
// quantile: <
|
||||
// quantile: 0.99
|
||||
// value: 41.9
|
||||
// >
|
||||
// >
|
||||
// ]
|
||||
}
|
||||
|
||||
func ExampleConstSummary() {
|
||||
desc := prometheus.NewDesc(
|
||||
"http_request_duration_seconds",
|
||||
"A summary of the HTTP request durations.",
|
||||
[]string{"code", "method"},
|
||||
prometheus.Labels{"owner": "example"},
|
||||
)
|
||||
|
||||
// Create a constant summary from values we got from a 3rd party telemetry system.
|
||||
s := prometheus.MustNewConstSummary(
|
||||
desc,
|
||||
4711, 403.34,
|
||||
map[float64]float64{0.5: 42.3, 0.9: 323.3},
|
||||
"200", "get",
|
||||
)
|
||||
|
||||
// Just for demonstration, let's check the state of the summary by
|
||||
// (ab)using its Write method (which is usually only used by Prometheus
|
||||
// internally).
|
||||
metric := &dto.Metric{}
|
||||
s.Write(metric)
|
||||
fmt.Println(proto.MarshalTextString(metric))
|
||||
|
||||
// Output:
|
||||
// label: <
|
||||
// name: "code"
|
||||
// value: "200"
|
||||
// >
|
||||
// label: <
|
||||
// name: "method"
|
||||
// value: "get"
|
||||
// >
|
||||
// label: <
|
||||
// name: "owner"
|
||||
// value: "example"
|
||||
// >
|
||||
// summary: <
|
||||
// sample_count: 4711
|
||||
// sample_sum: 403.34
|
||||
// quantile: <
|
||||
// quantile: 0.5
|
||||
// value: 42.3
|
||||
// >
|
||||
// quantile: <
|
||||
// quantile: 0.9
|
||||
// value: 323.3
|
||||
// >
|
||||
// >
|
||||
}
|
||||
|
||||
func ExampleHistogram() {
|
||||
temps := prometheus.NewHistogram(prometheus.HistogramOpts{
|
||||
Name: "pond_temperature_celsius",
|
||||
Help: "The temperature of the frog pond.", // Sorry, we can't measure how badly it smells.
|
||||
Buckets: prometheus.LinearBuckets(20, 5, 5), // 5 buckets, each 5 centigrade wide.
|
||||
})
|
||||
|
||||
// Simulate some observations.
|
||||
for i := 0; i < 1000; i++ {
|
||||
temps.Observe(30 + math.Floor(120*math.Sin(float64(i)*0.1))/10)
|
||||
}
|
||||
|
||||
// Just for demonstration, let's check the state of the histogram by
|
||||
// (ab)using its Write method (which is usually only used by Prometheus
|
||||
// internally).
|
||||
metric := &dto.Metric{}
|
||||
temps.Write(metric)
|
||||
fmt.Println(proto.MarshalTextString(metric))
|
||||
|
||||
// Output:
|
||||
// histogram: <
|
||||
// sample_count: 1000
|
||||
// sample_sum: 29969.50000000001
|
||||
// bucket: <
|
||||
// cumulative_count: 192
|
||||
// upper_bound: 20
|
||||
// >
|
||||
// bucket: <
|
||||
// cumulative_count: 366
|
||||
// upper_bound: 25
|
||||
// >
|
||||
// bucket: <
|
||||
// cumulative_count: 501
|
||||
// upper_bound: 30
|
||||
// >
|
||||
// bucket: <
|
||||
// cumulative_count: 638
|
||||
// upper_bound: 35
|
||||
// >
|
||||
// bucket: <
|
||||
// cumulative_count: 816
|
||||
// upper_bound: 40
|
||||
// >
|
||||
// >
|
||||
}
|
||||
|
||||
func ExampleConstHistogram() {
|
||||
desc := prometheus.NewDesc(
|
||||
"http_request_duration_seconds",
|
||||
"A histogram of the HTTP request durations.",
|
||||
[]string{"code", "method"},
|
||||
prometheus.Labels{"owner": "example"},
|
||||
)
|
||||
|
||||
// Create a constant histogram from values we got from a 3rd party telemetry system.
|
||||
h := prometheus.MustNewConstHistogram(
|
||||
desc,
|
||||
4711, 403.34,
|
||||
map[float64]uint64{25: 121, 50: 2403, 100: 3221, 200: 4233},
|
||||
"200", "get",
|
||||
)
|
||||
|
||||
// Just for demonstration, let's check the state of the histogram by
|
||||
// (ab)using its Write method (which is usually only used by Prometheus
|
||||
// internally).
|
||||
metric := &dto.Metric{}
|
||||
h.Write(metric)
|
||||
fmt.Println(proto.MarshalTextString(metric))
|
||||
|
||||
// Output:
|
||||
// label: <
|
||||
// name: "code"
|
||||
// value: "200"
|
||||
// >
|
||||
// label: <
|
||||
// name: "method"
|
||||
// value: "get"
|
||||
// >
|
||||
// label: <
|
||||
// name: "owner"
|
||||
// value: "example"
|
||||
// >
|
||||
// histogram: <
|
||||
// sample_count: 4711
|
||||
// sample_sum: 403.34
|
||||
// bucket: <
|
||||
// cumulative_count: 121
|
||||
// upper_bound: 25
|
||||
// >
|
||||
// bucket: <
|
||||
// cumulative_count: 2403
|
||||
// upper_bound: 50
|
||||
// >
|
||||
// bucket: <
|
||||
// cumulative_count: 3221
|
||||
// upper_bound: 100
|
||||
// >
|
||||
// bucket: <
|
||||
// cumulative_count: 4233
|
||||
// upper_bound: 200
|
||||
// >
|
||||
// >
|
||||
}
|
||||
|
||||
func ExamplePushCollectors() {
|
||||
hostname, _ := os.Hostname()
|
||||
completionTime := prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "db_backup_last_completion_time",
|
||||
Help: "The timestamp of the last succesful completion of a DB backup.",
|
||||
})
|
||||
completionTime.Set(float64(time.Now().Unix()))
|
||||
if err := prometheus.PushCollectors(
|
||||
"db_backup", hostname,
|
||||
"http://pushgateway:9091",
|
||||
completionTime,
|
||||
); err != nil {
|
||||
fmt.Println("Could not push completion time to Pushgateway:", err)
|
||||
}
|
||||
}
|
||||
119
vendor/github.com/prometheus/client_golang/prometheus/expvar.go
generated
vendored
Normal file
119
vendor/github.com/prometheus/client_golang/prometheus/expvar.go
generated
vendored
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"expvar"
|
||||
)
|
||||
|
||||
// ExpvarCollector collects metrics from the expvar interface. It provides a
|
||||
// quick way to expose numeric values that are already exported via expvar as
|
||||
// Prometheus metrics. Note that the data models of expvar and Prometheus are
|
||||
// fundamentally different, and that the ExpvarCollector is inherently
|
||||
// slow. Thus, the ExpvarCollector is probably great for experiments and
|
||||
// prototying, but you should seriously consider a more direct implementation of
|
||||
// Prometheus metrics for monitoring production systems.
|
||||
//
|
||||
// Use NewExpvarCollector to create new instances.
|
||||
type ExpvarCollector struct {
|
||||
exports map[string]*Desc
|
||||
}
|
||||
|
||||
// NewExpvarCollector returns a newly allocated ExpvarCollector that still has
|
||||
// to be registered with the Prometheus registry.
|
||||
//
|
||||
// The exports map has the following meaning:
|
||||
//
|
||||
// The keys in the map correspond to expvar keys, i.e. for every expvar key you
|
||||
// want to export as Prometheus metric, you need an entry in the exports
|
||||
// map. The descriptor mapped to each key describes how to export the expvar
|
||||
// value. It defines the name and the help string of the Prometheus metric
|
||||
// proxying the expvar value. The type will always be Untyped.
|
||||
//
|
||||
// For descriptors without variable labels, the expvar value must be a number or
|
||||
// a bool. The number is then directly exported as the Prometheus sample
|
||||
// value. (For a bool, 'false' translates to 0 and 'true' to 1). Expvar values
|
||||
// that are not numbers or bools are silently ignored.
|
||||
//
|
||||
// If the descriptor has one variable label, the expvar value must be an expvar
|
||||
// map. The keys in the expvar map become the various values of the one
|
||||
// Prometheus label. The values in the expvar map must be numbers or bools again
|
||||
// as above.
|
||||
//
|
||||
// For descriptors with more than one variable label, the expvar must be a
|
||||
// nested expvar map, i.e. where the values of the topmost map are maps again
|
||||
// etc. until a depth is reached that corresponds to the number of labels. The
|
||||
// leaves of that structure must be numbers or bools as above to serve as the
|
||||
// sample values.
|
||||
//
|
||||
// Anything that does not fit into the scheme above is silently ignored.
|
||||
func NewExpvarCollector(exports map[string]*Desc) *ExpvarCollector {
|
||||
return &ExpvarCollector{
|
||||
exports: exports,
|
||||
}
|
||||
}
|
||||
|
||||
// Describe implements Collector.
|
||||
func (e *ExpvarCollector) Describe(ch chan<- *Desc) {
|
||||
for _, desc := range e.exports {
|
||||
ch <- desc
|
||||
}
|
||||
}
|
||||
|
||||
// Collect implements Collector.
|
||||
func (e *ExpvarCollector) Collect(ch chan<- Metric) {
|
||||
for name, desc := range e.exports {
|
||||
var m Metric
|
||||
expVar := expvar.Get(name)
|
||||
if expVar == nil {
|
||||
continue
|
||||
}
|
||||
var v interface{}
|
||||
labels := make([]string, len(desc.variableLabels))
|
||||
if err := json.Unmarshal([]byte(expVar.String()), &v); err != nil {
|
||||
ch <- NewInvalidMetric(desc, err)
|
||||
continue
|
||||
}
|
||||
var processValue func(v interface{}, i int)
|
||||
processValue = func(v interface{}, i int) {
|
||||
if i >= len(labels) {
|
||||
copiedLabels := append(make([]string, 0, len(labels)), labels...)
|
||||
switch v := v.(type) {
|
||||
case float64:
|
||||
m = MustNewConstMetric(desc, UntypedValue, v, copiedLabels...)
|
||||
case bool:
|
||||
if v {
|
||||
m = MustNewConstMetric(desc, UntypedValue, 1, copiedLabels...)
|
||||
} else {
|
||||
m = MustNewConstMetric(desc, UntypedValue, 0, copiedLabels...)
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
ch <- m
|
||||
return
|
||||
}
|
||||
vm, ok := v.(map[string]interface{})
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
for lv, val := range vm {
|
||||
labels[i] = lv
|
||||
processValue(val, i+1)
|
||||
}
|
||||
}
|
||||
processValue(v, 0)
|
||||
}
|
||||
}
|
||||
97
vendor/github.com/prometheus/client_golang/prometheus/expvar_test.go
generated
vendored
Normal file
97
vendor/github.com/prometheus/client_golang/prometheus/expvar_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// 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 (
|
||||
"expvar"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
func ExampleExpvarCollector() {
|
||||
expvarCollector := prometheus.NewExpvarCollector(map[string]*prometheus.Desc{
|
||||
"memstats": prometheus.NewDesc(
|
||||
"expvar_memstats",
|
||||
"All numeric memstats as one metric family. Not a good role-model, actually... ;-)",
|
||||
[]string{"type"}, nil,
|
||||
),
|
||||
"lone-int": prometheus.NewDesc(
|
||||
"expvar_lone_int",
|
||||
"Just an expvar int as an example.",
|
||||
nil, nil,
|
||||
),
|
||||
"http-request-map": prometheus.NewDesc(
|
||||
"expvar_http_request_total",
|
||||
"How many http requests processed, partitioned by status code and http method.",
|
||||
[]string{"code", "method"}, nil,
|
||||
),
|
||||
})
|
||||
prometheus.MustRegister(expvarCollector)
|
||||
|
||||
// The Prometheus part is done here. But to show that this example is
|
||||
// doing anything, we have to manually export something via expvar. In
|
||||
// real-life use-cases, some library would already have exported via
|
||||
// expvar what we want to re-export as Prometheus metrics.
|
||||
expvar.NewInt("lone-int").Set(42)
|
||||
expvarMap := expvar.NewMap("http-request-map")
|
||||
var (
|
||||
expvarMap1, expvarMap2 expvar.Map
|
||||
expvarInt11, expvarInt12, expvarInt21, expvarInt22 expvar.Int
|
||||
)
|
||||
expvarMap1.Init()
|
||||
expvarMap2.Init()
|
||||
expvarInt11.Set(3)
|
||||
expvarInt12.Set(13)
|
||||
expvarInt21.Set(11)
|
||||
expvarInt22.Set(212)
|
||||
expvarMap1.Set("POST", &expvarInt11)
|
||||
expvarMap1.Set("GET", &expvarInt12)
|
||||
expvarMap2.Set("POST", &expvarInt21)
|
||||
expvarMap2.Set("GET", &expvarInt22)
|
||||
expvarMap.Set("404", &expvarMap1)
|
||||
expvarMap.Set("200", &expvarMap2)
|
||||
// Results in the following expvar map:
|
||||
// "http-request-count": {"200": {"POST": 11, "GET": 212}, "404": {"POST": 3, "GET": 13}}
|
||||
|
||||
// Let's see what the scrape would yield, but exclude the memstats metrics.
|
||||
metricStrings := []string{}
|
||||
metric := dto.Metric{}
|
||||
metricChan := make(chan prometheus.Metric)
|
||||
go func() {
|
||||
expvarCollector.Collect(metricChan)
|
||||
close(metricChan)
|
||||
}()
|
||||
for m := range metricChan {
|
||||
if strings.Index(m.Desc().String(), "expvar_memstats") == -1 {
|
||||
metric.Reset()
|
||||
m.Write(&metric)
|
||||
metricStrings = append(metricStrings, metric.String())
|
||||
}
|
||||
}
|
||||
sort.Strings(metricStrings)
|
||||
for _, s := range metricStrings {
|
||||
fmt.Println(strings.TrimRight(s, " "))
|
||||
}
|
||||
// Output:
|
||||
// label:<name:"code" value:"200" > label:<name:"method" value:"GET" > untyped:<value:212 >
|
||||
// label:<name:"code" value:"200" > label:<name:"method" value:"POST" > untyped:<value:11 >
|
||||
// label:<name:"code" value:"404" > label:<name:"method" value:"GET" > untyped:<value:13 >
|
||||
// label:<name:"code" value:"404" > label:<name:"method" value:"POST" > untyped:<value:3 >
|
||||
// untyped:<value:42 >
|
||||
}
|
||||
147
vendor/github.com/prometheus/client_golang/prometheus/gauge.go
generated
vendored
Normal file
147
vendor/github.com/prometheus/client_golang/prometheus/gauge.go
generated
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// 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
|
||||
|
||||
import "hash/fnv"
|
||||
|
||||
// Gauge is a Metric that represents a single numerical value that can
|
||||
// arbitrarily go up and down.
|
||||
//
|
||||
// A Gauge is typically used for measured values like temperatures or current
|
||||
// memory usage, but also "counts" that can go up and down, like the number of
|
||||
// running goroutines.
|
||||
//
|
||||
// To create Gauge instances, use NewGauge.
|
||||
type Gauge interface {
|
||||
Metric
|
||||
Collector
|
||||
|
||||
// Set sets the Gauge to an arbitrary value.
|
||||
Set(float64)
|
||||
// Inc increments the Gauge by 1.
|
||||
Inc()
|
||||
// Dec decrements the Gauge by 1.
|
||||
Dec()
|
||||
// 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)
|
||||
}
|
||||
|
||||
// GaugeOpts is an alias for Opts. See there for doc comments.
|
||||
type GaugeOpts Opts
|
||||
|
||||
// NewGauge creates a new Gauge based on the provided GaugeOpts.
|
||||
func NewGauge(opts GaugeOpts) Gauge {
|
||||
return newValue(NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
nil,
|
||||
opts.ConstLabels,
|
||||
), GaugeValue, 0)
|
||||
}
|
||||
|
||||
// GaugeVec is a Collector that bundles a set of Gauges that all share the same
|
||||
// Desc, but have different values for their variable labels. This is used if
|
||||
// you want to count the same thing partitioned by various dimensions
|
||||
// (e.g. number of operations queued, partitioned by user and operation
|
||||
// type). Create instances with NewGaugeVec.
|
||||
type GaugeVec struct {
|
||||
MetricVec
|
||||
}
|
||||
|
||||
// NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and
|
||||
// partitioned by the given label names. At least one label name must be
|
||||
// provided.
|
||||
func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
|
||||
desc := NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
labelNames,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
return &GaugeVec{
|
||||
MetricVec: MetricVec{
|
||||
children: map[uint64]Metric{},
|
||||
desc: desc,
|
||||
hash: fnv.New64a(),
|
||||
newMetric: func(lvs ...string) Metric {
|
||||
return newValue(desc, GaugeValue, 0, lvs...)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetMetricWithLabelValues replaces the method of the same name in
|
||||
// MetricVec. The difference is that this method returns a Gauge and not a
|
||||
// Metric so that no type conversion is required.
|
||||
func (m *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) {
|
||||
metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||
if metric != nil {
|
||||
return metric.(Gauge), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetMetricWith replaces the method of the same name in MetricVec. The
|
||||
// difference is that this method returns a Gauge and not a Metric so that no
|
||||
// type conversion is required.
|
||||
func (m *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) {
|
||||
metric, err := m.MetricVec.GetMetricWith(labels)
|
||||
if metric != nil {
|
||||
return metric.(Gauge), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
||||
// GetMetricWithLabelValues would have returned an error. By not returning an
|
||||
// error, WithLabelValues allows shortcuts like
|
||||
// myVec.WithLabelValues("404", "GET").Add(42)
|
||||
func (m *GaugeVec) WithLabelValues(lvs ...string) Gauge {
|
||||
return m.MetricVec.WithLabelValues(lvs...).(Gauge)
|
||||
}
|
||||
|
||||
// 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"}).Add(42)
|
||||
func (m *GaugeVec) With(labels Labels) Gauge {
|
||||
return m.MetricVec.With(labels).(Gauge)
|
||||
}
|
||||
|
||||
// GaugeFunc is a Gauge whose value is determined at collect time by calling a
|
||||
// provided function.
|
||||
//
|
||||
// To create GaugeFunc instances, use NewGaugeFunc.
|
||||
type GaugeFunc interface {
|
||||
Metric
|
||||
Collector
|
||||
}
|
||||
|
||||
// NewGaugeFunc creates a new GaugeFunc based on the provided GaugeOpts. The
|
||||
// value reported is determined by calling the given function from within the
|
||||
// Write method. Take into account that metric collection may happen
|
||||
// concurrently. If that results in concurrent calls to Write, like in the case
|
||||
// where a GaugeFunc is directly registered with Prometheus, the provided
|
||||
// function must be concurrency-safe.
|
||||
func NewGaugeFunc(opts GaugeOpts, function func() float64) GaugeFunc {
|
||||
return newValueFunc(NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
nil,
|
||||
opts.ConstLabels,
|
||||
), GaugeValue, function)
|
||||
}
|
||||
182
vendor/github.com/prometheus/client_golang/prometheus/gauge_test.go
generated
vendored
Normal file
182
vendor/github.com/prometheus/client_golang/prometheus/gauge_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
func listenGaugeStream(vals, result chan float64, done chan struct{}) {
|
||||
var sum float64
|
||||
outer:
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
close(vals)
|
||||
for v := range vals {
|
||||
sum += v
|
||||
}
|
||||
break outer
|
||||
case v := <-vals:
|
||||
sum += v
|
||||
}
|
||||
}
|
||||
result <- sum
|
||||
close(result)
|
||||
}
|
||||
|
||||
func TestGaugeConcurrency(t *testing.T) {
|
||||
it := func(n uint32) bool {
|
||||
mutations := int(n % 10000)
|
||||
concLevel := int(n%15 + 1)
|
||||
|
||||
var start, end sync.WaitGroup
|
||||
start.Add(1)
|
||||
end.Add(concLevel)
|
||||
|
||||
sStream := make(chan float64, mutations*concLevel)
|
||||
result := make(chan float64)
|
||||
done := make(chan struct{})
|
||||
|
||||
go listenGaugeStream(sStream, result, done)
|
||||
go func() {
|
||||
end.Wait()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
gge := NewGauge(GaugeOpts{
|
||||
Name: "test_gauge",
|
||||
Help: "no help can be found here",
|
||||
})
|
||||
for i := 0; i < concLevel; i++ {
|
||||
vals := make([]float64, mutations)
|
||||
for j := 0; j < mutations; j++ {
|
||||
vals[j] = rand.Float64() - 0.5
|
||||
}
|
||||
|
||||
go func(vals []float64) {
|
||||
start.Wait()
|
||||
for _, v := range vals {
|
||||
sStream <- v
|
||||
gge.Add(v)
|
||||
}
|
||||
end.Done()
|
||||
}(vals)
|
||||
}
|
||||
start.Done()
|
||||
|
||||
if expected, got := <-result, math.Float64frombits(gge.(*value).valBits); math.Abs(expected-got) > 0.000001 {
|
||||
t.Fatalf("expected approx. %f, got %f", expected, got)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if err := quick.Check(it, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGaugeVecConcurrency(t *testing.T) {
|
||||
it := func(n uint32) bool {
|
||||
mutations := int(n % 10000)
|
||||
concLevel := int(n%15 + 1)
|
||||
vecLength := int(n%5 + 1)
|
||||
|
||||
var start, end sync.WaitGroup
|
||||
start.Add(1)
|
||||
end.Add(concLevel)
|
||||
|
||||
sStreams := make([]chan float64, vecLength)
|
||||
results := make([]chan float64, vecLength)
|
||||
done := make(chan struct{})
|
||||
|
||||
for i := 0; i < vecLength; i++ {
|
||||
sStreams[i] = make(chan float64, mutations*concLevel)
|
||||
results[i] = make(chan float64)
|
||||
go listenGaugeStream(sStreams[i], results[i], done)
|
||||
}
|
||||
|
||||
go func() {
|
||||
end.Wait()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
gge := NewGaugeVec(
|
||||
GaugeOpts{
|
||||
Name: "test_gauge",
|
||||
Help: "no help can be found here",
|
||||
},
|
||||
[]string{"label"},
|
||||
)
|
||||
for i := 0; i < concLevel; i++ {
|
||||
vals := make([]float64, mutations)
|
||||
pick := make([]int, mutations)
|
||||
for j := 0; j < mutations; j++ {
|
||||
vals[j] = rand.Float64() - 0.5
|
||||
pick[j] = rand.Intn(vecLength)
|
||||
}
|
||||
|
||||
go func(vals []float64) {
|
||||
start.Wait()
|
||||
for i, v := range vals {
|
||||
sStreams[pick[i]] <- v
|
||||
gge.WithLabelValues(string('A' + pick[i])).Add(v)
|
||||
}
|
||||
end.Done()
|
||||
}(vals)
|
||||
}
|
||||
start.Done()
|
||||
|
||||
for i := range sStreams {
|
||||
if expected, got := <-results[i], math.Float64frombits(gge.WithLabelValues(string('A'+i)).(*value).valBits); math.Abs(expected-got) > 0.000001 {
|
||||
t.Fatalf("expected approx. %f, got %f", expected, got)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if err := quick.Check(it, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGaugeFunc(t *testing.T) {
|
||||
gf := NewGaugeFunc(
|
||||
GaugeOpts{
|
||||
Name: "test_name",
|
||||
Help: "test help",
|
||||
ConstLabels: Labels{"a": "1", "b": "2"},
|
||||
},
|
||||
func() float64 { return 3.1415 },
|
||||
)
|
||||
|
||||
if expected, got := `Desc{fqName: "test_name", help: "test help", constLabels: {a="1",b="2"}, variableLabels: []}`, gf.Desc().String(); expected != got {
|
||||
t.Errorf("expected %q, got %q", expected, got)
|
||||
}
|
||||
|
||||
m := &dto.Metric{}
|
||||
gf.Write(m)
|
||||
|
||||
if expected, got := `label:<name:"a" value:"1" > label:<name:"b" value:"2" > gauge:<value:3.1415 > `, m.String(); expected != got {
|
||||
t.Errorf("expected %q, got %q", expected, got)
|
||||
}
|
||||
}
|
||||
263
vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
generated
vendored
Normal file
263
vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
generated
vendored
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
package prometheus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
)
|
||||
|
||||
type goCollector struct {
|
||||
goroutines Gauge
|
||||
gcDesc *Desc
|
||||
|
||||
// metrics to describe and collect
|
||||
metrics memStatsMetrics
|
||||
}
|
||||
|
||||
// NewGoCollector returns a collector which exports metrics about the current
|
||||
// go process.
|
||||
func NewGoCollector() *goCollector {
|
||||
return &goCollector{
|
||||
goroutines: NewGauge(GaugeOpts{
|
||||
Namespace: "go",
|
||||
Name: "goroutines",
|
||||
Help: "Number of goroutines that currently exist.",
|
||||
}),
|
||||
gcDesc: NewDesc(
|
||||
"go_gc_duration_seconds",
|
||||
"A summary of the GC invocation durations.",
|
||||
nil, nil),
|
||||
metrics: memStatsMetrics{
|
||||
{
|
||||
desc: NewDesc(
|
||||
memstatNamespace("alloc_bytes"),
|
||||
"Number of bytes allocated and still in use.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("alloc_bytes_total"),
|
||||
"Total number of bytes allocated, even if freed.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("sys_bytes"),
|
||||
"Number of bytes obtained by system. Sum of all system allocations.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("lookups_total"),
|
||||
"Total number of pointer lookups.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mallocs_total"),
|
||||
"Total number of mallocs.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("frees_total"),
|
||||
"Total number of frees.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_alloc_bytes"),
|
||||
"Number of heap bytes allocated and still in use.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_sys_bytes"),
|
||||
"Number of heap bytes obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_idle_bytes"),
|
||||
"Number of heap bytes waiting to be used.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_inuse_bytes"),
|
||||
"Number of heap bytes that are in use.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_released_bytes_total"),
|
||||
"Total number of heap bytes released to OS.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
|
||||
valType: CounterValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("heap_objects"),
|
||||
"Number of allocated objects.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("stack_inuse_bytes"),
|
||||
"Number of bytes in use by the stack allocator.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("stack_sys_bytes"),
|
||||
"Number of bytes obtained from system for stack allocator.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mspan_inuse_bytes"),
|
||||
"Number of bytes in use by mspan structures.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mspan_sys_bytes"),
|
||||
"Number of bytes used for mspan structures obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mcache_inuse_bytes"),
|
||||
"Number of bytes in use by mcache structures.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("mcache_sys_bytes"),
|
||||
"Number of bytes used for mcache structures obtained from system.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("buck_hash_sys_bytes"),
|
||||
"Number of bytes used by the profiling bucket hash table.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("gc_sys_bytes"),
|
||||
"Number of bytes used for garbage collection system metadata.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("other_sys_bytes"),
|
||||
"Number of bytes used for other system allocations.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("next_gc_bytes"),
|
||||
"Number of heap bytes when next garbage collection will take place.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
|
||||
valType: GaugeValue,
|
||||
}, {
|
||||
desc: NewDesc(
|
||||
memstatNamespace("last_gc_time_seconds"),
|
||||
"Number of seconds since 1970 of last garbage collection.",
|
||||
nil, nil,
|
||||
),
|
||||
eval: func(ms *runtime.MemStats) float64 { return float64(ms.LastGC*10 ^ 9) },
|
||||
valType: GaugeValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func memstatNamespace(s string) string {
|
||||
return fmt.Sprintf("go_memstats_%s", s)
|
||||
}
|
||||
|
||||
// Describe returns all descriptions of the collector.
|
||||
func (c *goCollector) Describe(ch chan<- *Desc) {
|
||||
ch <- c.goroutines.Desc()
|
||||
ch <- c.gcDesc
|
||||
|
||||
for _, i := range c.metrics {
|
||||
ch <- i.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
|
||||
|
||||
var stats debug.GCStats
|
||||
stats.PauseQuantiles = make([]time.Duration, 5)
|
||||
debug.ReadGCStats(&stats)
|
||||
|
||||
quantiles := make(map[float64]float64)
|
||||
for idx, pq := range stats.PauseQuantiles[1:] {
|
||||
quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds()
|
||||
}
|
||||
quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
|
||||
ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), quantiles)
|
||||
|
||||
ms := &runtime.MemStats{}
|
||||
runtime.ReadMemStats(ms)
|
||||
for _, i := range c.metrics {
|
||||
ch <- MustNewConstMetric(i.desc, i.valType, i.eval(ms))
|
||||
}
|
||||
}
|
||||
|
||||
// memStatsMetrics provide description, value, and value type for memstat metrics.
|
||||
type memStatsMetrics []struct {
|
||||
desc *Desc
|
||||
eval func(*runtime.MemStats) float64
|
||||
valType ValueType
|
||||
}
|
||||
123
vendor/github.com/prometheus/client_golang/prometheus/go_collector_test.go
generated
vendored
Normal file
123
vendor/github.com/prometheus/client_golang/prometheus/go_collector_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
package prometheus
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
func TestGoCollector(t *testing.T) {
|
||||
var (
|
||||
c = NewGoCollector()
|
||||
ch = make(chan Metric)
|
||||
waitc = make(chan struct{})
|
||||
closec = make(chan struct{})
|
||||
old = -1
|
||||
)
|
||||
defer close(closec)
|
||||
|
||||
go func() {
|
||||
c.Collect(ch)
|
||||
go func(c <-chan struct{}) {
|
||||
<-c
|
||||
}(closec)
|
||||
<-waitc
|
||||
c.Collect(ch)
|
||||
}()
|
||||
|
||||
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 <-time.After(1 * time.Second):
|
||||
t.Fatalf("expected collect timed out")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGCCollector(t *testing.T) {
|
||||
var (
|
||||
c = NewGoCollector()
|
||||
ch = make(chan Metric)
|
||||
waitc = make(chan struct{})
|
||||
closec = make(chan struct{})
|
||||
oldGC uint64
|
||||
oldPause float64
|
||||
)
|
||||
defer close(closec)
|
||||
|
||||
go func() {
|
||||
c.Collect(ch)
|
||||
// force GC
|
||||
runtime.GC()
|
||||
<-waitc
|
||||
c.Collect(ch)
|
||||
}()
|
||||
|
||||
first := true
|
||||
for {
|
||||
select {
|
||||
case metric := <-ch:
|
||||
switch m := metric.(type) {
|
||||
case *constSummary, *value:
|
||||
pb := &dto.Metric{}
|
||||
m.Write(pb)
|
||||
if pb.GetSummary() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(pb.GetSummary().Quantile) != 5 {
|
||||
t.Errorf("expected 4 buckets, got %d", len(pb.GetSummary().Quantile))
|
||||
}
|
||||
for idx, want := range []float64{0.0, 0.25, 0.5, 0.75, 1.0} {
|
||||
if *pb.GetSummary().Quantile[idx].Quantile != want {
|
||||
t.Errorf("bucket #%d is off, got %f, want %f", idx, *pb.GetSummary().Quantile[idx].Quantile, want)
|
||||
}
|
||||
}
|
||||
if first {
|
||||
first = false
|
||||
oldGC = *pb.GetSummary().SampleCount
|
||||
oldPause = *pb.GetSummary().SampleSum
|
||||
close(waitc)
|
||||
continue
|
||||
}
|
||||
if diff := *pb.GetSummary().SampleCount - oldGC; diff != 1 {
|
||||
t.Errorf("want 1 new garbage collection run, got %d", diff)
|
||||
}
|
||||
if diff := *pb.GetSummary().SampleSum - oldPause; diff <= 0 {
|
||||
t.Errorf("want moar pause, got %f", diff)
|
||||
}
|
||||
return
|
||||
}
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("expected collect timed out")
|
||||
}
|
||||
}
|
||||
}
|
||||
450
vendor/github.com/prometheus/client_golang/prometheus/histogram.go
generated
vendored
Normal file
450
vendor/github.com/prometheus/client_golang/prometheus/histogram.go
generated
vendored
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
// 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.
|
||||
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"math"
|
||||
"sort"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
// A Histogram counts individual observations from an event or sample stream in
|
||||
// configurable buckets. Similar to a summary, it also provides a sum of
|
||||
// observations and an observation count.
|
||||
//
|
||||
// On the Prometheus server, quantiles can be calculated from a Histogram using
|
||||
// the histogram_quantile function in the query language.
|
||||
//
|
||||
// Note that Histograms, in contrast to Summaries, can be aggregated with the
|
||||
// Prometheus query language (see the documentation for detailed
|
||||
// procedures). However, Histograms require the user to pre-define suitable
|
||||
// buckets, and they are in general less accurate. The Observe method of a
|
||||
// Histogram has a very low performance overhead in comparison with the Observe
|
||||
// method of a Summary.
|
||||
//
|
||||
// To create Histogram instances, use NewHistogram.
|
||||
type Histogram interface {
|
||||
Metric
|
||||
Collector
|
||||
|
||||
// Observe adds a single observation to the histogram.
|
||||
Observe(float64)
|
||||
}
|
||||
|
||||
// bucketLabel is used for the label that defines the upper bound of a
|
||||
// bucket of a histogram ("le" -> "less or equal").
|
||||
const bucketLabel = "le"
|
||||
|
||||
var (
|
||||
// DefBuckets are the default Histogram buckets. The default buckets are
|
||||
// tailored to broadly measure the response time (in seconds) of a
|
||||
// network service. Most likely, however, you will be required to define
|
||||
// buckets customized to your use case.
|
||||
DefBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}
|
||||
|
||||
errBucketLabelNotAllowed = fmt.Errorf(
|
||||
"%q is not allowed as label name in histograms", bucketLabel,
|
||||
)
|
||||
)
|
||||
|
||||
// LinearBuckets creates 'count' buckets, each 'width' wide, where the lowest
|
||||
// bucket has an upper bound of 'start'. The final +Inf bucket is not counted
|
||||
// and not included in the returned slice. The returned slice is meant to be
|
||||
// used for the Buckets field of HistogramOpts.
|
||||
//
|
||||
// The function panics if 'count' is zero or negative.
|
||||
func LinearBuckets(start, width float64, count int) []float64 {
|
||||
if count < 1 {
|
||||
panic("LinearBuckets needs a positive count")
|
||||
}
|
||||
buckets := make([]float64, count)
|
||||
for i := range buckets {
|
||||
buckets[i] = start
|
||||
start += width
|
||||
}
|
||||
return buckets
|
||||
}
|
||||
|
||||
// ExponentialBuckets creates 'count' buckets, where the lowest bucket has an
|
||||
// upper bound of 'start' and each following bucket's upper bound is 'factor'
|
||||
// times the previous bucket's upper bound. The final +Inf bucket is not counted
|
||||
// and not included in the returned slice. The returned slice is meant to be
|
||||
// used for the Buckets field of HistogramOpts.
|
||||
//
|
||||
// The function panics if 'count' is 0 or negative, if 'start' is 0 or negative,
|
||||
// or if 'factor' is less than or equal 1.
|
||||
func ExponentialBuckets(start, factor float64, count int) []float64 {
|
||||
if count < 1 {
|
||||
panic("ExponentialBuckets needs a positive count")
|
||||
}
|
||||
if start <= 0 {
|
||||
panic("ExponentialBuckets needs a positive start value")
|
||||
}
|
||||
if factor <= 1 {
|
||||
panic("ExponentialBuckets needs a factor greater than 1")
|
||||
}
|
||||
buckets := make([]float64, count)
|
||||
for i := range buckets {
|
||||
buckets[i] = start
|
||||
start *= factor
|
||||
}
|
||||
return buckets
|
||||
}
|
||||
|
||||
// HistogramOpts bundles the options for creating a Histogram metric. It is
|
||||
// mandatory to set Name and Help to a non-empty string. All other fields are
|
||||
// optional and can safely be left at their zero value.
|
||||
type HistogramOpts struct {
|
||||
// Namespace, Subsystem, and Name are components of the fully-qualified
|
||||
// name of the Histogram (created by joining these components with
|
||||
// "_"). Only Name is mandatory, the others merely help structuring the
|
||||
// name. Note that the fully-qualified name of the Histogram must be a
|
||||
// valid Prometheus metric name.
|
||||
Namespace string
|
||||
Subsystem string
|
||||
Name string
|
||||
|
||||
// Help provides information about this Histogram. Mandatory!
|
||||
//
|
||||
// Metrics with the same fully-qualified name must have the same Help
|
||||
// string.
|
||||
Help string
|
||||
|
||||
// ConstLabels are used to attach fixed labels to this
|
||||
// Histogram. Histograms with the same fully-qualified name must have the
|
||||
// same label names in their ConstLabels.
|
||||
//
|
||||
// Note that in most cases, labels have a value that varies during the
|
||||
// lifetime of a process. Those labels are usually managed with a
|
||||
// HistogramVec. ConstLabels serve only special purposes. One is for the
|
||||
// special case where the value of a label does not change during the
|
||||
// lifetime of a process, e.g. if the revision of the running binary is
|
||||
// put into a label. Another, more advanced purpose is if more than one
|
||||
// Collector needs to collect Histograms with the same fully-qualified
|
||||
// name. In that case, those Summaries must differ in the values of
|
||||
// their ConstLabels. See the Collector examples.
|
||||
//
|
||||
// If the value of a label never changes (not even between binaries),
|
||||
// that label most likely should not be a label at all (but part of the
|
||||
// metric name).
|
||||
ConstLabels Labels
|
||||
|
||||
// Buckets defines the buckets into which observations are counted. Each
|
||||
// element in the slice is the upper inclusive bound of a bucket. The
|
||||
// values must be sorted in strictly increasing order. There is no need
|
||||
// to add a highest bucket with +Inf bound, it will be added
|
||||
// implicitly. The default value is DefBuckets.
|
||||
Buckets []float64
|
||||
}
|
||||
|
||||
// NewHistogram creates a new Histogram based on the provided HistogramOpts. It
|
||||
// panics if the buckets in HistogramOpts are not in strictly increasing order.
|
||||
func NewHistogram(opts HistogramOpts) Histogram {
|
||||
return newHistogram(
|
||||
NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
nil,
|
||||
opts.ConstLabels,
|
||||
),
|
||||
opts,
|
||||
)
|
||||
}
|
||||
|
||||
func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogram {
|
||||
if len(desc.variableLabels) != len(labelValues) {
|
||||
panic(errInconsistentCardinality)
|
||||
}
|
||||
|
||||
for _, n := range desc.variableLabels {
|
||||
if n == bucketLabel {
|
||||
panic(errBucketLabelNotAllowed)
|
||||
}
|
||||
}
|
||||
for _, lp := range desc.constLabelPairs {
|
||||
if lp.GetName() == bucketLabel {
|
||||
panic(errBucketLabelNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts.Buckets) == 0 {
|
||||
opts.Buckets = DefBuckets
|
||||
}
|
||||
|
||||
h := &histogram{
|
||||
desc: desc,
|
||||
upperBounds: opts.Buckets,
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
}
|
||||
for i, upperBound := range h.upperBounds {
|
||||
if i < len(h.upperBounds)-1 {
|
||||
if upperBound >= h.upperBounds[i+1] {
|
||||
panic(fmt.Errorf(
|
||||
"histogram buckets must be in increasing order: %f >= %f",
|
||||
upperBound, h.upperBounds[i+1],
|
||||
))
|
||||
}
|
||||
} else {
|
||||
if math.IsInf(upperBound, +1) {
|
||||
// The +Inf bucket is implicit. Remove it here.
|
||||
h.upperBounds = h.upperBounds[:i]
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally we know the final length of h.upperBounds and can make counts.
|
||||
h.counts = make([]uint64, len(h.upperBounds))
|
||||
|
||||
h.Init(h) // Init self-collection.
|
||||
return h
|
||||
}
|
||||
|
||||
type histogram struct {
|
||||
// sumBits contains the bits of the float64 representing the sum of all
|
||||
// observations. sumBits and count have to go first in the struct to
|
||||
// guarantee alignment for atomic operations.
|
||||
// http://golang.org/pkg/sync/atomic/#pkg-note-BUG
|
||||
sumBits uint64
|
||||
count uint64
|
||||
|
||||
SelfCollector
|
||||
// Note that there is no mutex required.
|
||||
|
||||
desc *Desc
|
||||
|
||||
upperBounds []float64
|
||||
counts []uint64
|
||||
|
||||
labelPairs []*dto.LabelPair
|
||||
}
|
||||
|
||||
func (h *histogram) Desc() *Desc {
|
||||
return h.desc
|
||||
}
|
||||
|
||||
func (h *histogram) Observe(v float64) {
|
||||
// TODO(beorn7): For small numbers of buckets (<30), a linear search is
|
||||
// slightly faster than the binary search. If we really care, we could
|
||||
// switch from one search strategy to the other depending on the number
|
||||
// of buckets.
|
||||
//
|
||||
// Microbenchmarks (BenchmarkHistogramNoLabels):
|
||||
// 11 buckets: 38.3 ns/op linear - binary 48.7 ns/op
|
||||
// 100 buckets: 78.1 ns/op linear - binary 54.9 ns/op
|
||||
// 300 buckets: 154 ns/op linear - binary 61.6 ns/op
|
||||
i := sort.SearchFloat64s(h.upperBounds, v)
|
||||
if i < len(h.counts) {
|
||||
atomic.AddUint64(&h.counts[i], 1)
|
||||
}
|
||||
atomic.AddUint64(&h.count, 1)
|
||||
for {
|
||||
oldBits := atomic.LoadUint64(&h.sumBits)
|
||||
newBits := math.Float64bits(math.Float64frombits(oldBits) + v)
|
||||
if atomic.CompareAndSwapUint64(&h.sumBits, oldBits, newBits) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *histogram) Write(out *dto.Metric) error {
|
||||
his := &dto.Histogram{}
|
||||
buckets := make([]*dto.Bucket, len(h.upperBounds))
|
||||
|
||||
his.SampleSum = proto.Float64(math.Float64frombits(atomic.LoadUint64(&h.sumBits)))
|
||||
his.SampleCount = proto.Uint64(atomic.LoadUint64(&h.count))
|
||||
var count uint64
|
||||
for i, upperBound := range h.upperBounds {
|
||||
count += atomic.LoadUint64(&h.counts[i])
|
||||
buckets[i] = &dto.Bucket{
|
||||
CumulativeCount: proto.Uint64(count),
|
||||
UpperBound: proto.Float64(upperBound),
|
||||
}
|
||||
}
|
||||
his.Bucket = buckets
|
||||
out.Histogram = his
|
||||
out.Label = h.labelPairs
|
||||
return nil
|
||||
}
|
||||
|
||||
// HistogramVec is a Collector that bundles a set of Histograms that all share the
|
||||
// same Desc, but have different values for their variable labels. This is used
|
||||
// if you want to count the same thing partitioned by various dimensions
|
||||
// (e.g. HTTP request latencies, partitioned by status code and method). Create
|
||||
// instances with NewHistogramVec.
|
||||
type HistogramVec struct {
|
||||
MetricVec
|
||||
}
|
||||
|
||||
// NewHistogramVec creates a new HistogramVec based on the provided HistogramOpts and
|
||||
// partitioned by the given label names. At least one label name must be
|
||||
// provided.
|
||||
func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec {
|
||||
desc := NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
labelNames,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
return &HistogramVec{
|
||||
MetricVec: MetricVec{
|
||||
children: map[uint64]Metric{},
|
||||
desc: desc,
|
||||
hash: fnv.New64a(),
|
||||
newMetric: func(lvs ...string) Metric {
|
||||
return newHistogram(desc, opts, lvs...)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||
if metric != nil {
|
||||
return metric.(Histogram), 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) {
|
||||
metric, err := m.MetricVec.GetMetricWith(labels)
|
||||
if metric != nil {
|
||||
return metric.(Histogram), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
type constHistogram struct {
|
||||
desc *Desc
|
||||
count uint64
|
||||
sum float64
|
||||
buckets map[float64]uint64
|
||||
labelPairs []*dto.LabelPair
|
||||
}
|
||||
|
||||
func (h *constHistogram) Desc() *Desc {
|
||||
return h.desc
|
||||
}
|
||||
|
||||
func (h *constHistogram) Write(out *dto.Metric) error {
|
||||
his := &dto.Histogram{}
|
||||
buckets := make([]*dto.Bucket, 0, len(h.buckets))
|
||||
|
||||
his.SampleCount = proto.Uint64(h.count)
|
||||
his.SampleSum = proto.Float64(h.sum)
|
||||
|
||||
for upperBound, count := range h.buckets {
|
||||
buckets = append(buckets, &dto.Bucket{
|
||||
CumulativeCount: proto.Uint64(count),
|
||||
UpperBound: proto.Float64(upperBound),
|
||||
})
|
||||
}
|
||||
|
||||
if len(buckets) > 0 {
|
||||
sort.Sort(buckSort(buckets))
|
||||
}
|
||||
his.Bucket = buckets
|
||||
|
||||
out.Histogram = his
|
||||
out.Label = h.labelPairs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewConstHistogram returns a metric representing a Prometheus histogram with
|
||||
// fixed values for the count, sum, and bucket counts. As those parameters
|
||||
// cannot be changed, the returned value does not implement the Histogram
|
||||
// interface (but only the Metric interface). Users of this package will not
|
||||
// have much use for it in regular operations. However, when implementing custom
|
||||
// Collectors, it is useful as a throw-away metric that is generated on the fly
|
||||
// to send it to Prometheus in the Collect method.
|
||||
//
|
||||
// buckets is a map of upper bounds to cumulative counts, excluding the +Inf
|
||||
// bucket.
|
||||
//
|
||||
// NewConstHistogram returns an error if the length of labelValues is not
|
||||
// consistent with the variable labels in Desc.
|
||||
func NewConstHistogram(
|
||||
desc *Desc,
|
||||
count uint64,
|
||||
sum float64,
|
||||
buckets map[float64]uint64,
|
||||
labelValues ...string,
|
||||
) (Metric, error) {
|
||||
if len(desc.variableLabels) != len(labelValues) {
|
||||
return nil, errInconsistentCardinality
|
||||
}
|
||||
return &constHistogram{
|
||||
desc: desc,
|
||||
count: count,
|
||||
sum: sum,
|
||||
buckets: buckets,
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MustNewConstHistogram is a version of NewConstHistogram that panics where
|
||||
// NewConstMetric would have returned an error.
|
||||
func MustNewConstHistogram(
|
||||
desc *Desc,
|
||||
count uint64,
|
||||
sum float64,
|
||||
buckets map[float64]uint64,
|
||||
labelValues ...string,
|
||||
) Metric {
|
||||
m, err := NewConstHistogram(desc, count, sum, buckets, labelValues...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type buckSort []*dto.Bucket
|
||||
|
||||
func (s buckSort) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s buckSort) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s buckSort) Less(i, j int) bool {
|
||||
return s[i].GetUpperBound() < s[j].GetUpperBound()
|
||||
}
|
||||
326
vendor/github.com/prometheus/client_golang/prometheus/histogram_test.go
generated
vendored
Normal file
326
vendor/github.com/prometheus/client_golang/prometheus/histogram_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
// 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.
|
||||
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
func benchmarkHistogramObserve(w int, b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(w)
|
||||
|
||||
g := new(sync.WaitGroup)
|
||||
g.Add(1)
|
||||
|
||||
s := NewHistogram(HistogramOpts{})
|
||||
|
||||
for i := 0; i < w; i++ {
|
||||
go func() {
|
||||
g.Wait()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Observe(float64(i))
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
g.Done()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkHistogramObserve1(b *testing.B) {
|
||||
benchmarkHistogramObserve(1, b)
|
||||
}
|
||||
|
||||
func BenchmarkHistogramObserve2(b *testing.B) {
|
||||
benchmarkHistogramObserve(2, b)
|
||||
}
|
||||
|
||||
func BenchmarkHistogramObserve4(b *testing.B) {
|
||||
benchmarkHistogramObserve(4, b)
|
||||
}
|
||||
|
||||
func BenchmarkHistogramObserve8(b *testing.B) {
|
||||
benchmarkHistogramObserve(8, b)
|
||||
}
|
||||
|
||||
func benchmarkHistogramWrite(w int, b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(w)
|
||||
|
||||
g := new(sync.WaitGroup)
|
||||
g.Add(1)
|
||||
|
||||
s := NewHistogram(HistogramOpts{})
|
||||
|
||||
for i := 0; i < 1000000; i++ {
|
||||
s.Observe(float64(i))
|
||||
}
|
||||
|
||||
for j := 0; j < w; j++ {
|
||||
outs := make([]dto.Metric, b.N)
|
||||
|
||||
go func(o []dto.Metric) {
|
||||
g.Wait()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Write(&o[i])
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
}(outs)
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
g.Done()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkHistogramWrite1(b *testing.B) {
|
||||
benchmarkHistogramWrite(1, b)
|
||||
}
|
||||
|
||||
func BenchmarkHistogramWrite2(b *testing.B) {
|
||||
benchmarkHistogramWrite(2, b)
|
||||
}
|
||||
|
||||
func BenchmarkHistogramWrite4(b *testing.B) {
|
||||
benchmarkHistogramWrite(4, b)
|
||||
}
|
||||
|
||||
func BenchmarkHistogramWrite8(b *testing.B) {
|
||||
benchmarkHistogramWrite(8, b)
|
||||
}
|
||||
|
||||
// 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)}
|
||||
|
||||
func TestHistogramConcurrency(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping test in short mode.")
|
||||
}
|
||||
|
||||
rand.Seed(42)
|
||||
|
||||
it := func(n uint32) bool {
|
||||
mutations := int(n%1e4 + 1e4)
|
||||
concLevel := int(n%5 + 1)
|
||||
total := mutations * concLevel
|
||||
|
||||
var start, end sync.WaitGroup
|
||||
start.Add(1)
|
||||
end.Add(concLevel)
|
||||
|
||||
sum := NewHistogram(HistogramOpts{
|
||||
Name: "test_histogram",
|
||||
Help: "helpless",
|
||||
Buckets: testBuckets,
|
||||
})
|
||||
|
||||
allVars := make([]float64, total)
|
||||
var sampleSum float64
|
||||
for i := 0; i < concLevel; i++ {
|
||||
vals := make([]float64, mutations)
|
||||
for j := 0; j < mutations; j++ {
|
||||
v := rand.NormFloat64()
|
||||
vals[j] = v
|
||||
allVars[i*mutations+j] = v
|
||||
sampleSum += v
|
||||
}
|
||||
|
||||
go func(vals []float64) {
|
||||
start.Wait()
|
||||
for _, v := range vals {
|
||||
sum.Observe(v)
|
||||
}
|
||||
end.Done()
|
||||
}(vals)
|
||||
}
|
||||
sort.Float64s(allVars)
|
||||
start.Done()
|
||||
end.Wait()
|
||||
|
||||
m := &dto.Metric{}
|
||||
sum.Write(m)
|
||||
if got, want := int(*m.Histogram.SampleCount), total; got != want {
|
||||
t.Errorf("got sample count %d, want %d", got, want)
|
||||
}
|
||||
if got, want := *m.Histogram.SampleSum, sampleSum; math.Abs((got-want)/want) > 0.001 {
|
||||
t.Errorf("got sample sum %f, want %f", got, want)
|
||||
}
|
||||
|
||||
wantCounts := getCumulativeCounts(allVars)
|
||||
|
||||
if got, want := len(m.Histogram.Bucket), len(testBuckets)-1; got != want {
|
||||
t.Errorf("got %d buckets in protobuf, want %d", got, want)
|
||||
}
|
||||
for i, wantBound := range testBuckets {
|
||||
if i == len(testBuckets)-1 {
|
||||
break // No +Inf bucket in protobuf.
|
||||
}
|
||||
if gotBound := *m.Histogram.Bucket[i].UpperBound; gotBound != wantBound {
|
||||
t.Errorf("got bound %f, want %f", gotBound, wantBound)
|
||||
}
|
||||
if gotCount, wantCount := *m.Histogram.Bucket[i].CumulativeCount, wantCounts[i]; gotCount != wantCount {
|
||||
t.Errorf("got count %d, want %d", gotCount, wantCount)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if err := quick.Check(it, nil); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHistogramVecConcurrency(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping test in short mode.")
|
||||
}
|
||||
|
||||
rand.Seed(42)
|
||||
|
||||
objectives := make([]float64, 0, len(DefObjectives))
|
||||
for qu := range DefObjectives {
|
||||
|
||||
objectives = append(objectives, qu)
|
||||
}
|
||||
sort.Float64s(objectives)
|
||||
|
||||
it := func(n uint32) bool {
|
||||
mutations := int(n%1e4 + 1e4)
|
||||
concLevel := int(n%7 + 1)
|
||||
vecLength := int(n%3 + 1)
|
||||
|
||||
var start, end sync.WaitGroup
|
||||
start.Add(1)
|
||||
end.Add(concLevel)
|
||||
|
||||
his := NewHistogramVec(
|
||||
HistogramOpts{
|
||||
Name: "test_histogram",
|
||||
Help: "helpless",
|
||||
Buckets: []float64{-2, -1, -0.5, 0, 0.5, 1, 2, math.Inf(+1)},
|
||||
},
|
||||
[]string{"label"},
|
||||
)
|
||||
|
||||
allVars := make([][]float64, vecLength)
|
||||
sampleSums := make([]float64, vecLength)
|
||||
for i := 0; i < concLevel; i++ {
|
||||
vals := make([]float64, mutations)
|
||||
picks := make([]int, mutations)
|
||||
for j := 0; j < mutations; j++ {
|
||||
v := rand.NormFloat64()
|
||||
vals[j] = v
|
||||
pick := rand.Intn(vecLength)
|
||||
picks[j] = pick
|
||||
allVars[pick] = append(allVars[pick], v)
|
||||
sampleSums[pick] += v
|
||||
}
|
||||
|
||||
go func(vals []float64) {
|
||||
start.Wait()
|
||||
for i, v := range vals {
|
||||
his.WithLabelValues(string('A' + picks[i])).Observe(v)
|
||||
}
|
||||
end.Done()
|
||||
}(vals)
|
||||
}
|
||||
for _, vars := range allVars {
|
||||
sort.Float64s(vars)
|
||||
}
|
||||
start.Done()
|
||||
end.Wait()
|
||||
|
||||
for i := 0; i < vecLength; i++ {
|
||||
m := &dto.Metric{}
|
||||
s := his.WithLabelValues(string('A' + i))
|
||||
s.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)
|
||||
}
|
||||
if got, want := int(*m.Histogram.SampleCount), len(allVars[i]); got != want {
|
||||
t.Errorf("got sample count %d, want %d", got, want)
|
||||
}
|
||||
if got, want := *m.Histogram.SampleSum, sampleSums[i]; math.Abs((got-want)/want) > 0.001 {
|
||||
t.Errorf("got sample sum %f, want %f", got, want)
|
||||
}
|
||||
|
||||
wantCounts := getCumulativeCounts(allVars[i])
|
||||
|
||||
for j, wantBound := range testBuckets {
|
||||
if j == len(testBuckets)-1 {
|
||||
break // No +Inf bucket in protobuf.
|
||||
}
|
||||
if gotBound := *m.Histogram.Bucket[j].UpperBound; gotBound != wantBound {
|
||||
t.Errorf("got bound %f, want %f", gotBound, wantBound)
|
||||
}
|
||||
if gotCount, wantCount := *m.Histogram.Bucket[j].CumulativeCount, wantCounts[j]; gotCount != wantCount {
|
||||
t.Errorf("got count %d, want %d", gotCount, wantCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if err := quick.Check(it, nil); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func getCumulativeCounts(vars []float64) []uint64 {
|
||||
counts := make([]uint64, len(testBuckets))
|
||||
for _, v := range vars {
|
||||
for i := len(testBuckets) - 1; i >= 0; i-- {
|
||||
if v > testBuckets[i] {
|
||||
break
|
||||
}
|
||||
counts[i]++
|
||||
}
|
||||
}
|
||||
return counts
|
||||
}
|
||||
|
||||
func TestBuckets(t *testing.T) {
|
||||
got := LinearBuckets(-15, 5, 6)
|
||||
want := []float64{-15, -10, -5, 0, 5, 10}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("linear buckets: got %v, want %v", got, want)
|
||||
}
|
||||
|
||||
got = ExponentialBuckets(100, 1.2, 3)
|
||||
want = []float64{100, 120, 144}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("linear buckets: got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
361
vendor/github.com/prometheus/client_golang/prometheus/http.go
generated
vendored
Normal file
361
vendor/github.com/prometheus/client_golang/prometheus/http.go
generated
vendored
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var instLabels = []string{"method", "code"}
|
||||
|
||||
type nower interface {
|
||||
Now() time.Time
|
||||
}
|
||||
|
||||
type nowFunc func() time.Time
|
||||
|
||||
func (n nowFunc) Now() time.Time {
|
||||
return n()
|
||||
}
|
||||
|
||||
var now nower = nowFunc(func() time.Time {
|
||||
return time.Now()
|
||||
})
|
||||
|
||||
func nowSeries(t ...time.Time) nower {
|
||||
return nowFunc(func() time.Time {
|
||||
defer func() {
|
||||
t = t[1:]
|
||||
}()
|
||||
|
||||
return t[0]
|
||||
})
|
||||
}
|
||||
|
||||
// InstrumentHandler wraps the given HTTP handler for instrumentation. It
|
||||
// registers four metric collectors (if not already done) and reports HTTP
|
||||
// metrics to the (newly or already) registered collectors: http_requests_total
|
||||
// (CounterVec), http_request_duration_microseconds (Summary),
|
||||
// http_request_size_bytes (Summary), http_response_size_bytes (Summary). Each
|
||||
// has a constant label named "handler" with the provided handlerName as
|
||||
// value. http_requests_total is a metric vector partitioned by HTTP method
|
||||
// (label name "method") and HTTP status code (label name "code").
|
||||
func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFunc {
|
||||
return InstrumentHandlerFunc(handlerName, handler.ServeHTTP)
|
||||
}
|
||||
|
||||
// InstrumentHandlerFunc wraps the given function for instrumentation. It
|
||||
// otherwise works in the same way as InstrumentHandler.
|
||||
func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||
return InstrumentHandlerFuncWithOpts(
|
||||
SummaryOpts{
|
||||
Subsystem: "http",
|
||||
ConstLabels: Labels{"handler": handlerName},
|
||||
},
|
||||
handlerFunc,
|
||||
)
|
||||
}
|
||||
|
||||
// InstrumentHandlerWithOpts works like InstrumentHandler but provides more
|
||||
// flexibility (at the cost of a more complex call syntax). As
|
||||
// InstrumentHandler, this function registers four metric collectors, but it
|
||||
// uses the provided SummaryOpts to create them. However, the fields "Name" and
|
||||
// "Help" in the SummaryOpts are ignored. "Name" is replaced by
|
||||
// "requests_total", "request_duration_microseconds", "request_size_bytes", and
|
||||
// "response_size_bytes", respectively. "Help" is replaced by an appropriate
|
||||
// help string. The names of the variable labels of the http_requests_total
|
||||
// CounterVec are "method" (get, post, etc.), and "code" (HTTP status code).
|
||||
//
|
||||
// If InstrumentHandlerWithOpts is called as follows, it mimics exactly the
|
||||
// behavior of InstrumentHandler:
|
||||
//
|
||||
// prometheus.InstrumentHandlerWithOpts(
|
||||
// prometheus.SummaryOpts{
|
||||
// Subsystem: "http",
|
||||
// ConstLabels: prometheus.Labels{"handler": handlerName},
|
||||
// },
|
||||
// handler,
|
||||
// )
|
||||
//
|
||||
// Technical detail: "requests_total" is a CounterVec, not a SummaryVec, so it
|
||||
// cannot use SummaryOpts. Instead, a CounterOpts struct is created internally,
|
||||
// and all its fields are set to the equally named fields in the provided
|
||||
// SummaryOpts.
|
||||
func InstrumentHandlerWithOpts(opts SummaryOpts, handler http.Handler) http.HandlerFunc {
|
||||
return InstrumentHandlerFuncWithOpts(opts, handler.ServeHTTP)
|
||||
}
|
||||
|
||||
// InstrumentHandlerFuncWithOpts works like InstrumentHandlerFunc but provides
|
||||
// more flexibility (at the cost of a more complex call syntax). See
|
||||
// InstrumentHandlerWithOpts for details how the provided SummaryOpts are used.
|
||||
func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||
reqCnt := NewCounterVec(
|
||||
CounterOpts{
|
||||
Namespace: opts.Namespace,
|
||||
Subsystem: opts.Subsystem,
|
||||
Name: "requests_total",
|
||||
Help: "Total number of HTTP requests made.",
|
||||
ConstLabels: opts.ConstLabels,
|
||||
},
|
||||
instLabels,
|
||||
)
|
||||
|
||||
opts.Name = "request_duration_microseconds"
|
||||
opts.Help = "The HTTP request latencies in microseconds."
|
||||
reqDur := NewSummary(opts)
|
||||
|
||||
opts.Name = "request_size_bytes"
|
||||
opts.Help = "The HTTP request sizes in bytes."
|
||||
reqSz := NewSummary(opts)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
_, cn := w.(http.CloseNotifier)
|
||||
_, fl := w.(http.Flusher)
|
||||
_, hj := w.(http.Hijacker)
|
||||
_, rf := w.(io.ReaderFrom)
|
||||
var rw http.ResponseWriter
|
||||
if cn && fl && hj && rf {
|
||||
rw = &fancyResponseWriterDelegator{delegate}
|
||||
} else {
|
||||
rw = delegate
|
||||
}
|
||||
handlerFunc(rw, r)
|
||||
|
||||
elapsed := float64(time.Since(now)) / float64(time.Microsecond)
|
||||
|
||||
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))
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
out <- s
|
||||
}
|
||||
|
||||
type responseWriterDelegator struct {
|
||||
http.ResponseWriter
|
||||
|
||||
handler, method string
|
||||
status int
|
||||
written int64
|
||||
wroteHeader bool
|
||||
}
|
||||
|
||||
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 fancyResponseWriterDelegator struct {
|
||||
*responseWriterDelegator
|
||||
}
|
||||
|
||||
func (f *fancyResponseWriterDelegator) CloseNotify() <-chan bool {
|
||||
return f.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
|
||||
func (f *fancyResponseWriterDelegator) Flush() {
|
||||
f.ResponseWriter.(http.Flusher).Flush()
|
||||
}
|
||||
|
||||
func (f *fancyResponseWriterDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return f.ResponseWriter.(http.Hijacker).Hijack()
|
||||
}
|
||||
|
||||
func (f *fancyResponseWriterDelegator) ReadFrom(r io.Reader) (int64, error) {
|
||||
if !f.wroteHeader {
|
||||
f.WriteHeader(http.StatusOK)
|
||||
}
|
||||
n, err := f.ResponseWriter.(io.ReaderFrom).ReadFrom(r)
|
||||
f.written += n
|
||||
return n, err
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func sanitizeCode(s int) string {
|
||||
switch s {
|
||||
case 100:
|
||||
return "100"
|
||||
case 101:
|
||||
return "101"
|
||||
|
||||
case 200:
|
||||
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)
|
||||
}
|
||||
}
|
||||
121
vendor/github.com/prometheus/client_golang/prometheus/http_test.go
generated
vendored
Normal file
121
vendor/github.com/prometheus/client_golang/prometheus/http_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
type respBody string
|
||||
|
||||
func (b respBody) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusTeapot)
|
||||
w.Write([]byte(b))
|
||||
}
|
||||
|
||||
func TestInstrumentHandler(t *testing.T) {
|
||||
defer func(n nower) {
|
||||
now = n.(nower)
|
||||
}(now)
|
||||
|
||||
instant := time.Now()
|
||||
end := instant.Add(30 * time.Second)
|
||||
now = nowSeries(instant, end)
|
||||
respBody := respBody("Howdy there!")
|
||||
|
||||
hndlr := InstrumentHandler("test-handler", respBody)
|
||||
|
||||
opts := SummaryOpts{
|
||||
Subsystem: "http",
|
||||
ConstLabels: Labels{"handler": "test-handler"},
|
||||
}
|
||||
|
||||
reqCnt := MustRegisterOrGet(NewCounterVec(
|
||||
CounterOpts{
|
||||
Namespace: opts.Namespace,
|
||||
Subsystem: opts.Subsystem,
|
||||
Name: "requests_total",
|
||||
Help: "Total number of HTTP requests made.",
|
||||
ConstLabels: opts.ConstLabels,
|
||||
},
|
||||
instLabels,
|
||||
)).(*CounterVec)
|
||||
|
||||
opts.Name = "request_duration_microseconds"
|
||||
opts.Help = "The HTTP request latencies in microseconds."
|
||||
reqDur := MustRegisterOrGet(NewSummary(opts)).(Summary)
|
||||
|
||||
opts.Name = "request_size_bytes"
|
||||
opts.Help = "The HTTP request sizes in bytes."
|
||||
MustRegisterOrGet(NewSummary(opts))
|
||||
|
||||
opts.Name = "response_size_bytes"
|
||||
opts.Help = "The HTTP response sizes in bytes."
|
||||
MustRegisterOrGet(NewSummary(opts))
|
||||
|
||||
reqCnt.Reset()
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req := &http.Request{
|
||||
Method: "GET",
|
||||
}
|
||||
|
||||
hndlr.ServeHTTP(resp, req)
|
||||
|
||||
if resp.Code != http.StatusTeapot {
|
||||
t.Fatalf("expected status %d, got %d", http.StatusTeapot, resp.Code)
|
||||
}
|
||||
if string(resp.Body.Bytes()) != "Howdy there!" {
|
||||
t.Fatalf("expected body %s, got %s", "Howdy there!", string(resp.Body.Bytes()))
|
||||
}
|
||||
|
||||
out := &dto.Metric{}
|
||||
reqDur.Write(out)
|
||||
if want, got := "test-handler", out.Label[0].GetValue(); want != got {
|
||||
t.Errorf("want label value %q in reqDur, got %q", want, got)
|
||||
}
|
||||
if want, got := uint64(1), out.Summary.GetSampleCount(); want != got {
|
||||
t.Errorf("want sample count %d in reqDur, got %d", want, got)
|
||||
}
|
||||
|
||||
out.Reset()
|
||||
if want, got := 1, len(reqCnt.children); want != got {
|
||||
t.Errorf("want %d children in reqCnt, got %d", want, got)
|
||||
}
|
||||
cnt, err := reqCnt.GetMetricWithLabelValues("get", "418")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cnt.Write(out)
|
||||
if want, got := "418", out.Label[0].GetValue(); want != got {
|
||||
t.Errorf("want label value %q in reqCnt, got %q", want, got)
|
||||
}
|
||||
if want, got := "test-handler", out.Label[1].GetValue(); want != got {
|
||||
t.Errorf("want label value %q in reqCnt, got %q", want, got)
|
||||
}
|
||||
if want, got := "get", out.Label[2].GetValue(); want != got {
|
||||
t.Errorf("want label value %q in reqCnt, got %q", want, got)
|
||||
}
|
||||
if out.Counter == nil {
|
||||
t.Fatal("expected non-nil counter in reqCnt")
|
||||
}
|
||||
if want, got := 1., out.Counter.GetValue(); want != got {
|
||||
t.Errorf("want reqCnt of %f, got %f", want, got)
|
||||
}
|
||||
}
|
||||
166
vendor/github.com/prometheus/client_golang/prometheus/metric.go
generated
vendored
Normal file
166
vendor/github.com/prometheus/client_golang/prometheus/metric.go
generated
vendored
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
const separatorByte byte = 255
|
||||
|
||||
// A Metric models a single sample value with its meta data being exported to
|
||||
// Prometheus. Implementers of Metric in this package inclued Gauge, Counter,
|
||||
// Untyped, and Summary. Users can implement their own Metric types, but that
|
||||
// should be rarely needed. See the example for SelfCollector, which is also an
|
||||
// example for a user-implemented Metric.
|
||||
type Metric interface {
|
||||
// Desc returns the descriptor for the Metric. This method idempotently
|
||||
// returns the same descriptor throughout the lifetime of the
|
||||
// Metric. The returned descriptor is immutable by contract. A Metric
|
||||
// unable to describe itself must return an invalid descriptor (created
|
||||
// with NewInvalidDesc).
|
||||
Desc() *Desc
|
||||
// Write encodes the Metric into a "Metric" Protocol Buffer data
|
||||
// transmission object.
|
||||
//
|
||||
// Implementers of custom Metric types must observe concurrency safety
|
||||
// as reads of this metric may occur at any time, and any blocking
|
||||
// occurs at the expense of total performance of rendering all
|
||||
// registered metrics. Ideally Metric implementations should support
|
||||
// concurrent readers.
|
||||
//
|
||||
// The Prometheus client library attempts to minimize memory allocations
|
||||
// and will provide a pre-existing reset dto.Metric pointer. Prometheus
|
||||
// may recycle the dto.Metric proto message, so Metric implementations
|
||||
// should just populate the provided dto.Metric and then should not keep
|
||||
// any reference to it.
|
||||
//
|
||||
// While populating dto.Metric, labels must be sorted lexicographically.
|
||||
// (Implementers may find LabelPairSorter useful for that.)
|
||||
Write(*dto.Metric) error
|
||||
}
|
||||
|
||||
// Opts bundles the options for creating most Metric types. Each metric
|
||||
// implementation XXX has its own XXXOpts type, but in most cases, it is just be
|
||||
// an alias of this type (which might change when the requirement arises.)
|
||||
//
|
||||
// It is mandatory to set Name and Help to a non-empty string. All other fields
|
||||
// are optional and can safely be left at their zero value.
|
||||
type Opts struct {
|
||||
// Namespace, Subsystem, and Name are components of the fully-qualified
|
||||
// name of the Metric (created by joining these components with
|
||||
// "_"). Only Name is mandatory, the others merely help structuring the
|
||||
// name. Note that the fully-qualified name of the metric must be a
|
||||
// valid Prometheus metric name.
|
||||
Namespace string
|
||||
Subsystem string
|
||||
Name string
|
||||
|
||||
// Help provides information about this metric. Mandatory!
|
||||
//
|
||||
// Metrics with the same fully-qualified name must have the same Help
|
||||
// string.
|
||||
Help string
|
||||
|
||||
// ConstLabels are used to attach fixed labels to this metric. Metrics
|
||||
// with the same fully-qualified name must have the same label names in
|
||||
// their ConstLabels.
|
||||
//
|
||||
// Note that in most cases, labels have a value that varies during the
|
||||
// lifetime of a process. Those labels are usually managed with a metric
|
||||
// vector collector (like CounterVec, GaugeVec, UntypedVec). ConstLabels
|
||||
// serve only special purposes. One is for the special case where the
|
||||
// value of a label does not change during the lifetime of a process,
|
||||
// e.g. if the revision of the running binary is put into a
|
||||
// label. Another, more advanced purpose is if more than one Collector
|
||||
// needs to collect Metrics with the same fully-qualified name. In that
|
||||
// case, those Metrics must differ in the values of their
|
||||
// ConstLabels. See the Collector examples.
|
||||
//
|
||||
// If the value of a label never changes (not even between binaries),
|
||||
// that label most likely should not be a label at all (but part of the
|
||||
// metric name).
|
||||
ConstLabels Labels
|
||||
}
|
||||
|
||||
// BuildFQName joins the given three name components by "_". Empty name
|
||||
// components are ignored. If the name parameter itself is empty, an empty
|
||||
// string is returned, no matter what. Metric implementations included in this
|
||||
// library use this function internally to generate the fully-qualified metric
|
||||
// name from the name component in their Opts. Users of the library will only
|
||||
// need this function if they implement their own Metric or instantiate a Desc
|
||||
// (with NewDesc) directly.
|
||||
func BuildFQName(namespace, subsystem, name string) string {
|
||||
if name == "" {
|
||||
return ""
|
||||
}
|
||||
switch {
|
||||
case namespace != "" && subsystem != "":
|
||||
return strings.Join([]string{namespace, subsystem, name}, "_")
|
||||
case namespace != "":
|
||||
return strings.Join([]string{namespace, name}, "_")
|
||||
case subsystem != "":
|
||||
return strings.Join([]string{subsystem, name}, "_")
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// LabelPairSorter implements sort.Interface. It is used to sort a slice of
|
||||
// dto.LabelPair pointers. This is useful for implementing the Write method of
|
||||
// custom metrics.
|
||||
type LabelPairSorter []*dto.LabelPair
|
||||
|
||||
func (s LabelPairSorter) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s LabelPairSorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s LabelPairSorter) Less(i, j int) bool {
|
||||
return s[i].GetName() < s[j].GetName()
|
||||
}
|
||||
|
||||
type hashSorter []uint64
|
||||
|
||||
func (s hashSorter) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s hashSorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s hashSorter) Less(i, j int) bool {
|
||||
return s[i] < s[j]
|
||||
}
|
||||
|
||||
type invalidMetric struct {
|
||||
desc *Desc
|
||||
err error
|
||||
}
|
||||
|
||||
// NewInvalidMetric returns a metric whose Write method always returns the
|
||||
// provided error. It is useful if a Collector finds itself unable to collect
|
||||
// a metric and wishes to report an error to the registry.
|
||||
func NewInvalidMetric(desc *Desc, err error) Metric {
|
||||
return &invalidMetric{desc, err}
|
||||
}
|
||||
|
||||
func (m *invalidMetric) Desc() *Desc { return m.desc }
|
||||
|
||||
func (m *invalidMetric) Write(*dto.Metric) error { return m.err }
|
||||
35
vendor/github.com/prometheus/client_golang/prometheus/metric_test.go
generated
vendored
Normal file
35
vendor/github.com/prometheus/client_golang/prometheus/metric_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// 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
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestBuildFQName(t *testing.T) {
|
||||
scenarios := []struct{ namespace, subsystem, name, result string }{
|
||||
{"a", "b", "c", "a_b_c"},
|
||||
{"", "b", "c", "b_c"},
|
||||
{"a", "", "c", "a_c"},
|
||||
{"", "", "c", "c"},
|
||||
{"a", "b", "", ""},
|
||||
{"a", "", "", ""},
|
||||
{"", "b", "", ""},
|
||||
{" ", "", "", ""},
|
||||
}
|
||||
|
||||
for i, s := range scenarios {
|
||||
if want, got := s.result, BuildFQName(s.namespace, s.subsystem, s.name); want != got {
|
||||
t.Errorf("%d. want %s, got %s", i, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
142
vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
generated
vendored
Normal file
142
vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
generated
vendored
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
// 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.
|
||||
|
||||
package prometheus
|
||||
|
||||
import "github.com/prometheus/procfs"
|
||||
|
||||
type processCollector struct {
|
||||
pid int
|
||||
collectFn func(chan<- Metric)
|
||||
pidFn func() (int, error)
|
||||
cpuTotal Counter
|
||||
openFDs, maxFDs Gauge
|
||||
vsize, rss Gauge
|
||||
startTime Gauge
|
||||
}
|
||||
|
||||
// NewProcessCollector returns a collector which exports the current state of
|
||||
// process metrics including cpu, memory and file descriptor usage as well as
|
||||
// the process start time for the given process id under the given namespace.
|
||||
func NewProcessCollector(pid int, namespace string) *processCollector {
|
||||
return NewProcessCollectorPIDFn(
|
||||
func() (int, error) { return pid, nil },
|
||||
namespace,
|
||||
)
|
||||
}
|
||||
|
||||
// NewProcessCollectorPIDFn returns a collector which exports the current state
|
||||
// of process metrics including cpu, memory and file descriptor usage as well
|
||||
// as the process start time under the given namespace. The given pidFn is
|
||||
// called on each collect and is used to determine the process to export
|
||||
// metrics for.
|
||||
func NewProcessCollectorPIDFn(
|
||||
pidFn func() (int, error),
|
||||
namespace string,
|
||||
) *processCollector {
|
||||
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.",
|
||||
}),
|
||||
}
|
||||
|
||||
// Set up process metric collection if supported by the runtime.
|
||||
if _, err := procfs.NewStat(); err == nil {
|
||||
c.collectFn = c.processCollect
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
// Collect returns the current state of all metrics of the collector.
|
||||
func (c *processCollector) Collect(ch chan<- Metric) {
|
||||
c.collectFn(ch)
|
||||
}
|
||||
|
||||
// TODO(ts): Bring back error reporting by reverting 7faf9e7 as soon as the
|
||||
// client allows users to configure the error behavior.
|
||||
func (c *processCollector) processCollect(ch chan<- Metric) {
|
||||
pid, err := c.pidFn()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
p, err := procfs.NewProc(pid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
if startTime, err := stat.StartTime(); err == nil {
|
||||
c.startTime.Set(startTime)
|
||||
ch <- c.startTime
|
||||
}
|
||||
}
|
||||
|
||||
if fds, err := p.FileDescriptorsLen(); err == nil {
|
||||
c.openFDs.Set(float64(fds))
|
||||
ch <- c.openFDs
|
||||
}
|
||||
|
||||
if limits, err := p.NewLimits(); err == nil {
|
||||
c.maxFDs.Set(float64(limits.OpenFiles))
|
||||
ch <- c.maxFDs
|
||||
}
|
||||
}
|
||||
54
vendor/github.com/prometheus/client_golang/prometheus/process_collector_test.go
generated
vendored
Normal file
54
vendor/github.com/prometheus/client_golang/prometheus/process_collector_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
package prometheus
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/procfs"
|
||||
)
|
||||
|
||||
func TestProcessCollector(t *testing.T) {
|
||||
if _, err := procfs.Self(); err != nil {
|
||||
t.Skipf("skipping TestProcessCollector, procfs not available: %s", err)
|
||||
}
|
||||
|
||||
registry := newRegistry()
|
||||
registry.Register(NewProcessCollector(os.Getpid(), ""))
|
||||
registry.Register(NewProcessCollectorPIDFn(
|
||||
func() (int, error) { return os.Getpid(), nil }, "foobar"))
|
||||
|
||||
s := httptest.NewServer(InstrumentHandler("prometheus", registry))
|
||||
defer s.Close()
|
||||
r, err := http.Get(s.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer r.Body.Close()
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, re := range []*regexp.Regexp{
|
||||
regexp.MustCompile("process_cpu_seconds_total [0-9]"),
|
||||
regexp.MustCompile("process_max_fds [0-9]{2,}"),
|
||||
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 [0-9]{2,}"),
|
||||
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,}"),
|
||||
} {
|
||||
if !re.Match(body) {
|
||||
t.Errorf("want body to match %s\n%s", re, body)
|
||||
}
|
||||
}
|
||||
}
|
||||
65
vendor/github.com/prometheus/client_golang/prometheus/push.go
generated
vendored
Normal file
65
vendor/github.com/prometheus/client_golang/prometheus/push.go
generated
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// 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.
|
||||
|
||||
// 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 prometheus
|
||||
|
||||
// Push triggers a metric collection by the default registry and pushes all
|
||||
// collected metrics to the Pushgateway specified by addr. See the Pushgateway
|
||||
// documentation for detailed implications of the job and instance
|
||||
// parameter. instance can be left empty. You can use just host:port or ip:port
|
||||
// as url, in which case 'http://' is added automatically. You can also include
|
||||
// the schema in the URL. However, do not include the '/metrics/jobs/...' part.
|
||||
//
|
||||
// Note that all previously pushed metrics with the same job and instance will
|
||||
// be replaced with the metrics pushed by this call. (It uses HTTP method 'PUT'
|
||||
// to push to the Pushgateway.)
|
||||
func Push(job, instance, url string) error {
|
||||
return defRegistry.Push(job, instance, url, "PUT")
|
||||
}
|
||||
|
||||
// PushAdd works like Push, but only previously pushed metrics with the same
|
||||
// name (and the same job and instance) will be replaced. (It uses HTTP method
|
||||
// 'POST' to push to the Pushgateway.)
|
||||
func PushAdd(job, instance, url string) error {
|
||||
return defRegistry.Push(job, instance, url, "POST")
|
||||
}
|
||||
|
||||
// PushCollectors works like Push, but it does not collect from the default
|
||||
// registry. Instead, it collects from the provided collectors. It is a
|
||||
// convenient way to push only a few metrics.
|
||||
func PushCollectors(job, instance, url string, collectors ...Collector) error {
|
||||
return pushCollectors(job, instance, url, "PUT", collectors...)
|
||||
}
|
||||
|
||||
// PushAddCollectors works like PushAdd, but it does not collect from the
|
||||
// default registry. Instead, it collects from the provided collectors. It is a
|
||||
// convenient way to push only a few metrics.
|
||||
func PushAddCollectors(job, instance, url string, collectors ...Collector) error {
|
||||
return pushCollectors(job, instance, url, "POST", collectors...)
|
||||
}
|
||||
|
||||
func pushCollectors(job, instance, url, method string, collectors ...Collector) error {
|
||||
r := newRegistry()
|
||||
for _, collector := range collectors {
|
||||
if _, err := r.Register(collector); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return r.Push(job, instance, url, method)
|
||||
}
|
||||
726
vendor/github.com/prometheus/client_golang/prometheus/registry.go
generated
vendored
Normal file
726
vendor/github.com/prometheus/client_golang/prometheus/registry.go
generated
vendored
Normal file
|
|
@ -0,0 +1,726 @@
|
|||
// 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.
|
||||
|
||||
// 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 prometheus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/prometheus/common/expfmt"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
var (
|
||||
defRegistry = newDefaultRegistry()
|
||||
errAlreadyReg = errors.New("duplicate metrics collector registration attempted")
|
||||
)
|
||||
|
||||
// Constants relevant to the HTTP interface.
|
||||
const (
|
||||
// APIVersion is the version of the format of the exported data. This
|
||||
// will match this library's version, which subscribes to the Semantic
|
||||
// Versioning scheme.
|
||||
APIVersion = "0.0.4"
|
||||
|
||||
// DelimitedTelemetryContentType is the content type set on telemetry
|
||||
// data responses in delimited protobuf format.
|
||||
DelimitedTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`
|
||||
// TextTelemetryContentType is the content type set on telemetry data
|
||||
// responses in text format.
|
||||
TextTelemetryContentType = `text/plain; version=` + APIVersion
|
||||
// ProtoTextTelemetryContentType is the content type set on telemetry
|
||||
// data responses in protobuf text format. (Only used for debugging.)
|
||||
ProtoTextTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=text`
|
||||
// ProtoCompactTextTelemetryContentType is the content type set on
|
||||
// telemetry data responses in protobuf compact text format. (Only used
|
||||
// for debugging.)
|
||||
ProtoCompactTextTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=compact-text`
|
||||
|
||||
// Constants for object pools.
|
||||
numBufs = 4
|
||||
numMetricFamilies = 1000
|
||||
numMetrics = 10000
|
||||
|
||||
// Capacity for the channel to collect metrics and descriptors.
|
||||
capMetricChan = 1000
|
||||
capDescChan = 10
|
||||
|
||||
contentTypeHeader = "Content-Type"
|
||||
contentLengthHeader = "Content-Length"
|
||||
contentEncodingHeader = "Content-Encoding"
|
||||
|
||||
acceptEncodingHeader = "Accept-Encoding"
|
||||
acceptHeader = "Accept"
|
||||
)
|
||||
|
||||
// Handler returns the HTTP handler for the global Prometheus registry. It is
|
||||
// already instrumented with InstrumentHandler (using "prometheus" as handler
|
||||
// name). Usually the handler is used to handle the "/metrics" endpoint.
|
||||
func Handler() http.Handler {
|
||||
return InstrumentHandler("prometheus", defRegistry)
|
||||
}
|
||||
|
||||
// UninstrumentedHandler works in the same way as Handler, but the returned HTTP
|
||||
// handler is not instrumented. This is useful if no instrumentation is desired
|
||||
// (for whatever reason) or if the instrumentation has to happen with a
|
||||
// different handler name (or with a different instrumentation approach
|
||||
// altogether). See the InstrumentHandler example.
|
||||
func UninstrumentedHandler() http.Handler {
|
||||
return defRegistry
|
||||
}
|
||||
|
||||
// Register registers a new Collector to be included in metrics collection. It
|
||||
// returns an error if the descriptors provided by the Collector are invalid or
|
||||
// if they - in combination with descriptors of already registered Collectors -
|
||||
// do not fulfill the consistency and uniqueness criteria described in the Desc
|
||||
// documentation.
|
||||
//
|
||||
// Do not register the same Collector multiple times concurrently. (Registering
|
||||
// the same Collector twice would result in an error anyway, but on top of that,
|
||||
// it is not safe to do so concurrently.)
|
||||
func Register(m Collector) error {
|
||||
_, err := defRegistry.Register(m)
|
||||
return err
|
||||
}
|
||||
|
||||
// MustRegister works like Register but panics where Register would have
|
||||
// returned an error.
|
||||
func MustRegister(m Collector) {
|
||||
err := Register(m)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterOrGet works like Register but does not return an error if a Collector
|
||||
// is registered that equals a previously registered Collector. (Two Collectors
|
||||
// are considered equal if their Describe method yields the same set of
|
||||
// descriptors.) Instead, the previously registered Collector is returned (which
|
||||
// is helpful if the new and previously registered Collectors are equal but not
|
||||
// identical, i.e. not pointers to the same object).
|
||||
//
|
||||
// As for Register, it is still not safe to call RegisterOrGet with the same
|
||||
// Collector multiple times concurrently.
|
||||
func RegisterOrGet(m Collector) (Collector, error) {
|
||||
return defRegistry.RegisterOrGet(m)
|
||||
}
|
||||
|
||||
// MustRegisterOrGet works like Register but panics where RegisterOrGet would
|
||||
// have returned an error.
|
||||
func MustRegisterOrGet(m Collector) Collector {
|
||||
existing, err := RegisterOrGet(m)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return existing
|
||||
}
|
||||
|
||||
// Unregister unregisters the Collector that equals the Collector passed in as
|
||||
// an argument. (Two Collectors are considered equal if their Describe method
|
||||
// yields the same set of descriptors.) The function returns whether a Collector
|
||||
// was unregistered.
|
||||
func Unregister(c Collector) bool {
|
||||
return defRegistry.Unregister(c)
|
||||
}
|
||||
|
||||
// SetMetricFamilyInjectionHook sets a function that is called whenever metrics
|
||||
// are collected. The hook function must be set before metrics collection begins
|
||||
// (i.e. call SetMetricFamilyInjectionHook before setting the HTTP handler.) The
|
||||
// MetricFamily protobufs returned by the hook function are merged with the
|
||||
// metrics collected in the usual way.
|
||||
//
|
||||
// This is a way to directly inject MetricFamily protobufs managed and owned by
|
||||
// the caller. The caller has full responsibility. As no registration of the
|
||||
// injected metrics has happened, there is no descriptor to check against, and
|
||||
// there are no registration-time checks. If collect-time checks are disabled
|
||||
// (see function EnableCollectChecks), no sanity checks are performed on the
|
||||
// returned protobufs at all. If collect-checks are enabled, type and uniqueness
|
||||
// checks are performed, but no further consistency checks (which would require
|
||||
// knowledge of a metric descriptor).
|
||||
//
|
||||
// Sorting concerns: The caller is responsible for sorting the label pairs in
|
||||
// each metric. However, the order of metrics will be sorted by the registry as
|
||||
// it is required anyway after merging with the metric families collected
|
||||
// conventionally.
|
||||
//
|
||||
// The function must be callable at any time and concurrently.
|
||||
func SetMetricFamilyInjectionHook(hook func() []*dto.MetricFamily) {
|
||||
defRegistry.metricFamilyInjectionHook = hook
|
||||
}
|
||||
|
||||
// PanicOnCollectError sets the behavior whether a panic is caused upon an error
|
||||
// while metrics are collected and served to the HTTP endpoint. By default, an
|
||||
// internal server error (status code 500) is served with an error message.
|
||||
func PanicOnCollectError(b bool) {
|
||||
defRegistry.panicOnCollectError = b
|
||||
}
|
||||
|
||||
// EnableCollectChecks enables (or disables) additional consistency checks
|
||||
// during metrics collection. These additional checks are not enabled by default
|
||||
// because they inflict a performance penalty and the errors they check for can
|
||||
// only happen if the used Metric and Collector types have internal programming
|
||||
// errors. It can be helpful to enable these checks while working with custom
|
||||
// Collectors or Metrics whose correctness is not well established yet.
|
||||
func EnableCollectChecks(b bool) {
|
||||
defRegistry.collectChecksEnabled = b
|
||||
}
|
||||
|
||||
// encoder is a function that writes a dto.MetricFamily to an io.Writer in a
|
||||
// certain encoding. It returns the number of bytes written and any error
|
||||
// encountered. Note that pbutil.WriteDelimited and pbutil.MetricFamilyToText
|
||||
// are encoders.
|
||||
type encoder func(io.Writer, *dto.MetricFamily) (int, error)
|
||||
|
||||
type registry struct {
|
||||
mtx sync.RWMutex
|
||||
collectorsByID map[uint64]Collector // ID is a hash of the descIDs.
|
||||
descIDs map[uint64]struct{}
|
||||
dimHashesByName map[string]uint64
|
||||
bufPool chan *bytes.Buffer
|
||||
metricFamilyPool chan *dto.MetricFamily
|
||||
metricPool chan *dto.Metric
|
||||
metricFamilyInjectionHook func() []*dto.MetricFamily
|
||||
|
||||
panicOnCollectError, collectChecksEnabled bool
|
||||
}
|
||||
|
||||
func (r *registry) Register(c Collector) (Collector, error) {
|
||||
descChan := make(chan *Desc, capDescChan)
|
||||
go func() {
|
||||
c.Describe(descChan)
|
||||
close(descChan)
|
||||
}()
|
||||
|
||||
newDescIDs := map[uint64]struct{}{}
|
||||
newDimHashesByName := map[string]uint64{}
|
||||
var collectorID uint64 // Just a sum of all desc IDs.
|
||||
var duplicateDescErr error
|
||||
|
||||
r.mtx.Lock()
|
||||
defer r.mtx.Unlock()
|
||||
// Coduct various tests...
|
||||
for desc := range descChan {
|
||||
|
||||
// Is the descriptor valid at all?
|
||||
if desc.err != nil {
|
||||
return c, fmt.Errorf("descriptor %s is invalid: %s", desc, desc.err)
|
||||
}
|
||||
|
||||
// Is the descID unique?
|
||||
// (In other words: Is the fqName + constLabel combination unique?)
|
||||
if _, exists := r.descIDs[desc.id]; exists {
|
||||
duplicateDescErr = fmt.Errorf("descriptor %s already exists with the same fully-qualified name and const label values", desc)
|
||||
}
|
||||
// If it is not a duplicate desc in this collector, add it to
|
||||
// the collectorID. (We allow duplicate descs within the same
|
||||
// collector, but their existence must be a no-op.)
|
||||
if _, exists := newDescIDs[desc.id]; !exists {
|
||||
newDescIDs[desc.id] = struct{}{}
|
||||
collectorID += desc.id
|
||||
}
|
||||
|
||||
// Are all the label names and the help string consistent with
|
||||
// previous descriptors of the same name?
|
||||
// First check existing descriptors...
|
||||
if dimHash, exists := r.dimHashesByName[desc.fqName]; exists {
|
||||
if dimHash != desc.dimHash {
|
||||
return nil, fmt.Errorf("a previously registered descriptor with the same fully-qualified name as %s has different label names or a different help string", desc)
|
||||
}
|
||||
} else {
|
||||
// ...then check the new descriptors already seen.
|
||||
if dimHash, exists := newDimHashesByName[desc.fqName]; exists {
|
||||
if dimHash != desc.dimHash {
|
||||
return nil, fmt.Errorf("descriptors reported by collector have inconsistent label names or help strings for the same fully-qualified name, offender is %s", desc)
|
||||
}
|
||||
} else {
|
||||
newDimHashesByName[desc.fqName] = desc.dimHash
|
||||
}
|
||||
}
|
||||
}
|
||||
// Did anything happen at all?
|
||||
if len(newDescIDs) == 0 {
|
||||
return nil, errors.New("collector has no descriptors")
|
||||
}
|
||||
if existing, exists := r.collectorsByID[collectorID]; exists {
|
||||
return existing, errAlreadyReg
|
||||
}
|
||||
// If the collectorID is new, but at least one of the descs existed
|
||||
// before, we are in trouble.
|
||||
if duplicateDescErr != nil {
|
||||
return nil, duplicateDescErr
|
||||
}
|
||||
|
||||
// Only after all tests have passed, actually register.
|
||||
r.collectorsByID[collectorID] = c
|
||||
for hash := range newDescIDs {
|
||||
r.descIDs[hash] = struct{}{}
|
||||
}
|
||||
for name, dimHash := range newDimHashesByName {
|
||||
r.dimHashesByName[name] = dimHash
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (r *registry) RegisterOrGet(m Collector) (Collector, error) {
|
||||
existing, err := r.Register(m)
|
||||
if err != nil && err != errAlreadyReg {
|
||||
return nil, err
|
||||
}
|
||||
return existing, nil
|
||||
}
|
||||
|
||||
func (r *registry) Unregister(c Collector) bool {
|
||||
descChan := make(chan *Desc, capDescChan)
|
||||
go func() {
|
||||
c.Describe(descChan)
|
||||
close(descChan)
|
||||
}()
|
||||
|
||||
descIDs := map[uint64]struct{}{}
|
||||
var collectorID uint64 // Just a sum of the desc IDs.
|
||||
for desc := range descChan {
|
||||
if _, exists := descIDs[desc.id]; !exists {
|
||||
collectorID += desc.id
|
||||
descIDs[desc.id] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
r.mtx.RLock()
|
||||
if _, exists := r.collectorsByID[collectorID]; !exists {
|
||||
r.mtx.RUnlock()
|
||||
return false
|
||||
}
|
||||
r.mtx.RUnlock()
|
||||
|
||||
r.mtx.Lock()
|
||||
defer r.mtx.Unlock()
|
||||
|
||||
delete(r.collectorsByID, collectorID)
|
||||
for id := range descIDs {
|
||||
delete(r.descIDs, id)
|
||||
}
|
||||
// dimHashesByName is left untouched as those must be consistent
|
||||
// throughout the lifetime of a program.
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *registry) Push(job, instance, pushURL, method string) error {
|
||||
if !strings.Contains(pushURL, "://") {
|
||||
pushURL = "http://" + pushURL
|
||||
}
|
||||
pushURL = fmt.Sprintf("%s/metrics/jobs/%s", pushURL, url.QueryEscape(job))
|
||||
if instance != "" {
|
||||
pushURL += "/instances/" + url.QueryEscape(instance)
|
||||
}
|
||||
buf := r.getBuf()
|
||||
defer r.giveBuf(buf)
|
||||
if err := r.writePB(expfmt.NewEncoder(buf, expfmt.FmtProtoDelim)); err != nil {
|
||||
if r.panicOnCollectError {
|
||||
panic(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest(method, pushURL, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set(contentTypeHeader, DelimitedTelemetryContentType)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 202 {
|
||||
return fmt.Errorf("unexpected status code %d while pushing to %s", resp.StatusCode, pushURL)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *registry) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
contentType := expfmt.Negotiate(req.Header)
|
||||
buf := r.getBuf()
|
||||
defer r.giveBuf(buf)
|
||||
writer, encoding := decorateWriter(req, buf)
|
||||
if err := r.writePB(expfmt.NewEncoder(writer, contentType)); err != nil {
|
||||
if r.panicOnCollectError {
|
||||
panic(err)
|
||||
}
|
||||
http.Error(w, "An error has occurred:\n\n"+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if closer, ok := writer.(io.Closer); ok {
|
||||
closer.Close()
|
||||
}
|
||||
header := w.Header()
|
||||
header.Set(contentTypeHeader, string(contentType))
|
||||
header.Set(contentLengthHeader, fmt.Sprint(buf.Len()))
|
||||
if encoding != "" {
|
||||
header.Set(contentEncodingHeader, encoding)
|
||||
}
|
||||
w.Write(buf.Bytes())
|
||||
}
|
||||
|
||||
func (r *registry) writePB(encoder expfmt.Encoder) error {
|
||||
var metricHashes map[uint64]struct{}
|
||||
if r.collectChecksEnabled {
|
||||
metricHashes = make(map[uint64]struct{})
|
||||
}
|
||||
metricChan := make(chan Metric, capMetricChan)
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
r.mtx.RLock()
|
||||
metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName))
|
||||
|
||||
// Scatter.
|
||||
// (Collectors could be complex and slow, so we call them all at once.)
|
||||
wg.Add(len(r.collectorsByID))
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(metricChan)
|
||||
}()
|
||||
for _, collector := range r.collectorsByID {
|
||||
go func(collector Collector) {
|
||||
defer wg.Done()
|
||||
collector.Collect(metricChan)
|
||||
}(collector)
|
||||
}
|
||||
r.mtx.RUnlock()
|
||||
|
||||
// Drain metricChan in case of premature return.
|
||||
defer func() {
|
||||
for _ = range metricChan {
|
||||
}
|
||||
}()
|
||||
|
||||
// Gather.
|
||||
for metric := range metricChan {
|
||||
// This could be done concurrently, too, but it required locking
|
||||
// of metricFamiliesByName (and of metricHashes if checks are
|
||||
// enabled). Most likely not worth it.
|
||||
desc := metric.Desc()
|
||||
metricFamily, ok := metricFamiliesByName[desc.fqName]
|
||||
if !ok {
|
||||
metricFamily = r.getMetricFamily()
|
||||
defer r.giveMetricFamily(metricFamily)
|
||||
metricFamily.Name = proto.String(desc.fqName)
|
||||
metricFamily.Help = proto.String(desc.help)
|
||||
metricFamiliesByName[desc.fqName] = metricFamily
|
||||
}
|
||||
dtoMetric := r.getMetric()
|
||||
defer r.giveMetric(dtoMetric)
|
||||
if err := metric.Write(dtoMetric); err != nil {
|
||||
// TODO: Consider different means of error reporting so
|
||||
// that a single erroneous metric could be skipped
|
||||
// instead of blowing up the whole collection.
|
||||
return fmt.Errorf("error collecting metric %v: %s", desc, err)
|
||||
}
|
||||
switch {
|
||||
case metricFamily.Type != nil:
|
||||
// Type already set. We are good.
|
||||
case dtoMetric.Gauge != nil:
|
||||
metricFamily.Type = dto.MetricType_GAUGE.Enum()
|
||||
case dtoMetric.Counter != nil:
|
||||
metricFamily.Type = dto.MetricType_COUNTER.Enum()
|
||||
case dtoMetric.Summary != nil:
|
||||
metricFamily.Type = dto.MetricType_SUMMARY.Enum()
|
||||
case dtoMetric.Untyped != nil:
|
||||
metricFamily.Type = dto.MetricType_UNTYPED.Enum()
|
||||
case dtoMetric.Histogram != nil:
|
||||
metricFamily.Type = dto.MetricType_HISTOGRAM.Enum()
|
||||
default:
|
||||
return fmt.Errorf("empty metric collected: %s", dtoMetric)
|
||||
}
|
||||
if r.collectChecksEnabled {
|
||||
if err := r.checkConsistency(metricFamily, dtoMetric, desc, metricHashes); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
metricFamily.Metric = append(metricFamily.Metric, dtoMetric)
|
||||
}
|
||||
|
||||
if r.metricFamilyInjectionHook != nil {
|
||||
for _, mf := range r.metricFamilyInjectionHook() {
|
||||
existingMF, exists := metricFamiliesByName[mf.GetName()]
|
||||
if !exists {
|
||||
metricFamiliesByName[mf.GetName()] = mf
|
||||
if r.collectChecksEnabled {
|
||||
for _, m := range mf.Metric {
|
||||
if err := r.checkConsistency(mf, m, nil, metricHashes); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
for _, m := range mf.Metric {
|
||||
if r.collectChecksEnabled {
|
||||
if err := r.checkConsistency(existingMF, m, nil, metricHashes); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
existingMF.Metric = append(existingMF.Metric, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now that MetricFamilies are all set, sort their Metrics
|
||||
// lexicographically by their label values.
|
||||
for _, mf := range metricFamiliesByName {
|
||||
sort.Sort(metricSorter(mf.Metric))
|
||||
}
|
||||
|
||||
// Write out MetricFamilies sorted by their name.
|
||||
names := make([]string, 0, len(metricFamiliesByName))
|
||||
for name := range metricFamiliesByName {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
for _, name := range names {
|
||||
if err := encoder.Encode(metricFamiliesByName[name]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *dto.Metric, desc *Desc, metricHashes map[uint64]struct{}) error {
|
||||
|
||||
// Type consistency with metric family.
|
||||
if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil ||
|
||||
metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil ||
|
||||
metricFamily.GetType() == dto.MetricType_SUMMARY && dtoMetric.Summary == nil ||
|
||||
metricFamily.GetType() == dto.MetricType_HISTOGRAM && dtoMetric.Histogram == nil ||
|
||||
metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil {
|
||||
return fmt.Errorf(
|
||||
"collected metric %s %s is not a %s",
|
||||
metricFamily.GetName(), dtoMetric, metricFamily.GetType(),
|
||||
)
|
||||
}
|
||||
|
||||
// Is the metric unique (i.e. no other metric with the same name and the same label values)?
|
||||
h := fnv.New64a()
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(metricFamily.GetName())
|
||||
buf.WriteByte(separatorByte)
|
||||
h.Write(buf.Bytes())
|
||||
// Make sure label pairs are sorted. We depend on it for the consistency
|
||||
// check. Label pairs must be sorted by contract. But the point of this
|
||||
// method is to check for contract violations. So we better do the sort
|
||||
// now.
|
||||
sort.Sort(LabelPairSorter(dtoMetric.Label))
|
||||
for _, lp := range dtoMetric.Label {
|
||||
buf.Reset()
|
||||
buf.WriteString(lp.GetValue())
|
||||
buf.WriteByte(separatorByte)
|
||||
h.Write(buf.Bytes())
|
||||
}
|
||||
metricHash := h.Sum64()
|
||||
if _, exists := metricHashes[metricHash]; exists {
|
||||
return fmt.Errorf(
|
||||
"collected metric %s %s was collected before with the same name and label values",
|
||||
metricFamily.GetName(), dtoMetric,
|
||||
)
|
||||
}
|
||||
metricHashes[metricHash] = struct{}{}
|
||||
|
||||
if desc == nil {
|
||||
return nil // Nothing left to check if we have no desc.
|
||||
}
|
||||
|
||||
// Desc consistency with metric family.
|
||||
if metricFamily.GetName() != desc.fqName {
|
||||
return fmt.Errorf(
|
||||
"collected metric %s %s has name %q but should have %q",
|
||||
metricFamily.GetName(), dtoMetric, metricFamily.GetName(), desc.fqName,
|
||||
)
|
||||
}
|
||||
if metricFamily.GetHelp() != desc.help {
|
||||
return fmt.Errorf(
|
||||
"collected metric %s %s has help %q but should have %q",
|
||||
metricFamily.GetName(), dtoMetric, metricFamily.GetHelp(), desc.help,
|
||||
)
|
||||
}
|
||||
|
||||
// Is the desc consistent with the content of the metric?
|
||||
lpsFromDesc := make([]*dto.LabelPair, 0, len(dtoMetric.Label))
|
||||
lpsFromDesc = append(lpsFromDesc, desc.constLabelPairs...)
|
||||
for _, l := range desc.variableLabels {
|
||||
lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{
|
||||
Name: proto.String(l),
|
||||
})
|
||||
}
|
||||
if len(lpsFromDesc) != len(dtoMetric.Label) {
|
||||
return fmt.Errorf(
|
||||
"labels in collected metric %s %s are inconsistent with descriptor %s",
|
||||
metricFamily.GetName(), dtoMetric, desc,
|
||||
)
|
||||
}
|
||||
sort.Sort(LabelPairSorter(lpsFromDesc))
|
||||
for i, lpFromDesc := range lpsFromDesc {
|
||||
lpFromMetric := dtoMetric.Label[i]
|
||||
if lpFromDesc.GetName() != lpFromMetric.GetName() ||
|
||||
lpFromDesc.Value != nil && lpFromDesc.GetValue() != lpFromMetric.GetValue() {
|
||||
return fmt.Errorf(
|
||||
"labels in collected metric %s %s are inconsistent with descriptor %s",
|
||||
metricFamily.GetName(), dtoMetric, desc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
r.mtx.RLock() // Remaining checks need the read lock.
|
||||
defer r.mtx.RUnlock()
|
||||
|
||||
// Is the desc registered?
|
||||
if _, exist := r.descIDs[desc.id]; !exist {
|
||||
return fmt.Errorf(
|
||||
"collected metric %s %s with unregistered descriptor %s",
|
||||
metricFamily.GetName(), dtoMetric, desc,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *registry) getBuf() *bytes.Buffer {
|
||||
select {
|
||||
case buf := <-r.bufPool:
|
||||
return buf
|
||||
default:
|
||||
return &bytes.Buffer{}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *registry) giveBuf(buf *bytes.Buffer) {
|
||||
buf.Reset()
|
||||
select {
|
||||
case r.bufPool <- buf:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (r *registry) getMetricFamily() *dto.MetricFamily {
|
||||
select {
|
||||
case mf := <-r.metricFamilyPool:
|
||||
return mf
|
||||
default:
|
||||
return &dto.MetricFamily{}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *registry) giveMetricFamily(mf *dto.MetricFamily) {
|
||||
mf.Reset()
|
||||
select {
|
||||
case r.metricFamilyPool <- mf:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (r *registry) getMetric() *dto.Metric {
|
||||
select {
|
||||
case m := <-r.metricPool:
|
||||
return m
|
||||
default:
|
||||
return &dto.Metric{}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *registry) giveMetric(m *dto.Metric) {
|
||||
m.Reset()
|
||||
select {
|
||||
case r.metricPool <- m:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func newRegistry() *registry {
|
||||
return ®istry{
|
||||
collectorsByID: map[uint64]Collector{},
|
||||
descIDs: map[uint64]struct{}{},
|
||||
dimHashesByName: map[string]uint64{},
|
||||
bufPool: make(chan *bytes.Buffer, numBufs),
|
||||
metricFamilyPool: make(chan *dto.MetricFamily, numMetricFamilies),
|
||||
metricPool: make(chan *dto.Metric, numMetrics),
|
||||
}
|
||||
}
|
||||
|
||||
func newDefaultRegistry() *registry {
|
||||
r := newRegistry()
|
||||
r.Register(NewProcessCollector(os.Getpid(), ""))
|
||||
r.Register(NewGoCollector())
|
||||
return r
|
||||
}
|
||||
|
||||
// decorateWriter wraps a writer to handle gzip compression if requested. It
|
||||
// returns the decorated writer and the appropriate "Content-Encoding" header
|
||||
// (which is empty if no compression is enabled).
|
||||
func decorateWriter(request *http.Request, writer io.Writer) (io.Writer, string) {
|
||||
header := request.Header.Get(acceptEncodingHeader)
|
||||
parts := strings.Split(header, ",")
|
||||
for _, part := range parts {
|
||||
part := strings.TrimSpace(part)
|
||||
if part == "gzip" || strings.HasPrefix(part, "gzip;") {
|
||||
return gzip.NewWriter(writer), "gzip"
|
||||
}
|
||||
}
|
||||
return writer, ""
|
||||
}
|
||||
|
||||
type metricSorter []*dto.Metric
|
||||
|
||||
func (s metricSorter) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s metricSorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s metricSorter) Less(i, j int) bool {
|
||||
if len(s[i].Label) != len(s[j].Label) {
|
||||
// This should not happen. The metrics are
|
||||
// inconsistent. However, we have to deal with the fact, as
|
||||
// people might use custom collectors or metric family injection
|
||||
// to create inconsistent metrics. So let's simply compare the
|
||||
// number of labels in this case. That will still yield
|
||||
// reproducible sorting.
|
||||
return len(s[i].Label) < len(s[j].Label)
|
||||
}
|
||||
for n, lp := range s[i].Label {
|
||||
vi := lp.GetValue()
|
||||
vj := s[j].Label[n].GetValue()
|
||||
if vi != vj {
|
||||
return vi < vj
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
535
vendor/github.com/prometheus/client_golang/prometheus/registry_test.go
generated
vendored
Normal file
535
vendor/github.com/prometheus/client_golang/prometheus/registry_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,535 @@
|
|||
// 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.
|
||||
|
||||
// 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 prometheus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
type fakeResponseWriter struct {
|
||||
header http.Header
|
||||
body bytes.Buffer
|
||||
}
|
||||
|
||||
func (r *fakeResponseWriter) Header() http.Header {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *fakeResponseWriter) Write(d []byte) (l int, err error) {
|
||||
return r.body.Write(d)
|
||||
}
|
||||
|
||||
func (r *fakeResponseWriter) WriteHeader(c int) {
|
||||
}
|
||||
|
||||
func testHandler(t testing.TB) {
|
||||
|
||||
metricVec := NewCounterVec(
|
||||
CounterOpts{
|
||||
Name: "name",
|
||||
Help: "docstring",
|
||||
ConstLabels: Labels{"constname": "constvalue"},
|
||||
},
|
||||
[]string{"labelname"},
|
||||
)
|
||||
|
||||
metricVec.WithLabelValues("val1").Inc()
|
||||
metricVec.WithLabelValues("val2").Inc()
|
||||
|
||||
varintBuf := make([]byte, binary.MaxVarintLen32)
|
||||
|
||||
externalMetricFamily := &dto.MetricFamily{
|
||||
Name: proto.String("externalname"),
|
||||
Help: proto.String("externaldocstring"),
|
||||
Type: dto.MetricType_COUNTER.Enum(),
|
||||
Metric: []*dto.Metric{
|
||||
{
|
||||
Label: []*dto.LabelPair{
|
||||
{
|
||||
Name: proto.String("externalconstname"),
|
||||
Value: proto.String("externalconstvalue"),
|
||||
},
|
||||
{
|
||||
Name: proto.String("externallabelname"),
|
||||
Value: proto.String("externalval1"),
|
||||
},
|
||||
},
|
||||
Counter: &dto.Counter{
|
||||
Value: proto.Float64(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
marshaledExternalMetricFamily, err := proto.Marshal(externalMetricFamily)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var externalBuf bytes.Buffer
|
||||
l := binary.PutUvarint(varintBuf, uint64(len(marshaledExternalMetricFamily)))
|
||||
_, err = externalBuf.Write(varintBuf[:l])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = externalBuf.Write(marshaledExternalMetricFamily)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
externalMetricFamilyAsBytes := externalBuf.Bytes()
|
||||
externalMetricFamilyAsText := []byte(`# HELP externalname externaldocstring
|
||||
# TYPE externalname counter
|
||||
externalname{externalconstname="externalconstvalue",externallabelname="externalval1"} 1
|
||||
`)
|
||||
externalMetricFamilyAsProtoText := []byte(`name: "externalname"
|
||||
help: "externaldocstring"
|
||||
type: COUNTER
|
||||
metric: <
|
||||
label: <
|
||||
name: "externalconstname"
|
||||
value: "externalconstvalue"
|
||||
>
|
||||
label: <
|
||||
name: "externallabelname"
|
||||
value: "externalval1"
|
||||
>
|
||||
counter: <
|
||||
value: 1
|
||||
>
|
||||
>
|
||||
|
||||
`)
|
||||
externalMetricFamilyAsProtoCompactText := []byte(`name:"externalname" help:"externaldocstring" type:COUNTER metric:<label:<name:"externalconstname" value:"externalconstvalue" > label:<name:"externallabelname" value:"externalval1" > counter:<value:1 > >
|
||||
`)
|
||||
|
||||
expectedMetricFamily := &dto.MetricFamily{
|
||||
Name: proto.String("name"),
|
||||
Help: proto.String("docstring"),
|
||||
Type: dto.MetricType_COUNTER.Enum(),
|
||||
Metric: []*dto.Metric{
|
||||
{
|
||||
Label: []*dto.LabelPair{
|
||||
{
|
||||
Name: proto.String("constname"),
|
||||
Value: proto.String("constvalue"),
|
||||
},
|
||||
{
|
||||
Name: proto.String("labelname"),
|
||||
Value: proto.String("val1"),
|
||||
},
|
||||
},
|
||||
Counter: &dto.Counter{
|
||||
Value: proto.Float64(1),
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: []*dto.LabelPair{
|
||||
{
|
||||
Name: proto.String("constname"),
|
||||
Value: proto.String("constvalue"),
|
||||
},
|
||||
{
|
||||
Name: proto.String("labelname"),
|
||||
Value: proto.String("val2"),
|
||||
},
|
||||
},
|
||||
Counter: &dto.Counter{
|
||||
Value: proto.Float64(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
marshaledExpectedMetricFamily, err := proto.Marshal(expectedMetricFamily)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
l = binary.PutUvarint(varintBuf, uint64(len(marshaledExpectedMetricFamily)))
|
||||
_, err = buf.Write(varintBuf[:l])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = buf.Write(marshaledExpectedMetricFamily)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedMetricFamilyAsBytes := buf.Bytes()
|
||||
expectedMetricFamilyAsText := []byte(`# HELP name docstring
|
||||
# TYPE name counter
|
||||
name{constname="constvalue",labelname="val1"} 1
|
||||
name{constname="constvalue",labelname="val2"} 1
|
||||
`)
|
||||
expectedMetricFamilyAsProtoText := []byte(`name: "name"
|
||||
help: "docstring"
|
||||
type: COUNTER
|
||||
metric: <
|
||||
label: <
|
||||
name: "constname"
|
||||
value: "constvalue"
|
||||
>
|
||||
label: <
|
||||
name: "labelname"
|
||||
value: "val1"
|
||||
>
|
||||
counter: <
|
||||
value: 1
|
||||
>
|
||||
>
|
||||
metric: <
|
||||
label: <
|
||||
name: "constname"
|
||||
value: "constvalue"
|
||||
>
|
||||
label: <
|
||||
name: "labelname"
|
||||
value: "val2"
|
||||
>
|
||||
counter: <
|
||||
value: 1
|
||||
>
|
||||
>
|
||||
|
||||
`)
|
||||
expectedMetricFamilyAsProtoCompactText := []byte(`name:"name" help:"docstring" type:COUNTER metric:<label:<name:"constname" value:"constvalue" > label:<name:"labelname" value:"val1" > counter:<value:1 > > metric:<label:<name:"constname" value:"constvalue" > label:<name:"labelname" value:"val2" > counter:<value:1 > >
|
||||
`)
|
||||
|
||||
externalMetricFamilyWithSameName := &dto.MetricFamily{
|
||||
Name: proto.String("name"),
|
||||
Help: proto.String("inconsistent help string does not matter here"),
|
||||
Type: dto.MetricType_COUNTER.Enum(),
|
||||
Metric: []*dto.Metric{
|
||||
{
|
||||
Label: []*dto.LabelPair{
|
||||
{
|
||||
Name: proto.String("constname"),
|
||||
Value: proto.String("constvalue"),
|
||||
},
|
||||
{
|
||||
Name: proto.String("labelname"),
|
||||
Value: proto.String("different_val"),
|
||||
},
|
||||
},
|
||||
Counter: &dto.Counter{
|
||||
Value: proto.Float64(42),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expectedMetricFamilyMergedWithExternalAsProtoCompactText := []byte(`name:"name" help:"docstring" type:COUNTER metric:<label:<name:"constname" value:"constvalue" > label:<name:"labelname" value:"different_val" > counter:<value:42 > > metric:<label:<name:"constname" value:"constvalue" > label:<name:"labelname" value:"val1" > counter:<value:1 > > metric:<label:<name:"constname" value:"constvalue" > label:<name:"labelname" value:"val2" > counter:<value:1 > >
|
||||
`)
|
||||
|
||||
type output struct {
|
||||
headers map[string]string
|
||||
body []byte
|
||||
}
|
||||
|
||||
var scenarios = []struct {
|
||||
headers map[string]string
|
||||
out output
|
||||
collector Collector
|
||||
externalMF []*dto.MetricFamily
|
||||
}{
|
||||
{ // 0
|
||||
headers: map[string]string{
|
||||
"Accept": "foo/bar;q=0.2, dings/bums;q=0.8",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `text/plain; version=0.0.4`,
|
||||
},
|
||||
body: []byte{},
|
||||
},
|
||||
},
|
||||
{ // 1
|
||||
headers: map[string]string{
|
||||
"Accept": "foo/bar;q=0.2, application/quark;q=0.8",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `text/plain; version=0.0.4`,
|
||||
},
|
||||
body: []byte{},
|
||||
},
|
||||
},
|
||||
{ // 2
|
||||
headers: map[string]string{
|
||||
"Accept": "foo/bar;q=0.2, application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=bla;q=0.8",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `text/plain; version=0.0.4`,
|
||||
},
|
||||
body: []byte{},
|
||||
},
|
||||
},
|
||||
{ // 3
|
||||
headers: map[string]string{
|
||||
"Accept": "text/plain;q=0.2, application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited;q=0.8",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`,
|
||||
},
|
||||
body: []byte{},
|
||||
},
|
||||
},
|
||||
{ // 4
|
||||
headers: map[string]string{
|
||||
"Accept": "application/json",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `text/plain; version=0.0.4`,
|
||||
},
|
||||
body: expectedMetricFamilyAsText,
|
||||
},
|
||||
collector: metricVec,
|
||||
},
|
||||
{ // 5
|
||||
headers: map[string]string{
|
||||
"Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`,
|
||||
},
|
||||
body: expectedMetricFamilyAsBytes,
|
||||
},
|
||||
collector: metricVec,
|
||||
},
|
||||
{ // 6
|
||||
headers: map[string]string{
|
||||
"Accept": "application/json",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `text/plain; version=0.0.4`,
|
||||
},
|
||||
body: externalMetricFamilyAsText,
|
||||
},
|
||||
externalMF: []*dto.MetricFamily{externalMetricFamily},
|
||||
},
|
||||
{ // 7
|
||||
headers: map[string]string{
|
||||
"Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`,
|
||||
},
|
||||
body: externalMetricFamilyAsBytes,
|
||||
},
|
||||
externalMF: []*dto.MetricFamily{externalMetricFamily},
|
||||
},
|
||||
{ // 8
|
||||
headers: map[string]string{
|
||||
"Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`,
|
||||
},
|
||||
body: bytes.Join(
|
||||
[][]byte{
|
||||
externalMetricFamilyAsBytes,
|
||||
expectedMetricFamilyAsBytes,
|
||||
},
|
||||
[]byte{},
|
||||
),
|
||||
},
|
||||
collector: metricVec,
|
||||
externalMF: []*dto.MetricFamily{externalMetricFamily},
|
||||
},
|
||||
{ // 9
|
||||
headers: map[string]string{
|
||||
"Accept": "text/plain",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `text/plain; version=0.0.4`,
|
||||
},
|
||||
body: []byte{},
|
||||
},
|
||||
},
|
||||
{ // 10
|
||||
headers: map[string]string{
|
||||
"Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=bla;q=0.2, text/plain;q=0.5",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `text/plain; version=0.0.4`,
|
||||
},
|
||||
body: expectedMetricFamilyAsText,
|
||||
},
|
||||
collector: metricVec,
|
||||
},
|
||||
{ // 11
|
||||
headers: map[string]string{
|
||||
"Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=bla;q=0.2, text/plain;q=0.5;version=0.0.4",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `text/plain; version=0.0.4`,
|
||||
},
|
||||
body: bytes.Join(
|
||||
[][]byte{
|
||||
externalMetricFamilyAsText,
|
||||
expectedMetricFamilyAsText,
|
||||
},
|
||||
[]byte{},
|
||||
),
|
||||
},
|
||||
collector: metricVec,
|
||||
externalMF: []*dto.MetricFamily{externalMetricFamily},
|
||||
},
|
||||
{ // 12
|
||||
headers: map[string]string{
|
||||
"Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited;q=0.2, text/plain;q=0.5;version=0.0.2",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`,
|
||||
},
|
||||
body: bytes.Join(
|
||||
[][]byte{
|
||||
externalMetricFamilyAsBytes,
|
||||
expectedMetricFamilyAsBytes,
|
||||
},
|
||||
[]byte{},
|
||||
),
|
||||
},
|
||||
collector: metricVec,
|
||||
externalMF: []*dto.MetricFamily{externalMetricFamily},
|
||||
},
|
||||
{ // 13
|
||||
headers: map[string]string{
|
||||
"Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=text;q=0.5, application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited;q=0.4",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=text`,
|
||||
},
|
||||
body: bytes.Join(
|
||||
[][]byte{
|
||||
externalMetricFamilyAsProtoText,
|
||||
expectedMetricFamilyAsProtoText,
|
||||
},
|
||||
[]byte{},
|
||||
),
|
||||
},
|
||||
collector: metricVec,
|
||||
externalMF: []*dto.MetricFamily{externalMetricFamily},
|
||||
},
|
||||
{ // 14
|
||||
headers: map[string]string{
|
||||
"Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=compact-text",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=compact-text`,
|
||||
},
|
||||
body: bytes.Join(
|
||||
[][]byte{
|
||||
externalMetricFamilyAsProtoCompactText,
|
||||
expectedMetricFamilyAsProtoCompactText,
|
||||
},
|
||||
[]byte{},
|
||||
),
|
||||
},
|
||||
collector: metricVec,
|
||||
externalMF: []*dto.MetricFamily{externalMetricFamily},
|
||||
},
|
||||
{ // 15
|
||||
headers: map[string]string{
|
||||
"Accept": "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=compact-text",
|
||||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=compact-text`,
|
||||
},
|
||||
body: bytes.Join(
|
||||
[][]byte{
|
||||
externalMetricFamilyAsProtoCompactText,
|
||||
expectedMetricFamilyMergedWithExternalAsProtoCompactText,
|
||||
},
|
||||
[]byte{},
|
||||
),
|
||||
},
|
||||
collector: metricVec,
|
||||
externalMF: []*dto.MetricFamily{
|
||||
externalMetricFamily,
|
||||
externalMetricFamilyWithSameName,
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, scenario := range scenarios {
|
||||
registry := newRegistry()
|
||||
registry.collectChecksEnabled = true
|
||||
|
||||
if scenario.collector != nil {
|
||||
registry.Register(scenario.collector)
|
||||
}
|
||||
if scenario.externalMF != nil {
|
||||
registry.metricFamilyInjectionHook = func() []*dto.MetricFamily {
|
||||
return scenario.externalMF
|
||||
}
|
||||
}
|
||||
writer := &fakeResponseWriter{
|
||||
header: http.Header{},
|
||||
}
|
||||
handler := InstrumentHandler("prometheus", registry)
|
||||
request, _ := http.NewRequest("GET", "/", nil)
|
||||
for key, value := range scenario.headers {
|
||||
request.Header.Add(key, value)
|
||||
}
|
||||
handler(writer, request)
|
||||
|
||||
for key, value := range scenario.out.headers {
|
||||
if writer.Header().Get(key) != value {
|
||||
t.Errorf(
|
||||
"%d. expected %q for header %q, got %q",
|
||||
i, value, key, writer.Header().Get(key),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if !bytes.Equal(scenario.out.body, writer.body.Bytes()) {
|
||||
t.Errorf(
|
||||
"%d. expected %q for body, got %q",
|
||||
i, scenario.out.body, writer.body.Bytes(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
testHandler(t)
|
||||
}
|
||||
|
||||
func BenchmarkHandler(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
testHandler(b)
|
||||
}
|
||||
}
|
||||
540
vendor/github.com/prometheus/client_golang/prometheus/summary.go
generated
vendored
Normal file
540
vendor/github.com/prometheus/client_golang/prometheus/summary.go
generated
vendored
Normal file
|
|
@ -0,0 +1,540 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"math"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/beorn7/perks/quantile"
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
// quantileLabel is used for the label that defines the quantile in a
|
||||
// summary.
|
||||
const quantileLabel = "quantile"
|
||||
|
||||
// A Summary captures individual observations from an event or sample stream and
|
||||
// summarizes them in a manner similar to traditional summary statistics: 1. sum
|
||||
// of observations, 2. observation count, 3. rank estimations.
|
||||
//
|
||||
// A typical use-case is the observation of request latencies. By default, a
|
||||
// Summary provides the median, the 90th and the 99th percentile of the latency
|
||||
// as rank estimations.
|
||||
//
|
||||
// Note that the rank estimations cannot be aggregated in a meaningful way with
|
||||
// the Prometheus query language (i.e. you cannot average or add them). If you
|
||||
// need aggregatable quantiles (e.g. you want the 99th percentile latency of all
|
||||
// queries served across all instances of a service), consider the Histogram
|
||||
// metric type. See the Prometheus documentation for more details.
|
||||
//
|
||||
// To create Summary instances, use NewSummary.
|
||||
type Summary interface {
|
||||
Metric
|
||||
Collector
|
||||
|
||||
// Observe adds a single observation to the summary.
|
||||
Observe(float64)
|
||||
}
|
||||
|
||||
var (
|
||||
// DefObjectives are the default Summary quantile values.
|
||||
DefObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}
|
||||
|
||||
errQuantileLabelNotAllowed = fmt.Errorf(
|
||||
"%q is not allowed as label name in summaries", quantileLabel,
|
||||
)
|
||||
)
|
||||
|
||||
// Default values for SummaryOpts.
|
||||
const (
|
||||
// DefMaxAge is the default duration for which observations stay
|
||||
// relevant.
|
||||
DefMaxAge time.Duration = 10 * time.Minute
|
||||
// DefAgeBuckets is the default number of buckets used to calculate the
|
||||
// age of observations.
|
||||
DefAgeBuckets = 5
|
||||
// DefBufCap is the standard buffer size for collecting Summary observations.
|
||||
DefBufCap = 500
|
||||
)
|
||||
|
||||
// SummaryOpts bundles the options for creating a Summary metric. It is
|
||||
// mandatory to set Name and Help to a non-empty string. All other fields are
|
||||
// optional and can safely be left at their zero value.
|
||||
type SummaryOpts struct {
|
||||
// Namespace, Subsystem, and Name are components of the fully-qualified
|
||||
// name of the Summary (created by joining these components with
|
||||
// "_"). Only Name is mandatory, the others merely help structuring the
|
||||
// name. Note that the fully-qualified name of the Summary must be a
|
||||
// valid Prometheus metric name.
|
||||
Namespace string
|
||||
Subsystem string
|
||||
Name string
|
||||
|
||||
// Help provides information about this Summary. Mandatory!
|
||||
//
|
||||
// Metrics with the same fully-qualified name must have the same Help
|
||||
// string.
|
||||
Help string
|
||||
|
||||
// ConstLabels are used to attach fixed labels to this
|
||||
// Summary. Summaries with the same fully-qualified name must have the
|
||||
// same label names in their ConstLabels.
|
||||
//
|
||||
// Note that in most cases, labels have a value that varies during the
|
||||
// lifetime of a process. Those labels are usually managed with a
|
||||
// SummaryVec. ConstLabels serve only special purposes. One is for the
|
||||
// special case where the value of a label does not change during the
|
||||
// lifetime of a process, e.g. if the revision of the running binary is
|
||||
// put into a label. Another, more advanced purpose is if more than one
|
||||
// Collector needs to collect Summaries with the same fully-qualified
|
||||
// name. In that case, those Summaries must differ in the values of
|
||||
// their ConstLabels. See the Collector examples.
|
||||
//
|
||||
// If the value of a label never changes (not even between binaries),
|
||||
// that label most likely should not be a label at all (but part of the
|
||||
// metric name).
|
||||
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.
|
||||
Objectives map[float64]float64
|
||||
|
||||
// MaxAge defines the duration for which an observation stays relevant
|
||||
// for the summary. Must be positive. The default value is DefMaxAge.
|
||||
MaxAge time.Duration
|
||||
|
||||
// AgeBuckets is the number of buckets used to exclude observations that
|
||||
// are older than MaxAge from the summary. A higher number has a
|
||||
// resource penalty, so only increase it if the higher resolution is
|
||||
// really required. For very high observation rates, you might want to
|
||||
// reduce the number of age buckets. With only one age bucket, you will
|
||||
// effectively see a complete reset of the summary each time MaxAge has
|
||||
// passed. The default value is DefAgeBuckets.
|
||||
AgeBuckets uint32
|
||||
|
||||
// BufCap defines the default sample stream buffer size. The default
|
||||
// value of DefBufCap should suffice for most uses. If there is a need
|
||||
// to increase the value, a multiple of 500 is recommended (because that
|
||||
// is the internal buffer size of the underlying package
|
||||
// "github.com/bmizerany/perks/quantile").
|
||||
BufCap uint32
|
||||
}
|
||||
|
||||
// TODO: Great fuck-up with the sliding-window decay algorithm... The Merge
|
||||
// method of perk/quantile is actually not working as advertised - and it might
|
||||
// be unfixable, as the underlying algorithm is apparently not capable of
|
||||
// merging summaries in the first place. To avoid using Merge, we are currently
|
||||
// adding observations to _each_ age bucket, i.e. the effort to add a sample is
|
||||
// essentially multiplied by the number of age buckets. When rotating age
|
||||
// buckets, we empty the previous head stream. On scrape time, we simply take
|
||||
// the quantiles from the head stream (no merging required). Result: More effort
|
||||
// on observation time, less effort on scrape time, which is exactly the
|
||||
// opposite of what we try to accomplish, but at least the results are correct.
|
||||
//
|
||||
// The quite elegant previous contraption to merge the age buckets efficiently
|
||||
// on scrape time (see code up commit 6b9530d72ea715f0ba612c0120e6e09fbf1d49d0)
|
||||
// can't be used anymore.
|
||||
|
||||
// NewSummary creates a new Summary based on the provided SummaryOpts.
|
||||
func NewSummary(opts SummaryOpts) Summary {
|
||||
return newSummary(
|
||||
NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
nil,
|
||||
opts.ConstLabels,
|
||||
),
|
||||
opts,
|
||||
)
|
||||
}
|
||||
|
||||
func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary {
|
||||
if len(desc.variableLabels) != len(labelValues) {
|
||||
panic(errInconsistentCardinality)
|
||||
}
|
||||
|
||||
for _, n := range desc.variableLabels {
|
||||
if n == quantileLabel {
|
||||
panic(errQuantileLabelNotAllowed)
|
||||
}
|
||||
}
|
||||
for _, lp := range desc.constLabelPairs {
|
||||
if lp.GetName() == quantileLabel {
|
||||
panic(errQuantileLabelNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts.Objectives) == 0 {
|
||||
opts.Objectives = DefObjectives
|
||||
}
|
||||
|
||||
if opts.MaxAge < 0 {
|
||||
panic(fmt.Errorf("illegal max age MaxAge=%v", opts.MaxAge))
|
||||
}
|
||||
if opts.MaxAge == 0 {
|
||||
opts.MaxAge = DefMaxAge
|
||||
}
|
||||
|
||||
if opts.AgeBuckets == 0 {
|
||||
opts.AgeBuckets = DefAgeBuckets
|
||||
}
|
||||
|
||||
if opts.BufCap == 0 {
|
||||
opts.BufCap = DefBufCap
|
||||
}
|
||||
|
||||
s := &summary{
|
||||
desc: desc,
|
||||
|
||||
objectives: opts.Objectives,
|
||||
sortedObjectives: make([]float64, 0, len(opts.Objectives)),
|
||||
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
|
||||
hotBuf: make([]float64, 0, opts.BufCap),
|
||||
coldBuf: make([]float64, 0, opts.BufCap),
|
||||
streamDuration: opts.MaxAge / time.Duration(opts.AgeBuckets),
|
||||
}
|
||||
s.headStreamExpTime = time.Now().Add(s.streamDuration)
|
||||
s.hotBufExpTime = s.headStreamExpTime
|
||||
|
||||
for i := uint32(0); i < opts.AgeBuckets; i++ {
|
||||
s.streams = append(s.streams, s.newStream())
|
||||
}
|
||||
s.headStream = s.streams[0]
|
||||
|
||||
for qu := range s.objectives {
|
||||
s.sortedObjectives = append(s.sortedObjectives, qu)
|
||||
}
|
||||
sort.Float64s(s.sortedObjectives)
|
||||
|
||||
s.Init(s) // Init self-collection.
|
||||
return s
|
||||
}
|
||||
|
||||
type summary struct {
|
||||
SelfCollector
|
||||
|
||||
bufMtx sync.Mutex // Protects hotBuf and hotBufExpTime.
|
||||
mtx sync.Mutex // Protects every other moving part.
|
||||
// Lock bufMtx before mtx if both are needed.
|
||||
|
||||
desc *Desc
|
||||
|
||||
objectives map[float64]float64
|
||||
sortedObjectives []float64
|
||||
|
||||
labelPairs []*dto.LabelPair
|
||||
|
||||
sum float64
|
||||
cnt uint64
|
||||
|
||||
hotBuf, coldBuf []float64
|
||||
|
||||
streams []*quantile.Stream
|
||||
streamDuration time.Duration
|
||||
headStream *quantile.Stream
|
||||
headStreamIdx int
|
||||
headStreamExpTime, hotBufExpTime time.Time
|
||||
}
|
||||
|
||||
func (s *summary) Desc() *Desc {
|
||||
return s.desc
|
||||
}
|
||||
|
||||
func (s *summary) Observe(v float64) {
|
||||
s.bufMtx.Lock()
|
||||
defer s.bufMtx.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
if now.After(s.hotBufExpTime) {
|
||||
s.asyncFlush(now)
|
||||
}
|
||||
s.hotBuf = append(s.hotBuf, v)
|
||||
if len(s.hotBuf) == cap(s.hotBuf) {
|
||||
s.asyncFlush(now)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *summary) Write(out *dto.Metric) error {
|
||||
sum := &dto.Summary{}
|
||||
qs := make([]*dto.Quantile, 0, len(s.objectives))
|
||||
|
||||
s.bufMtx.Lock()
|
||||
s.mtx.Lock()
|
||||
// Swap bufs even if hotBuf is empty to set new hotBufExpTime.
|
||||
s.swapBufs(time.Now())
|
||||
s.bufMtx.Unlock()
|
||||
|
||||
s.flushColdBuf()
|
||||
sum.SampleCount = proto.Uint64(s.cnt)
|
||||
sum.SampleSum = proto.Float64(s.sum)
|
||||
|
||||
for _, rank := range s.sortedObjectives {
|
||||
var q float64
|
||||
if s.headStream.Count() == 0 {
|
||||
q = math.NaN()
|
||||
} else {
|
||||
q = s.headStream.Query(rank)
|
||||
}
|
||||
qs = append(qs, &dto.Quantile{
|
||||
Quantile: proto.Float64(rank),
|
||||
Value: proto.Float64(q),
|
||||
})
|
||||
}
|
||||
|
||||
s.mtx.Unlock()
|
||||
|
||||
if len(qs) > 0 {
|
||||
sort.Sort(quantSort(qs))
|
||||
}
|
||||
sum.Quantile = qs
|
||||
|
||||
out.Summary = sum
|
||||
out.Label = s.labelPairs
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *summary) newStream() *quantile.Stream {
|
||||
return quantile.NewTargeted(s.objectives)
|
||||
}
|
||||
|
||||
// asyncFlush needs bufMtx locked.
|
||||
func (s *summary) asyncFlush(now time.Time) {
|
||||
s.mtx.Lock()
|
||||
s.swapBufs(now)
|
||||
|
||||
// Unblock the original goroutine that was responsible for the mutation
|
||||
// that triggered the compaction. But hold onto the global non-buffer
|
||||
// state mutex until the operation finishes.
|
||||
go func() {
|
||||
s.flushColdBuf()
|
||||
s.mtx.Unlock()
|
||||
}()
|
||||
}
|
||||
|
||||
// rotateStreams needs mtx AND bufMtx locked.
|
||||
func (s *summary) maybeRotateStreams() {
|
||||
for !s.hotBufExpTime.Equal(s.headStreamExpTime) {
|
||||
s.headStream.Reset()
|
||||
s.headStreamIdx++
|
||||
if s.headStreamIdx >= len(s.streams) {
|
||||
s.headStreamIdx = 0
|
||||
}
|
||||
s.headStream = s.streams[s.headStreamIdx]
|
||||
s.headStreamExpTime = s.headStreamExpTime.Add(s.streamDuration)
|
||||
}
|
||||
}
|
||||
|
||||
// flushColdBuf needs mtx locked.
|
||||
func (s *summary) flushColdBuf() {
|
||||
for _, v := range s.coldBuf {
|
||||
for _, stream := range s.streams {
|
||||
stream.Insert(v)
|
||||
}
|
||||
s.cnt++
|
||||
s.sum += v
|
||||
}
|
||||
s.coldBuf = s.coldBuf[0:0]
|
||||
s.maybeRotateStreams()
|
||||
}
|
||||
|
||||
// swapBufs needs mtx AND bufMtx locked, coldBuf must be empty.
|
||||
func (s *summary) swapBufs(now time.Time) {
|
||||
if len(s.coldBuf) != 0 {
|
||||
panic("coldBuf is not empty")
|
||||
}
|
||||
s.hotBuf, s.coldBuf = s.coldBuf, s.hotBuf
|
||||
// hotBuf is now empty and gets new expiration set.
|
||||
for now.After(s.hotBufExpTime) {
|
||||
s.hotBufExpTime = s.hotBufExpTime.Add(s.streamDuration)
|
||||
}
|
||||
}
|
||||
|
||||
type quantSort []*dto.Quantile
|
||||
|
||||
func (s quantSort) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s quantSort) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s quantSort) Less(i, j int) bool {
|
||||
return s[i].GetQuantile() < s[j].GetQuantile()
|
||||
}
|
||||
|
||||
// SummaryVec is a Collector that bundles a set of Summaries that all share the
|
||||
// same Desc, but have different values for their variable labels. This is used
|
||||
// if you want to count the same thing partitioned by various dimensions
|
||||
// (e.g. HTTP request latencies, partitioned by status code and method). Create
|
||||
// instances with NewSummaryVec.
|
||||
type SummaryVec struct {
|
||||
MetricVec
|
||||
}
|
||||
|
||||
// NewSummaryVec creates a new SummaryVec based on the provided SummaryOpts and
|
||||
// partitioned by the given label names. At least one label name must be
|
||||
// provided.
|
||||
func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec {
|
||||
desc := NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
labelNames,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
return &SummaryVec{
|
||||
MetricVec: MetricVec{
|
||||
children: map[uint64]Metric{},
|
||||
desc: desc,
|
||||
hash: fnv.New64a(),
|
||||
newMetric: func(lvs ...string) Metric {
|
||||
return newSummary(desc, opts, lvs...)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||
if metric != nil {
|
||||
return metric.(Summary), 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) {
|
||||
metric, err := m.MetricVec.GetMetricWith(labels)
|
||||
if metric != nil {
|
||||
return metric.(Summary), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
type constSummary struct {
|
||||
desc *Desc
|
||||
count uint64
|
||||
sum float64
|
||||
quantiles map[float64]float64
|
||||
labelPairs []*dto.LabelPair
|
||||
}
|
||||
|
||||
func (s *constSummary) Desc() *Desc {
|
||||
return s.desc
|
||||
}
|
||||
|
||||
func (s *constSummary) Write(out *dto.Metric) error {
|
||||
sum := &dto.Summary{}
|
||||
qs := make([]*dto.Quantile, 0, len(s.quantiles))
|
||||
|
||||
sum.SampleCount = proto.Uint64(s.count)
|
||||
sum.SampleSum = proto.Float64(s.sum)
|
||||
|
||||
for rank, q := range s.quantiles {
|
||||
qs = append(qs, &dto.Quantile{
|
||||
Quantile: proto.Float64(rank),
|
||||
Value: proto.Float64(q),
|
||||
})
|
||||
}
|
||||
|
||||
if len(qs) > 0 {
|
||||
sort.Sort(quantSort(qs))
|
||||
}
|
||||
sum.Quantile = qs
|
||||
|
||||
out.Summary = sum
|
||||
out.Label = s.labelPairs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewConstSummary returns a metric representing a Prometheus summary with fixed
|
||||
// values for the count, sum, and quantiles. As those parameters cannot be
|
||||
// changed, the returned value does not implement the Summary interface (but
|
||||
// only the Metric interface). Users of this package will not have much use for
|
||||
// it in regular operations. However, when implementing custom Collectors, it is
|
||||
// useful as a throw-away metric that is generated on the fly to send it to
|
||||
// Prometheus in the Collect method.
|
||||
//
|
||||
// quantiles maps ranks to quantile values. For example, a median latency of
|
||||
// 0.23s and a 99th percentile latency of 0.56s would be expressed as:
|
||||
// map[float64]float64{0.5: 0.23, 0.99: 0.56}
|
||||
//
|
||||
// NewConstSummary returns an error if the length of labelValues is not
|
||||
// consistent with the variable labels in Desc.
|
||||
func NewConstSummary(
|
||||
desc *Desc,
|
||||
count uint64,
|
||||
sum float64,
|
||||
quantiles map[float64]float64,
|
||||
labelValues ...string,
|
||||
) (Metric, error) {
|
||||
if len(desc.variableLabels) != len(labelValues) {
|
||||
return nil, errInconsistentCardinality
|
||||
}
|
||||
return &constSummary{
|
||||
desc: desc,
|
||||
count: count,
|
||||
sum: sum,
|
||||
quantiles: quantiles,
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MustNewConstSummary is a version of NewConstSummary that panics where
|
||||
// NewConstMetric would have returned an error.
|
||||
func MustNewConstSummary(
|
||||
desc *Desc,
|
||||
count uint64,
|
||||
sum float64,
|
||||
quantiles map[float64]float64,
|
||||
labelValues ...string,
|
||||
) Metric {
|
||||
m, err := NewConstSummary(desc, count, sum, quantiles, labelValues...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
347
vendor/github.com/prometheus/client_golang/prometheus/summary_test.go
generated
vendored
Normal file
347
vendor/github.com/prometheus/client_golang/prometheus/summary_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"sync"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
"time"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
func benchmarkSummaryObserve(w int, b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(w)
|
||||
|
||||
g := new(sync.WaitGroup)
|
||||
g.Add(1)
|
||||
|
||||
s := NewSummary(SummaryOpts{})
|
||||
|
||||
for i := 0; i < w; i++ {
|
||||
go func() {
|
||||
g.Wait()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Observe(float64(i))
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
g.Done()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkSummaryObserve1(b *testing.B) {
|
||||
benchmarkSummaryObserve(1, b)
|
||||
}
|
||||
|
||||
func BenchmarkSummaryObserve2(b *testing.B) {
|
||||
benchmarkSummaryObserve(2, b)
|
||||
}
|
||||
|
||||
func BenchmarkSummaryObserve4(b *testing.B) {
|
||||
benchmarkSummaryObserve(4, b)
|
||||
}
|
||||
|
||||
func BenchmarkSummaryObserve8(b *testing.B) {
|
||||
benchmarkSummaryObserve(8, b)
|
||||
}
|
||||
|
||||
func benchmarkSummaryWrite(w int, b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(w)
|
||||
|
||||
g := new(sync.WaitGroup)
|
||||
g.Add(1)
|
||||
|
||||
s := NewSummary(SummaryOpts{})
|
||||
|
||||
for i := 0; i < 1000000; i++ {
|
||||
s.Observe(float64(i))
|
||||
}
|
||||
|
||||
for j := 0; j < w; j++ {
|
||||
outs := make([]dto.Metric, b.N)
|
||||
|
||||
go func(o []dto.Metric) {
|
||||
g.Wait()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
s.Write(&o[i])
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
}(outs)
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
g.Done()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func BenchmarkSummaryWrite1(b *testing.B) {
|
||||
benchmarkSummaryWrite(1, b)
|
||||
}
|
||||
|
||||
func BenchmarkSummaryWrite2(b *testing.B) {
|
||||
benchmarkSummaryWrite(2, b)
|
||||
}
|
||||
|
||||
func BenchmarkSummaryWrite4(b *testing.B) {
|
||||
benchmarkSummaryWrite(4, b)
|
||||
}
|
||||
|
||||
func BenchmarkSummaryWrite8(b *testing.B) {
|
||||
benchmarkSummaryWrite(8, b)
|
||||
}
|
||||
|
||||
func TestSummaryConcurrency(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping test in short mode.")
|
||||
}
|
||||
|
||||
rand.Seed(42)
|
||||
|
||||
it := func(n uint32) bool {
|
||||
mutations := int(n%1e4 + 1e4)
|
||||
concLevel := int(n%5 + 1)
|
||||
total := mutations * concLevel
|
||||
|
||||
var start, end sync.WaitGroup
|
||||
start.Add(1)
|
||||
end.Add(concLevel)
|
||||
|
||||
sum := NewSummary(SummaryOpts{
|
||||
Name: "test_summary",
|
||||
Help: "helpless",
|
||||
})
|
||||
|
||||
allVars := make([]float64, total)
|
||||
var sampleSum float64
|
||||
for i := 0; i < concLevel; i++ {
|
||||
vals := make([]float64, mutations)
|
||||
for j := 0; j < mutations; j++ {
|
||||
v := rand.NormFloat64()
|
||||
vals[j] = v
|
||||
allVars[i*mutations+j] = v
|
||||
sampleSum += v
|
||||
}
|
||||
|
||||
go func(vals []float64) {
|
||||
start.Wait()
|
||||
for _, v := range vals {
|
||||
sum.Observe(v)
|
||||
}
|
||||
end.Done()
|
||||
}(vals)
|
||||
}
|
||||
sort.Float64s(allVars)
|
||||
start.Done()
|
||||
end.Wait()
|
||||
|
||||
m := &dto.Metric{}
|
||||
sum.Write(m)
|
||||
if got, want := int(*m.Summary.SampleCount), total; got != want {
|
||||
t.Errorf("got sample count %d, want %d", got, want)
|
||||
}
|
||||
if got, want := *m.Summary.SampleSum, sampleSum; math.Abs((got-want)/want) > 0.001 {
|
||||
t.Errorf("got sample sum %f, want %f", got, want)
|
||||
}
|
||||
|
||||
objectives := make([]float64, 0, len(DefObjectives))
|
||||
for qu := range DefObjectives {
|
||||
objectives = append(objectives, qu)
|
||||
}
|
||||
sort.Float64s(objectives)
|
||||
|
||||
for i, wantQ := range objectives {
|
||||
ε := DefObjectives[wantQ]
|
||||
gotQ := *m.Summary.Quantile[i].Quantile
|
||||
gotV := *m.Summary.Quantile[i].Value
|
||||
min, max := getBounds(allVars, wantQ, ε)
|
||||
if gotQ != wantQ {
|
||||
t.Errorf("got quantile %f, want %f", gotQ, wantQ)
|
||||
}
|
||||
if gotV < min || gotV > max {
|
||||
t.Errorf("got %f for quantile %f, want [%f,%f]", gotV, gotQ, min, max)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if err := quick.Check(it, nil); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSummaryVecConcurrency(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping test in short mode.")
|
||||
}
|
||||
|
||||
rand.Seed(42)
|
||||
|
||||
objectives := make([]float64, 0, len(DefObjectives))
|
||||
for qu := range DefObjectives {
|
||||
|
||||
objectives = append(objectives, qu)
|
||||
}
|
||||
sort.Float64s(objectives)
|
||||
|
||||
it := func(n uint32) bool {
|
||||
mutations := int(n%1e4 + 1e4)
|
||||
concLevel := int(n%7 + 1)
|
||||
vecLength := int(n%3 + 1)
|
||||
|
||||
var start, end sync.WaitGroup
|
||||
start.Add(1)
|
||||
end.Add(concLevel)
|
||||
|
||||
sum := NewSummaryVec(
|
||||
SummaryOpts{
|
||||
Name: "test_summary",
|
||||
Help: "helpless",
|
||||
},
|
||||
[]string{"label"},
|
||||
)
|
||||
|
||||
allVars := make([][]float64, vecLength)
|
||||
sampleSums := make([]float64, vecLength)
|
||||
for i := 0; i < concLevel; i++ {
|
||||
vals := make([]float64, mutations)
|
||||
picks := make([]int, mutations)
|
||||
for j := 0; j < mutations; j++ {
|
||||
v := rand.NormFloat64()
|
||||
vals[j] = v
|
||||
pick := rand.Intn(vecLength)
|
||||
picks[j] = pick
|
||||
allVars[pick] = append(allVars[pick], v)
|
||||
sampleSums[pick] += v
|
||||
}
|
||||
|
||||
go func(vals []float64) {
|
||||
start.Wait()
|
||||
for i, v := range vals {
|
||||
sum.WithLabelValues(string('A' + picks[i])).Observe(v)
|
||||
}
|
||||
end.Done()
|
||||
}(vals)
|
||||
}
|
||||
for _, vars := range allVars {
|
||||
sort.Float64s(vars)
|
||||
}
|
||||
start.Done()
|
||||
end.Wait()
|
||||
|
||||
for i := 0; i < vecLength; i++ {
|
||||
m := &dto.Metric{}
|
||||
s := sum.WithLabelValues(string('A' + i))
|
||||
s.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)
|
||||
}
|
||||
if got, want := *m.Summary.SampleSum, sampleSums[i]; math.Abs((got-want)/want) > 0.001 {
|
||||
t.Errorf("got sample sum %f for label %c, want %f", got, 'A'+i, want)
|
||||
}
|
||||
for j, wantQ := range objectives {
|
||||
ε := DefObjectives[wantQ]
|
||||
gotQ := *m.Summary.Quantile[j].Quantile
|
||||
gotV := *m.Summary.Quantile[j].Value
|
||||
min, max := getBounds(allVars[i], wantQ, ε)
|
||||
if gotQ != wantQ {
|
||||
t.Errorf("got quantile %f for label %c, want %f", gotQ, 'A'+i, wantQ)
|
||||
}
|
||||
if gotV < min || gotV > max {
|
||||
t.Errorf("got %f for quantile %f for label %c, want [%f,%f]", gotV, gotQ, 'A'+i, min, max)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if err := quick.Check(it, nil); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSummaryDecay(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping test in short mode.")
|
||||
// More because it depends on timing than because it is particularly long...
|
||||
}
|
||||
|
||||
sum := NewSummary(SummaryOpts{
|
||||
Name: "test_summary",
|
||||
Help: "helpless",
|
||||
MaxAge: 100 * time.Millisecond,
|
||||
Objectives: map[float64]float64{0.1: 0.001},
|
||||
AgeBuckets: 10,
|
||||
})
|
||||
|
||||
m := &dto.Metric{}
|
||||
i := 0
|
||||
tick := time.NewTicker(time.Millisecond)
|
||||
for _ = range tick.C {
|
||||
i++
|
||||
sum.Observe(float64(i))
|
||||
if i%10 == 0 {
|
||||
sum.Write(m)
|
||||
if got, want := *m.Summary.Quantile[0].Value, math.Max(float64(i)/10, float64(i-90)); math.Abs(got-want) > 20 {
|
||||
t.Errorf("%d. got %f, want %f", i, got, want)
|
||||
}
|
||||
m.Reset()
|
||||
}
|
||||
if i >= 1000 {
|
||||
break
|
||||
}
|
||||
}
|
||||
tick.Stop()
|
||||
// Wait for MaxAge without observations and make sure quantiles are NaN.
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
sum.Write(m)
|
||||
if got := *m.Summary.Quantile[0].Value; !math.IsNaN(got) {
|
||||
t.Errorf("got %f, want NaN after expiration", got)
|
||||
}
|
||||
}
|
||||
|
||||
func getBounds(vars []float64, q, ε float64) (min, max float64) {
|
||||
// TODO: This currently tolerates an error of up to 2*ε. The error must
|
||||
// be at most ε, but for some reason, it's sometimes slightly
|
||||
// higher. That's a bug.
|
||||
n := float64(len(vars))
|
||||
lower := int((q - 2*ε) * n)
|
||||
upper := int(math.Ceil((q + 2*ε) * n))
|
||||
min = vars[0]
|
||||
if lower > 1 {
|
||||
min = vars[lower-1]
|
||||
}
|
||||
max = vars[len(vars)-1]
|
||||
if upper < len(vars) {
|
||||
max = vars[upper-1]
|
||||
}
|
||||
return
|
||||
}
|
||||
145
vendor/github.com/prometheus/client_golang/prometheus/untyped.go
generated
vendored
Normal file
145
vendor/github.com/prometheus/client_golang/prometheus/untyped.go
generated
vendored
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
// 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
|
||||
|
||||
import "hash/fnv"
|
||||
|
||||
// Untyped is a Metric that represents a single numerical value that can
|
||||
// arbitrarily go up and down.
|
||||
//
|
||||
// An Untyped metric works the same as a Gauge. The only difference is that to
|
||||
// no type information is implied.
|
||||
//
|
||||
// To create Untyped instances, use NewUntyped.
|
||||
type Untyped interface {
|
||||
Metric
|
||||
Collector
|
||||
|
||||
// Set sets the Untyped metric to an arbitrary value.
|
||||
Set(float64)
|
||||
// Inc increments the Untyped metric by 1.
|
||||
Inc()
|
||||
// Dec decrements the Untyped metric by 1.
|
||||
Dec()
|
||||
// Add adds the given value to the Untyped metric. (The value can be
|
||||
// negative, resulting in a decrease.)
|
||||
Add(float64)
|
||||
// Sub subtracts the given value from the Untyped metric. (The value can
|
||||
// be negative, resulting in an increase.)
|
||||
Sub(float64)
|
||||
}
|
||||
|
||||
// UntypedOpts is an alias for Opts. See there for doc comments.
|
||||
type UntypedOpts Opts
|
||||
|
||||
// NewUntyped creates a new Untyped metric from the provided UntypedOpts.
|
||||
func NewUntyped(opts UntypedOpts) Untyped {
|
||||
return newValue(NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
nil,
|
||||
opts.ConstLabels,
|
||||
), UntypedValue, 0)
|
||||
}
|
||||
|
||||
// UntypedVec is a Collector that bundles a set of Untyped metrics that all
|
||||
// share the same Desc, but have different values for their variable
|
||||
// labels. This is used if you want to count the same thing partitioned by
|
||||
// various dimensions. Create instances with NewUntypedVec.
|
||||
type UntypedVec struct {
|
||||
MetricVec
|
||||
}
|
||||
|
||||
// NewUntypedVec creates a new UntypedVec based on the provided UntypedOpts and
|
||||
// partitioned by the given label names. At least one label name must be
|
||||
// provided.
|
||||
func NewUntypedVec(opts UntypedOpts, labelNames []string) *UntypedVec {
|
||||
desc := NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
labelNames,
|
||||
opts.ConstLabels,
|
||||
)
|
||||
return &UntypedVec{
|
||||
MetricVec: MetricVec{
|
||||
children: map[uint64]Metric{},
|
||||
desc: desc,
|
||||
hash: fnv.New64a(),
|
||||
newMetric: func(lvs ...string) Metric {
|
||||
return newValue(desc, UntypedValue, 0, lvs...)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetMetricWithLabelValues replaces the method of the same name in
|
||||
// MetricVec. The difference is that this method returns an Untyped and not a
|
||||
// Metric so that no type conversion is required.
|
||||
func (m *UntypedVec) GetMetricWithLabelValues(lvs ...string) (Untyped, error) {
|
||||
metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||
if metric != nil {
|
||||
return metric.(Untyped), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetMetricWith replaces the method of the same name in MetricVec. The
|
||||
// difference is that this method returns an Untyped and not a Metric so that no
|
||||
// type conversion is required.
|
||||
func (m *UntypedVec) GetMetricWith(labels Labels) (Untyped, error) {
|
||||
metric, err := m.MetricVec.GetMetricWith(labels)
|
||||
if metric != nil {
|
||||
return metric.(Untyped), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
||||
// GetMetricWithLabelValues would have returned an error. By not returning an
|
||||
// error, WithLabelValues allows shortcuts like
|
||||
// myVec.WithLabelValues("404", "GET").Add(42)
|
||||
func (m *UntypedVec) WithLabelValues(lvs ...string) Untyped {
|
||||
return m.MetricVec.WithLabelValues(lvs...).(Untyped)
|
||||
}
|
||||
|
||||
// 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"}).Add(42)
|
||||
func (m *UntypedVec) With(labels Labels) Untyped {
|
||||
return m.MetricVec.With(labels).(Untyped)
|
||||
}
|
||||
|
||||
// UntypedFunc is an Untyped whose value is determined at collect time by
|
||||
// calling a provided function.
|
||||
//
|
||||
// To create UntypedFunc instances, use NewUntypedFunc.
|
||||
type UntypedFunc interface {
|
||||
Metric
|
||||
Collector
|
||||
}
|
||||
|
||||
// NewUntypedFunc creates a new UntypedFunc based on the provided
|
||||
// UntypedOpts. The value reported is determined by calling the given function
|
||||
// from within the Write method. Take into account that metric collection may
|
||||
// happen concurrently. If that results in concurrent calls to Write, like in
|
||||
// the case where an UntypedFunc is directly registered with Prometheus, the
|
||||
// provided function must be concurrency-safe.
|
||||
func NewUntypedFunc(opts UntypedOpts, function func() float64) UntypedFunc {
|
||||
return newValueFunc(NewDesc(
|
||||
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||
opts.Help,
|
||||
nil,
|
||||
opts.ConstLabels,
|
||||
), UntypedValue, function)
|
||||
}
|
||||
234
vendor/github.com/prometheus/client_golang/prometheus/value.go
generated
vendored
Normal file
234
vendor/github.com/prometheus/client_golang/prometheus/value.go
generated
vendored
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"sync/atomic"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
// ValueType is an enumeration of metric types that represent a simple value.
|
||||
type ValueType int
|
||||
|
||||
// Possible values for the ValueType enum.
|
||||
const (
|
||||
_ ValueType = iota
|
||||
CounterValue
|
||||
GaugeValue
|
||||
UntypedValue
|
||||
)
|
||||
|
||||
var errInconsistentCardinality = errors.New("inconsistent label cardinality")
|
||||
|
||||
// value is a generic metric for simple values. It implements Metric, Collector,
|
||||
// Counter, Gauge, and Untyped. Its effective type is determined by
|
||||
// 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
|
||||
// to go first in the struct to guarantee alignment for atomic
|
||||
// operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG
|
||||
valBits uint64
|
||||
|
||||
SelfCollector
|
||||
|
||||
desc *Desc
|
||||
valType ValueType
|
||||
labelPairs []*dto.LabelPair
|
||||
}
|
||||
|
||||
// newValue returns a newly allocated value with the given Desc, ValueType,
|
||||
// sample value and label values. It panics if the number of label
|
||||
// values is different from the number of variable labels in Desc.
|
||||
func newValue(desc *Desc, valueType ValueType, val float64, labelValues ...string) *value {
|
||||
if len(labelValues) != len(desc.variableLabels) {
|
||||
panic(errInconsistentCardinality)
|
||||
}
|
||||
result := &value{
|
||||
desc: desc,
|
||||
valType: valueType,
|
||||
valBits: math.Float64bits(val),
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
}
|
||||
result.Init(result)
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *value) Desc() *Desc {
|
||||
return v.desc
|
||||
}
|
||||
|
||||
func (v *value) Set(val float64) {
|
||||
atomic.StoreUint64(&v.valBits, math.Float64bits(val))
|
||||
}
|
||||
|
||||
func (v *value) Inc() {
|
||||
v.Add(1)
|
||||
}
|
||||
|
||||
func (v *value) Dec() {
|
||||
v.Add(-1)
|
||||
}
|
||||
|
||||
func (v *value) Add(val float64) {
|
||||
for {
|
||||
oldBits := atomic.LoadUint64(&v.valBits)
|
||||
newBits := math.Float64bits(math.Float64frombits(oldBits) + val)
|
||||
if atomic.CompareAndSwapUint64(&v.valBits, oldBits, newBits) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (v *value) Sub(val float64) {
|
||||
v.Add(val * -1)
|
||||
}
|
||||
|
||||
func (v *value) Write(out *dto.Metric) error {
|
||||
val := math.Float64frombits(atomic.LoadUint64(&v.valBits))
|
||||
return populateMetric(v.valType, val, v.labelPairs, out)
|
||||
}
|
||||
|
||||
// valueFunc is a generic metric for simple values retrieved on collect time
|
||||
// from a function. It implements Metric and Collector. Its effective type is
|
||||
// determined by ValueType. This is a low-level building block used by the
|
||||
// library to back the implementations of CounterFunc, GaugeFunc, and
|
||||
// UntypedFunc.
|
||||
type valueFunc struct {
|
||||
SelfCollector
|
||||
|
||||
desc *Desc
|
||||
valType ValueType
|
||||
function func() float64
|
||||
labelPairs []*dto.LabelPair
|
||||
}
|
||||
|
||||
// newValueFunc returns a newly allocated valueFunc with the given Desc and
|
||||
// ValueType. The value reported is determined by calling the given function
|
||||
// from within the Write method. Take into account that metric collection may
|
||||
// happen concurrently. If that results in concurrent calls to Write, like in
|
||||
// the case where a valueFunc is directly registered with Prometheus, the
|
||||
// provided function must be concurrency-safe.
|
||||
func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *valueFunc {
|
||||
result := &valueFunc{
|
||||
desc: desc,
|
||||
valType: valueType,
|
||||
function: function,
|
||||
labelPairs: makeLabelPairs(desc, nil),
|
||||
}
|
||||
result.Init(result)
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *valueFunc) Desc() *Desc {
|
||||
return v.desc
|
||||
}
|
||||
|
||||
func (v *valueFunc) Write(out *dto.Metric) error {
|
||||
return populateMetric(v.valType, v.function(), v.labelPairs, out)
|
||||
}
|
||||
|
||||
// NewConstMetric returns a metric with one fixed value that cannot be
|
||||
// changed. Users of this package will not have much use for it in regular
|
||||
// operations. However, when implementing custom Collectors, it is useful as a
|
||||
// throw-away metric that is generated on the fly to send it to Prometheus in
|
||||
// the Collect method. NewConstMetric returns an error if the length of
|
||||
// labelValues is not consistent with the variable labels in Desc.
|
||||
func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) {
|
||||
if len(desc.variableLabels) != len(labelValues) {
|
||||
return nil, errInconsistentCardinality
|
||||
}
|
||||
return &constMetric{
|
||||
desc: desc,
|
||||
valType: valueType,
|
||||
val: value,
|
||||
labelPairs: makeLabelPairs(desc, labelValues),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MustNewConstMetric is a version of NewConstMetric that panics where
|
||||
// NewConstMetric would have returned an error.
|
||||
func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) Metric {
|
||||
m, err := NewConstMetric(desc, valueType, value, labelValues...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type constMetric struct {
|
||||
desc *Desc
|
||||
valType ValueType
|
||||
val float64
|
||||
labelPairs []*dto.LabelPair
|
||||
}
|
||||
|
||||
func (m *constMetric) Desc() *Desc {
|
||||
return m.desc
|
||||
}
|
||||
|
||||
func (m *constMetric) Write(out *dto.Metric) error {
|
||||
return populateMetric(m.valType, m.val, m.labelPairs, out)
|
||||
}
|
||||
|
||||
func populateMetric(
|
||||
t ValueType,
|
||||
v float64,
|
||||
labelPairs []*dto.LabelPair,
|
||||
m *dto.Metric,
|
||||
) error {
|
||||
m.Label = labelPairs
|
||||
switch t {
|
||||
case CounterValue:
|
||||
m.Counter = &dto.Counter{Value: proto.Float64(v)}
|
||||
case GaugeValue:
|
||||
m.Gauge = &dto.Gauge{Value: proto.Float64(v)}
|
||||
case UntypedValue:
|
||||
m.Untyped = &dto.Untyped{Value: proto.Float64(v)}
|
||||
default:
|
||||
return fmt.Errorf("encountered unknown type %v", t)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
|
||||
totalLen := len(desc.variableLabels) + len(desc.constLabelPairs)
|
||||
if totalLen == 0 {
|
||||
// Super fast path.
|
||||
return nil
|
||||
}
|
||||
if len(desc.variableLabels) == 0 {
|
||||
// Moderately fast path.
|
||||
return desc.constLabelPairs
|
||||
}
|
||||
labelPairs := make([]*dto.LabelPair, 0, totalLen)
|
||||
for i, n := range desc.variableLabels {
|
||||
labelPairs = append(labelPairs, &dto.LabelPair{
|
||||
Name: proto.String(n),
|
||||
Value: proto.String(labelValues[i]),
|
||||
})
|
||||
}
|
||||
for _, lp := range desc.constLabelPairs {
|
||||
labelPairs = append(labelPairs, lp)
|
||||
}
|
||||
sort.Sort(LabelPairSorter(labelPairs))
|
||||
return labelPairs
|
||||
}
|
||||
247
vendor/github.com/prometheus/client_golang/prometheus/vec.go
generated
vendored
Normal file
247
vendor/github.com/prometheus/client_golang/prometheus/vec.go
generated
vendored
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"hash"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// MetricVec is a Collector to bundle metrics of the same name that
|
||||
// differ in their label values. MetricVec is usually not used directly but as a
|
||||
// building block for implementations of vectors of a given metric
|
||||
// type. GaugeVec, CounterVec, SummaryVec, and UntypedVec are examples already
|
||||
// provided in this package.
|
||||
type MetricVec struct {
|
||||
mtx sync.RWMutex // Protects not only children, but also hash and buf.
|
||||
children map[uint64]Metric
|
||||
desc *Desc
|
||||
|
||||
// hash is our own hash instance to avoid repeated allocations.
|
||||
hash hash.Hash64
|
||||
// buf is used to copy string contents into it for hashing,
|
||||
// again to avoid allocations.
|
||||
buf bytes.Buffer
|
||||
|
||||
newMetric func(labelValues ...string) Metric
|
||||
}
|
||||
|
||||
// Describe implements Collector. The length of the returned slice
|
||||
// is always one.
|
||||
func (m *MetricVec) Describe(ch chan<- *Desc) {
|
||||
ch <- m.desc
|
||||
}
|
||||
|
||||
// Collect implements Collector.
|
||||
func (m *MetricVec) Collect(ch chan<- Metric) {
|
||||
m.mtx.RLock()
|
||||
defer m.mtx.RUnlock()
|
||||
|
||||
for _, metric := range m.children {
|
||||
ch <- metric
|
||||
}
|
||||
}
|
||||
|
||||
// GetMetricWithLabelValues returns the Metric for the given slice of label
|
||||
// values (same order as the VariableLabels in Desc). If that combination of
|
||||
// label values is accessed for the first time, a new Metric is created.
|
||||
//
|
||||
// It is possible to call this method without using the returned Metric to only
|
||||
// create the new Metric but leave it at its start value (e.g. a Summary or
|
||||
// Histogram without any observations). See also the SummaryVec example.
|
||||
//
|
||||
// Keeping the Metric for later use is possible (and should be considered if
|
||||
// performance is critical), but keep in mind that Reset, DeleteLabelValues and
|
||||
// Delete can be used to delete the Metric from the MetricVec. In that case, the
|
||||
// Metric will still exist, but it will not be exported anymore, even if a
|
||||
// Metric with the same label values is created later. See also the CounterVec
|
||||
// example.
|
||||
//
|
||||
// An error is returned if the number of label values is not the same as the
|
||||
// number of VariableLabels in Desc.
|
||||
//
|
||||
// Note that for more than one label value, this method is prone to mistakes
|
||||
// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
|
||||
// an alternative to avoid that type of mistake. For higher label numbers, the
|
||||
// latter has a much more readable (albeit more verbose) syntax, but it comes
|
||||
// with a performance overhead (for creating and processing the Labels map).
|
||||
// See also the GaugeVec example.
|
||||
func (m *MetricVec) GetMetricWithLabelValues(lvs ...string) (Metric, error) {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
|
||||
h, err := m.hashLabelValues(lvs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m.getOrCreateMetric(h, lvs...), nil
|
||||
}
|
||||
|
||||
// GetMetricWith returns the Metric for the given Labels map (the label names
|
||||
// must match those of the VariableLabels in Desc). If that label map is
|
||||
// accessed for the first time, a new Metric is created. Implications of
|
||||
// creating a Metric without using it and keeping the Metric for later use are
|
||||
// the same as for GetMetricWithLabelValues.
|
||||
//
|
||||
// An error is returned if the number and names of the Labels are inconsistent
|
||||
// with those of the VariableLabels in Desc.
|
||||
//
|
||||
// This method is used for the same purpose as
|
||||
// GetMetricWithLabelValues(...string). See there for pros and cons of the two
|
||||
// methods.
|
||||
func (m *MetricVec) GetMetricWith(labels Labels) (Metric, error) {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
|
||||
h, err := m.hashLabels(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lvs := make([]string, len(labels))
|
||||
for i, label := range m.desc.variableLabels {
|
||||
lvs[i] = labels[label]
|
||||
}
|
||||
return m.getOrCreateMetric(h, lvs...), nil
|
||||
}
|
||||
|
||||
// WithLabelValues works as GetMetricWithLabelValues, but panics if an error
|
||||
// occurs. The method allows neat syntax like:
|
||||
// httpReqs.WithLabelValues("404", "POST").Inc()
|
||||
func (m *MetricVec) WithLabelValues(lvs ...string) Metric {
|
||||
metric, err := m.GetMetricWithLabelValues(lvs...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return metric
|
||||
}
|
||||
|
||||
// With works as GetMetricWith, but panics if an error occurs. The method allows
|
||||
// neat syntax like:
|
||||
// httpReqs.With(Labels{"status":"404", "method":"POST"}).Inc()
|
||||
func (m *MetricVec) With(labels Labels) Metric {
|
||||
metric, err := m.GetMetricWith(labels)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return metric
|
||||
}
|
||||
|
||||
// DeleteLabelValues removes the metric where the variable labels are the same
|
||||
// as those passed in as labels (same order as the VariableLabels in Desc). It
|
||||
// returns true if a metric was deleted.
|
||||
//
|
||||
// It is not an error if the number of label values is not the same as the
|
||||
// number of VariableLabels in Desc. However, such inconsistent label count can
|
||||
// never match an actual Metric, so the method will always return false in that
|
||||
// case.
|
||||
//
|
||||
// Note that for more than one label value, this method is prone to mistakes
|
||||
// caused by an incorrect order of arguments. Consider Delete(Labels) as an
|
||||
// alternative to avoid that type of mistake. For higher label numbers, the
|
||||
// latter has a much more readable (albeit more verbose) syntax, but it comes
|
||||
// with a performance overhead (for creating and processing the Labels map).
|
||||
// See also the CounterVec example.
|
||||
func (m *MetricVec) DeleteLabelValues(lvs ...string) bool {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
|
||||
h, err := m.hashLabelValues(lvs)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if _, has := m.children[h]; !has {
|
||||
return false
|
||||
}
|
||||
delete(m.children, h)
|
||||
return true
|
||||
}
|
||||
|
||||
// Delete deletes the metric where the variable labels are the same as those
|
||||
// passed in as labels. It returns true if a metric was deleted.
|
||||
//
|
||||
// It is not an error if the number and names of the Labels are inconsistent
|
||||
// with those of the VariableLabels in the Desc of the MetricVec. However, such
|
||||
// inconsistent Labels can never match an actual Metric, so the method will
|
||||
// always return false in that case.
|
||||
//
|
||||
// This method is used for the same purpose as DeleteLabelValues(...string). See
|
||||
// there for pros and cons of the two methods.
|
||||
func (m *MetricVec) Delete(labels Labels) bool {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
|
||||
h, err := m.hashLabels(labels)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if _, has := m.children[h]; !has {
|
||||
return false
|
||||
}
|
||||
delete(m.children, h)
|
||||
return true
|
||||
}
|
||||
|
||||
// Reset deletes all metrics in this vector.
|
||||
func (m *MetricVec) Reset() {
|
||||
m.mtx.Lock()
|
||||
defer m.mtx.Unlock()
|
||||
|
||||
for h := range m.children {
|
||||
delete(m.children, h)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MetricVec) hashLabelValues(vals []string) (uint64, error) {
|
||||
if len(vals) != len(m.desc.variableLabels) {
|
||||
return 0, errInconsistentCardinality
|
||||
}
|
||||
m.hash.Reset()
|
||||
for _, val := range vals {
|
||||
m.buf.Reset()
|
||||
m.buf.WriteString(val)
|
||||
m.hash.Write(m.buf.Bytes())
|
||||
}
|
||||
return m.hash.Sum64(), nil
|
||||
}
|
||||
|
||||
func (m *MetricVec) hashLabels(labels Labels) (uint64, error) {
|
||||
if len(labels) != len(m.desc.variableLabels) {
|
||||
return 0, errInconsistentCardinality
|
||||
}
|
||||
m.hash.Reset()
|
||||
for _, label := range m.desc.variableLabels {
|
||||
val, ok := labels[label]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("label name %q missing in label map", label)
|
||||
}
|
||||
m.buf.Reset()
|
||||
m.buf.WriteString(val)
|
||||
m.hash.Write(m.buf.Bytes())
|
||||
}
|
||||
return m.hash.Sum64(), nil
|
||||
}
|
||||
|
||||
func (m *MetricVec) getOrCreateMetric(hash uint64, labelValues ...string) Metric {
|
||||
metric, ok := m.children[hash]
|
||||
if !ok {
|
||||
// Copy labelValues. Otherwise, they would be allocated even if we don't go
|
||||
// down this code path.
|
||||
copiedLabelValues := append(make([]string, 0, len(labelValues)), labelValues...)
|
||||
metric = m.newMetric(copiedLabelValues...)
|
||||
m.children[hash] = metric
|
||||
}
|
||||
return metric
|
||||
}
|
||||
91
vendor/github.com/prometheus/client_golang/prometheus/vec_test.go
generated
vendored
Normal file
91
vendor/github.com/prometheus/client_golang/prometheus/vec_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"hash/fnv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
desc := NewDesc("test", "helpless", []string{"l1", "l2"}, nil)
|
||||
vec := MetricVec{
|
||||
children: map[uint64]Metric{},
|
||||
desc: desc,
|
||||
hash: fnv.New64a(),
|
||||
newMetric: func(lvs ...string) Metric {
|
||||
return newValue(desc, UntypedValue, 0, lvs...)
|
||||
},
|
||||
}
|
||||
|
||||
if got, want := vec.Delete(Labels{"l1": "v1", "l2": "v2"}), false; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
|
||||
vec.With(Labels{"l1": "v1", "l2": "v2"}).(Untyped).Set(42)
|
||||
if got, want := vec.Delete(Labels{"l1": "v1", "l2": "v2"}), true; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
if got, want := vec.Delete(Labels{"l1": "v1", "l2": "v2"}), false; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
|
||||
vec.With(Labels{"l1": "v1", "l2": "v2"}).(Untyped).Set(42)
|
||||
if got, want := vec.Delete(Labels{"l2": "v2", "l1": "v1"}), true; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
if got, want := vec.Delete(Labels{"l2": "v2", "l1": "v1"}), false; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
|
||||
vec.With(Labels{"l1": "v1", "l2": "v2"}).(Untyped).Set(42)
|
||||
if got, want := vec.Delete(Labels{"l2": "v1", "l1": "v2"}), false; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
if got, want := vec.Delete(Labels{"l1": "v1"}), false; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteLabelValues(t *testing.T) {
|
||||
desc := NewDesc("test", "helpless", []string{"l1", "l2"}, nil)
|
||||
vec := MetricVec{
|
||||
children: map[uint64]Metric{},
|
||||
desc: desc,
|
||||
hash: fnv.New64a(),
|
||||
newMetric: func(lvs ...string) Metric {
|
||||
return newValue(desc, UntypedValue, 0, lvs...)
|
||||
},
|
||||
}
|
||||
|
||||
if got, want := vec.DeleteLabelValues("v1", "v2"), false; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
|
||||
vec.With(Labels{"l1": "v1", "l2": "v2"}).(Untyped).Set(42)
|
||||
if got, want := vec.DeleteLabelValues("v1", "v2"), true; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
if got, want := vec.DeleteLabelValues("v1", "v2"), false; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
|
||||
vec.With(Labels{"l1": "v1", "l2": "v2"}).(Untyped).Set(42)
|
||||
if got, want := vec.DeleteLabelValues("v2", "v1"), false; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
if got, want := vec.DeleteLabelValues("v1"), false; got != want {
|
||||
t.Errorf("got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
1
vendor/github.com/prometheus/client_model/.gitignore
generated
vendored
Normal file
1
vendor/github.com/prometheus/client_model/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
target/
|
||||
13
vendor/github.com/prometheus/client_model/AUTHORS.md
generated
vendored
Normal file
13
vendor/github.com/prometheus/client_model/AUTHORS.md
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
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):
|
||||
|
||||
* Björn Rabenstein <beorn@soundcloud.com>
|
||||
* Matt T. Proud <matt.proud@gmail.com>
|
||||
* Tobias Schmidt <ts@soundcloud.com>
|
||||
18
vendor/github.com/prometheus/client_model/CONTRIBUTING.md
generated
vendored
Normal file
18
vendor/github.com/prometheus/client_model/CONTRIBUTING.md
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Contributing
|
||||
|
||||
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 plan to do something more involved, first discuss your ideas
|
||||
on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers).
|
||||
This will avoid unnecessary work and surely give you and us a good deal
|
||||
of inspiration.
|
||||
|
||||
* Relevant coding style guidelines for the Go parts are the [Go Code Review
|
||||
Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments)
|
||||
and the _Formatting and style_ section of Peter Bourgon's [Go: Best
|
||||
Practices for Production
|
||||
Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style).
|
||||
201
vendor/github.com/prometheus/client_model/LICENSE
generated
vendored
Normal file
201
vendor/github.com/prometheus/client_model/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
61
vendor/github.com/prometheus/client_model/Makefile
generated
vendored
Normal file
61
vendor/github.com/prometheus/client_model/Makefile
generated
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# Copyright 2013 Prometheus Team
|
||||
# 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.
|
||||
|
||||
KEY_ID ?= _DEFINE_ME_
|
||||
|
||||
all: cpp go java python ruby
|
||||
|
||||
SUFFIXES:
|
||||
|
||||
cpp: cpp/metrics.pb.cc cpp/metrics.pb.h
|
||||
|
||||
cpp/metrics.pb.cc: metrics.proto
|
||||
protoc $< --cpp_out=cpp/
|
||||
|
||||
cpp/metrics.pb.h: metrics.proto
|
||||
protoc $< --cpp_out=cpp/
|
||||
|
||||
go: go/metrics.pb.go
|
||||
|
||||
go/metrics.pb.go: metrics.proto
|
||||
protoc $< --go_out=go/
|
||||
|
||||
java: src/main/java/io/prometheus/client/Metrics.java pom.xml
|
||||
mvn clean compile package
|
||||
|
||||
src/main/java/io/prometheus/client/Metrics.java: metrics.proto
|
||||
protoc $< --java_out=src/main/java
|
||||
|
||||
python: python/prometheus/client/model/metrics_pb2.py
|
||||
|
||||
python/prometheus/client/model/metrics_pb2.py: metrics.proto
|
||||
protoc $< --python_out=python/prometheus/client/model
|
||||
|
||||
ruby:
|
||||
$(MAKE) -C ruby build
|
||||
|
||||
clean:
|
||||
-rm -rf cpp/*
|
||||
-rm -rf go/*
|
||||
-rm -rf java/*
|
||||
-rm -rf python/*
|
||||
-$(MAKE) -C ruby clean
|
||||
-mvn clean
|
||||
|
||||
maven-deploy-snapshot: java
|
||||
mvn clean deploy -Dgpg.keyname=$(KEY_ID) -DperformRelease=true
|
||||
|
||||
maven-deploy-release: java
|
||||
mvn clean release:clean release:prepare release:perform -Dgpg.keyname=$(KEY_ID) -DperformRelease=true
|
||||
|
||||
.PHONY: all clean cpp go java maven-deploy-snapshot maven-deploy-release python ruby
|
||||
5
vendor/github.com/prometheus/client_model/NOTICE
generated
vendored
Normal file
5
vendor/github.com/prometheus/client_model/NOTICE
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Data model artifacts for Prometheus.
|
||||
Copyright 2012-2015 The Prometheus Authors
|
||||
|
||||
This product includes software developed at
|
||||
SoundCloud Ltd. (http://soundcloud.com/).
|
||||
26
vendor/github.com/prometheus/client_model/README.md
generated
vendored
Normal file
26
vendor/github.com/prometheus/client_model/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Background
|
||||
Under most circumstances, manually downloading this repository should never
|
||||
be required.
|
||||
|
||||
# Prerequisites
|
||||
# Base
|
||||
* [Google Protocol Buffers](https://developers.google.com/protocol-buffers)
|
||||
|
||||
## Java
|
||||
* [Apache Maven](http://maven.apache.org)
|
||||
* [Prometheus Maven Repository](https://github.com/prometheus/io.prometheus-maven-repository) checked out into ../io.prometheus-maven-repository
|
||||
|
||||
## Go
|
||||
* [Go](http://golang.org)
|
||||
* [goprotobuf](https://code.google.com/p/goprotobuf)
|
||||
|
||||
## Ruby
|
||||
* [Ruby](https://www.ruby-lang.org)
|
||||
* [bundler](https://rubygems.org/gems/bundler)
|
||||
|
||||
# Building
|
||||
$ make
|
||||
|
||||
# Getting Started
|
||||
* The Go source code is periodically indexed: [Go Protocol Buffer Model](http://godoc.org/github.com/prometheus/client_model/go).
|
||||
* All of the core developers are accessible via the [Prometheus Developers Mailinglist](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers).
|
||||
3380
vendor/github.com/prometheus/client_model/cpp/metrics.pb.cc
generated
vendored
Normal file
3380
vendor/github.com/prometheus/client_model/cpp/metrics.pb.cc
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
2072
vendor/github.com/prometheus/client_model/cpp/metrics.pb.h
generated
vendored
Normal file
2072
vendor/github.com/prometheus/client_model/cpp/metrics.pb.h
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
364
vendor/github.com/prometheus/client_model/go/metrics.pb.go
generated
vendored
Normal file
364
vendor/github.com/prometheus/client_model/go/metrics.pb.go
generated
vendored
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
// Code generated by protoc-gen-go.
|
||||
// source: metrics.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package io_prometheus_client is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
metrics.proto
|
||||
|
||||
It has these top-level messages:
|
||||
LabelPair
|
||||
Gauge
|
||||
Counter
|
||||
Quantile
|
||||
Summary
|
||||
Untyped
|
||||
Histogram
|
||||
Bucket
|
||||
Metric
|
||||
MetricFamily
|
||||
*/
|
||||
package io_prometheus_client
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = math.Inf
|
||||
|
||||
type MetricType int32
|
||||
|
||||
const (
|
||||
MetricType_COUNTER MetricType = 0
|
||||
MetricType_GAUGE MetricType = 1
|
||||
MetricType_SUMMARY MetricType = 2
|
||||
MetricType_UNTYPED MetricType = 3
|
||||
MetricType_HISTOGRAM MetricType = 4
|
||||
)
|
||||
|
||||
var MetricType_name = map[int32]string{
|
||||
0: "COUNTER",
|
||||
1: "GAUGE",
|
||||
2: "SUMMARY",
|
||||
3: "UNTYPED",
|
||||
4: "HISTOGRAM",
|
||||
}
|
||||
var MetricType_value = map[string]int32{
|
||||
"COUNTER": 0,
|
||||
"GAUGE": 1,
|
||||
"SUMMARY": 2,
|
||||
"UNTYPED": 3,
|
||||
"HISTOGRAM": 4,
|
||||
}
|
||||
|
||||
func (x MetricType) Enum() *MetricType {
|
||||
p := new(MetricType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
func (x MetricType) String() string {
|
||||
return proto.EnumName(MetricType_name, int32(x))
|
||||
}
|
||||
func (x *MetricType) UnmarshalJSON(data []byte) error {
|
||||
value, err := proto.UnmarshalJSONEnum(MetricType_value, data, "MetricType")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*x = MetricType(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
type LabelPair struct {
|
||||
Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
|
||||
Value *string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *LabelPair) Reset() { *m = LabelPair{} }
|
||||
func (m *LabelPair) String() string { return proto.CompactTextString(m) }
|
||||
func (*LabelPair) ProtoMessage() {}
|
||||
|
||||
func (m *LabelPair) GetName() string {
|
||||
if m != nil && m.Name != nil {
|
||||
return *m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *LabelPair) GetValue() string {
|
||||
if m != nil && m.Value != nil {
|
||||
return *m.Value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Gauge struct {
|
||||
Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Gauge) Reset() { *m = Gauge{} }
|
||||
func (m *Gauge) String() string { return proto.CompactTextString(m) }
|
||||
func (*Gauge) ProtoMessage() {}
|
||||
|
||||
func (m *Gauge) GetValue() float64 {
|
||||
if m != nil && m.Value != nil {
|
||||
return *m.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Counter struct {
|
||||
Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Counter) Reset() { *m = Counter{} }
|
||||
func (m *Counter) String() string { return proto.CompactTextString(m) }
|
||||
func (*Counter) ProtoMessage() {}
|
||||
|
||||
func (m *Counter) GetValue() float64 {
|
||||
if m != nil && m.Value != nil {
|
||||
return *m.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Quantile struct {
|
||||
Quantile *float64 `protobuf:"fixed64,1,opt,name=quantile" json:"quantile,omitempty"`
|
||||
Value *float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Quantile) Reset() { *m = Quantile{} }
|
||||
func (m *Quantile) String() string { return proto.CompactTextString(m) }
|
||||
func (*Quantile) ProtoMessage() {}
|
||||
|
||||
func (m *Quantile) GetQuantile() float64 {
|
||||
if m != nil && m.Quantile != nil {
|
||||
return *m.Quantile
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Quantile) GetValue() float64 {
|
||||
if m != nil && m.Value != nil {
|
||||
return *m.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Summary struct {
|
||||
SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count" json:"sample_count,omitempty"`
|
||||
SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum" json:"sample_sum,omitempty"`
|
||||
Quantile []*Quantile `protobuf:"bytes,3,rep,name=quantile" json:"quantile,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Summary) Reset() { *m = Summary{} }
|
||||
func (m *Summary) String() string { return proto.CompactTextString(m) }
|
||||
func (*Summary) ProtoMessage() {}
|
||||
|
||||
func (m *Summary) GetSampleCount() uint64 {
|
||||
if m != nil && m.SampleCount != nil {
|
||||
return *m.SampleCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Summary) GetSampleSum() float64 {
|
||||
if m != nil && m.SampleSum != nil {
|
||||
return *m.SampleSum
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Summary) GetQuantile() []*Quantile {
|
||||
if m != nil {
|
||||
return m.Quantile
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Untyped struct {
|
||||
Value *float64 `protobuf:"fixed64,1,opt,name=value" json:"value,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Untyped) Reset() { *m = Untyped{} }
|
||||
func (m *Untyped) String() string { return proto.CompactTextString(m) }
|
||||
func (*Untyped) ProtoMessage() {}
|
||||
|
||||
func (m *Untyped) GetValue() float64 {
|
||||
if m != nil && m.Value != nil {
|
||||
return *m.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Histogram struct {
|
||||
SampleCount *uint64 `protobuf:"varint,1,opt,name=sample_count" json:"sample_count,omitempty"`
|
||||
SampleSum *float64 `protobuf:"fixed64,2,opt,name=sample_sum" json:"sample_sum,omitempty"`
|
||||
Bucket []*Bucket `protobuf:"bytes,3,rep,name=bucket" json:"bucket,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Histogram) Reset() { *m = Histogram{} }
|
||||
func (m *Histogram) String() string { return proto.CompactTextString(m) }
|
||||
func (*Histogram) ProtoMessage() {}
|
||||
|
||||
func (m *Histogram) GetSampleCount() uint64 {
|
||||
if m != nil && m.SampleCount != nil {
|
||||
return *m.SampleCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Histogram) GetSampleSum() float64 {
|
||||
if m != nil && m.SampleSum != nil {
|
||||
return *m.SampleSum
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Histogram) GetBucket() []*Bucket {
|
||||
if m != nil {
|
||||
return m.Bucket
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Bucket struct {
|
||||
CumulativeCount *uint64 `protobuf:"varint,1,opt,name=cumulative_count" json:"cumulative_count,omitempty"`
|
||||
UpperBound *float64 `protobuf:"fixed64,2,opt,name=upper_bound" json:"upper_bound,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Bucket) Reset() { *m = Bucket{} }
|
||||
func (m *Bucket) String() string { return proto.CompactTextString(m) }
|
||||
func (*Bucket) ProtoMessage() {}
|
||||
|
||||
func (m *Bucket) GetCumulativeCount() uint64 {
|
||||
if m != nil && m.CumulativeCount != nil {
|
||||
return *m.CumulativeCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Bucket) GetUpperBound() float64 {
|
||||
if m != nil && m.UpperBound != nil {
|
||||
return *m.UpperBound
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Metric struct {
|
||||
Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"`
|
||||
Gauge *Gauge `protobuf:"bytes,2,opt,name=gauge" json:"gauge,omitempty"`
|
||||
Counter *Counter `protobuf:"bytes,3,opt,name=counter" json:"counter,omitempty"`
|
||||
Summary *Summary `protobuf:"bytes,4,opt,name=summary" json:"summary,omitempty"`
|
||||
Untyped *Untyped `protobuf:"bytes,5,opt,name=untyped" json:"untyped,omitempty"`
|
||||
Histogram *Histogram `protobuf:"bytes,7,opt,name=histogram" json:"histogram,omitempty"`
|
||||
TimestampMs *int64 `protobuf:"varint,6,opt,name=timestamp_ms" json:"timestamp_ms,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Metric) Reset() { *m = Metric{} }
|
||||
func (m *Metric) String() string { return proto.CompactTextString(m) }
|
||||
func (*Metric) ProtoMessage() {}
|
||||
|
||||
func (m *Metric) GetLabel() []*LabelPair {
|
||||
if m != nil {
|
||||
return m.Label
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Metric) GetGauge() *Gauge {
|
||||
if m != nil {
|
||||
return m.Gauge
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Metric) GetCounter() *Counter {
|
||||
if m != nil {
|
||||
return m.Counter
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Metric) GetSummary() *Summary {
|
||||
if m != nil {
|
||||
return m.Summary
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Metric) GetUntyped() *Untyped {
|
||||
if m != nil {
|
||||
return m.Untyped
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Metric) GetHistogram() *Histogram {
|
||||
if m != nil {
|
||||
return m.Histogram
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Metric) GetTimestampMs() int64 {
|
||||
if m != nil && m.TimestampMs != nil {
|
||||
return *m.TimestampMs
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type MetricFamily struct {
|
||||
Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
|
||||
Help *string `protobuf:"bytes,2,opt,name=help" json:"help,omitempty"`
|
||||
Type *MetricType `protobuf:"varint,3,opt,name=type,enum=io.prometheus.client.MetricType" json:"type,omitempty"`
|
||||
Metric []*Metric `protobuf:"bytes,4,rep,name=metric" json:"metric,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *MetricFamily) Reset() { *m = MetricFamily{} }
|
||||
func (m *MetricFamily) String() string { return proto.CompactTextString(m) }
|
||||
func (*MetricFamily) ProtoMessage() {}
|
||||
|
||||
func (m *MetricFamily) GetName() string {
|
||||
if m != nil && m.Name != nil {
|
||||
return *m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *MetricFamily) GetHelp() string {
|
||||
if m != nil && m.Help != nil {
|
||||
return *m.Help
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *MetricFamily) GetType() MetricType {
|
||||
if m != nil && m.Type != nil {
|
||||
return *m.Type
|
||||
}
|
||||
return MetricType_COUNTER
|
||||
}
|
||||
|
||||
func (m *MetricFamily) GetMetric() []*Metric {
|
||||
if m != nil {
|
||||
return m.Metric
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("io.prometheus.client.MetricType", MetricType_name, MetricType_value)
|
||||
}
|
||||
81
vendor/github.com/prometheus/client_model/metrics.proto
generated
vendored
Normal file
81
vendor/github.com/prometheus/client_model/metrics.proto
generated
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2013 Prometheus Team
|
||||
// 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.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package io.prometheus.client;
|
||||
option java_package = "io.prometheus.client";
|
||||
|
||||
message LabelPair {
|
||||
optional string name = 1;
|
||||
optional string value = 2;
|
||||
}
|
||||
|
||||
enum MetricType {
|
||||
COUNTER = 0;
|
||||
GAUGE = 1;
|
||||
SUMMARY = 2;
|
||||
UNTYPED = 3;
|
||||
HISTOGRAM = 4;
|
||||
}
|
||||
|
||||
message Gauge {
|
||||
optional double value = 1;
|
||||
}
|
||||
|
||||
message Counter {
|
||||
optional double value = 1;
|
||||
}
|
||||
|
||||
message Quantile {
|
||||
optional double quantile = 1;
|
||||
optional double value = 2;
|
||||
}
|
||||
|
||||
message Summary {
|
||||
optional uint64 sample_count = 1;
|
||||
optional double sample_sum = 2;
|
||||
repeated Quantile quantile = 3;
|
||||
}
|
||||
|
||||
message Untyped {
|
||||
optional double value = 1;
|
||||
}
|
||||
|
||||
message Histogram {
|
||||
optional uint64 sample_count = 1;
|
||||
optional double sample_sum = 2;
|
||||
repeated Bucket bucket = 3; // Ordered in increasing order of upper_bound, +Inf bucket is optional.
|
||||
}
|
||||
|
||||
message Bucket {
|
||||
optional uint64 cumulative_count = 1; // Cumulative in increasing order.
|
||||
optional double upper_bound = 2; // Inclusive.
|
||||
}
|
||||
|
||||
message Metric {
|
||||
repeated LabelPair label = 1;
|
||||
optional Gauge gauge = 2;
|
||||
optional Counter counter = 3;
|
||||
optional Summary summary = 4;
|
||||
optional Untyped untyped = 5;
|
||||
optional Histogram histogram = 7;
|
||||
optional int64 timestamp_ms = 6;
|
||||
}
|
||||
|
||||
message MetricFamily {
|
||||
optional string name = 1;
|
||||
optional string help = 2;
|
||||
optional MetricType type = 3;
|
||||
repeated Metric metric = 4;
|
||||
}
|
||||
130
vendor/github.com/prometheus/client_model/pom.xml
generated
vendored
Normal file
130
vendor/github.com/prometheus/client_model/pom.xml
generated
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>io.prometheus.client</groupId>
|
||||
<artifactId>model</artifactId>
|
||||
<version>0.0.3-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.sonatype.oss</groupId>
|
||||
<artifactId>oss-parent</artifactId>
|
||||
<version>7</version>
|
||||
</parent>
|
||||
|
||||
<name>Prometheus Client Data Model</name>
|
||||
<url>http://github.com/prometheus/client_model</url>
|
||||
<description>
|
||||
Prometheus Client Data Model: Generated Protocol Buffer Assets
|
||||
</description>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:prometheus/client_model.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:prometheus/client_model.git</developerConnection>
|
||||
<url>git@github.com:prometheus/client_model.git</url>
|
||||
</scm>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>mtp</id>
|
||||
<name>Matt T. Proud</name>
|
||||
<email>matt.proud@gmail.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<version>2.5.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.8</version>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
<docencoding>UTF-8</docencoding>
|
||||
<linksource>true</linksource>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-javadoc-site-report</id>
|
||||
<phase>site</phase>
|
||||
<goals>
|
||||
<goal>javadoc</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
<version>3.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release-sign-artifacts</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>performRelease</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
12
vendor/github.com/prometheus/client_model/python/prometheus/__init__.py
generated
vendored
Normal file
12
vendor/github.com/prometheus/client_model/python/prometheus/__init__.py
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Copyright 2013 Prometheus Team
|
||||
# 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.
|
||||
12
vendor/github.com/prometheus/client_model/python/prometheus/client/__init__.py
generated
vendored
Normal file
12
vendor/github.com/prometheus/client_model/python/prometheus/client/__init__.py
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Copyright 2013 Prometheus Team
|
||||
# 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.
|
||||
14
vendor/github.com/prometheus/client_model/python/prometheus/client/model/__init__.py
generated
vendored
Normal file
14
vendor/github.com/prometheus/client_model/python/prometheus/client/model/__init__.py
generated
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Copyright 2013 Prometheus Team
|
||||
# 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.
|
||||
|
||||
__all__ = ['metrics_pb2']
|
||||
575
vendor/github.com/prometheus/client_model/python/prometheus/client/model/metrics_pb2.py
generated
vendored
Normal file
575
vendor/github.com/prometheus/client_model/python/prometheus/client/model/metrics_pb2.py
generated
vendored
Normal file
|
|
@ -0,0 +1,575 @@
|
|||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: metrics.proto
|
||||
|
||||
import sys
|
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf import descriptor_pb2
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='metrics.proto',
|
||||
package='io.prometheus.client',
|
||||
serialized_pb=_b('\n\rmetrics.proto\x12\x14io.prometheus.client\"(\n\tLabelPair\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\x16\n\x05Gauge\x12\r\n\x05value\x18\x01 \x01(\x01\"\x18\n\x07\x43ounter\x12\r\n\x05value\x18\x01 \x01(\x01\"+\n\x08Quantile\x12\x10\n\x08quantile\x18\x01 \x01(\x01\x12\r\n\x05value\x18\x02 \x01(\x01\"e\n\x07Summary\x12\x14\n\x0csample_count\x18\x01 \x01(\x04\x12\x12\n\nsample_sum\x18\x02 \x01(\x01\x12\x30\n\x08quantile\x18\x03 \x03(\x0b\x32\x1e.io.prometheus.client.Quantile\"\x18\n\x07Untyped\x12\r\n\x05value\x18\x01 \x01(\x01\"c\n\tHistogram\x12\x14\n\x0csample_count\x18\x01 \x01(\x04\x12\x12\n\nsample_sum\x18\x02 \x01(\x01\x12,\n\x06\x62ucket\x18\x03 \x03(\x0b\x32\x1c.io.prometheus.client.Bucket\"7\n\x06\x42ucket\x12\x18\n\x10\x63umulative_count\x18\x01 \x01(\x04\x12\x13\n\x0bupper_bound\x18\x02 \x01(\x01\"\xbe\x02\n\x06Metric\x12.\n\x05label\x18\x01 \x03(\x0b\x32\x1f.io.prometheus.client.LabelPair\x12*\n\x05gauge\x18\x02 \x01(\x0b\x32\x1b.io.prometheus.client.Gauge\x12.\n\x07\x63ounter\x18\x03 \x01(\x0b\x32\x1d.io.prometheus.client.Counter\x12.\n\x07summary\x18\x04 \x01(\x0b\x32\x1d.io.prometheus.client.Summary\x12.\n\x07untyped\x18\x05 \x01(\x0b\x32\x1d.io.prometheus.client.Untyped\x12\x32\n\thistogram\x18\x07 \x01(\x0b\x32\x1f.io.prometheus.client.Histogram\x12\x14\n\x0ctimestamp_ms\x18\x06 \x01(\x03\"\x88\x01\n\x0cMetricFamily\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04help\x18\x02 \x01(\t\x12.\n\x04type\x18\x03 \x01(\x0e\x32 .io.prometheus.client.MetricType\x12,\n\x06metric\x18\x04 \x03(\x0b\x32\x1c.io.prometheus.client.Metric*M\n\nMetricType\x12\x0b\n\x07\x43OUNTER\x10\x00\x12\t\n\x05GAUGE\x10\x01\x12\x0b\n\x07SUMMARY\x10\x02\x12\x0b\n\x07UNTYPED\x10\x03\x12\r\n\tHISTOGRAM\x10\x04\x42\x16\n\x14io.prometheus.client')
|
||||
)
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
_METRICTYPE = _descriptor.EnumDescriptor(
|
||||
name='MetricType',
|
||||
full_name='io.prometheus.client.MetricType',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='COUNTER', index=0, number=0,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='GAUGE', index=1, number=1,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SUMMARY', index=2, number=2,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UNTYPED', index=3, number=3,
|
||||
options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='HISTOGRAM', index=4, number=4,
|
||||
options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
options=None,
|
||||
serialized_start=923,
|
||||
serialized_end=1000,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_METRICTYPE)
|
||||
|
||||
MetricType = enum_type_wrapper.EnumTypeWrapper(_METRICTYPE)
|
||||
COUNTER = 0
|
||||
GAUGE = 1
|
||||
SUMMARY = 2
|
||||
UNTYPED = 3
|
||||
HISTOGRAM = 4
|
||||
|
||||
|
||||
|
||||
_LABELPAIR = _descriptor.Descriptor(
|
||||
name='LabelPair',
|
||||
full_name='io.prometheus.client.LabelPair',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='name', full_name='io.prometheus.client.LabelPair.name', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value', full_name='io.prometheus.client.LabelPair.value', index=1,
|
||||
number=2, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=39,
|
||||
serialized_end=79,
|
||||
)
|
||||
|
||||
|
||||
_GAUGE = _descriptor.Descriptor(
|
||||
name='Gauge',
|
||||
full_name='io.prometheus.client.Gauge',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value', full_name='io.prometheus.client.Gauge.value', index=0,
|
||||
number=1, type=1, cpp_type=5, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=81,
|
||||
serialized_end=103,
|
||||
)
|
||||
|
||||
|
||||
_COUNTER = _descriptor.Descriptor(
|
||||
name='Counter',
|
||||
full_name='io.prometheus.client.Counter',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value', full_name='io.prometheus.client.Counter.value', index=0,
|
||||
number=1, type=1, cpp_type=5, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=105,
|
||||
serialized_end=129,
|
||||
)
|
||||
|
||||
|
||||
_QUANTILE = _descriptor.Descriptor(
|
||||
name='Quantile',
|
||||
full_name='io.prometheus.client.Quantile',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='quantile', full_name='io.prometheus.client.Quantile.quantile', index=0,
|
||||
number=1, type=1, cpp_type=5, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value', full_name='io.prometheus.client.Quantile.value', index=1,
|
||||
number=2, type=1, cpp_type=5, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=131,
|
||||
serialized_end=174,
|
||||
)
|
||||
|
||||
|
||||
_SUMMARY = _descriptor.Descriptor(
|
||||
name='Summary',
|
||||
full_name='io.prometheus.client.Summary',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='sample_count', full_name='io.prometheus.client.Summary.sample_count', index=0,
|
||||
number=1, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='sample_sum', full_name='io.prometheus.client.Summary.sample_sum', index=1,
|
||||
number=2, type=1, cpp_type=5, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='quantile', full_name='io.prometheus.client.Summary.quantile', index=2,
|
||||
number=3, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=176,
|
||||
serialized_end=277,
|
||||
)
|
||||
|
||||
|
||||
_UNTYPED = _descriptor.Descriptor(
|
||||
name='Untyped',
|
||||
full_name='io.prometheus.client.Untyped',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value', full_name='io.prometheus.client.Untyped.value', index=0,
|
||||
number=1, type=1, cpp_type=5, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=279,
|
||||
serialized_end=303,
|
||||
)
|
||||
|
||||
|
||||
_HISTOGRAM = _descriptor.Descriptor(
|
||||
name='Histogram',
|
||||
full_name='io.prometheus.client.Histogram',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='sample_count', full_name='io.prometheus.client.Histogram.sample_count', index=0,
|
||||
number=1, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='sample_sum', full_name='io.prometheus.client.Histogram.sample_sum', index=1,
|
||||
number=2, type=1, cpp_type=5, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='bucket', full_name='io.prometheus.client.Histogram.bucket', index=2,
|
||||
number=3, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=305,
|
||||
serialized_end=404,
|
||||
)
|
||||
|
||||
|
||||
_BUCKET = _descriptor.Descriptor(
|
||||
name='Bucket',
|
||||
full_name='io.prometheus.client.Bucket',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='cumulative_count', full_name='io.prometheus.client.Bucket.cumulative_count', index=0,
|
||||
number=1, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='upper_bound', full_name='io.prometheus.client.Bucket.upper_bound', index=1,
|
||||
number=2, type=1, cpp_type=5, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=406,
|
||||
serialized_end=461,
|
||||
)
|
||||
|
||||
|
||||
_METRIC = _descriptor.Descriptor(
|
||||
name='Metric',
|
||||
full_name='io.prometheus.client.Metric',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='label', full_name='io.prometheus.client.Metric.label', index=0,
|
||||
number=1, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='gauge', full_name='io.prometheus.client.Metric.gauge', index=1,
|
||||
number=2, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='counter', full_name='io.prometheus.client.Metric.counter', index=2,
|
||||
number=3, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='summary', full_name='io.prometheus.client.Metric.summary', index=3,
|
||||
number=4, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='untyped', full_name='io.prometheus.client.Metric.untyped', index=4,
|
||||
number=5, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='histogram', full_name='io.prometheus.client.Metric.histogram', index=5,
|
||||
number=7, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='timestamp_ms', full_name='io.prometheus.client.Metric.timestamp_ms', index=6,
|
||||
number=6, type=3, cpp_type=2, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=464,
|
||||
serialized_end=782,
|
||||
)
|
||||
|
||||
|
||||
_METRICFAMILY = _descriptor.Descriptor(
|
||||
name='MetricFamily',
|
||||
full_name='io.prometheus.client.MetricFamily',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='name', full_name='io.prometheus.client.MetricFamily.name', index=0,
|
||||
number=1, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='help', full_name='io.prometheus.client.MetricFamily.help', index=1,
|
||||
number=2, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='type', full_name='io.prometheus.client.MetricFamily.type', index=2,
|
||||
number=3, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='metric', full_name='io.prometheus.client.MetricFamily.metric', index=3,
|
||||
number=4, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
options=None),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
options=None,
|
||||
is_extendable=False,
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=785,
|
||||
serialized_end=921,
|
||||
)
|
||||
|
||||
_SUMMARY.fields_by_name['quantile'].message_type = _QUANTILE
|
||||
_HISTOGRAM.fields_by_name['bucket'].message_type = _BUCKET
|
||||
_METRIC.fields_by_name['label'].message_type = _LABELPAIR
|
||||
_METRIC.fields_by_name['gauge'].message_type = _GAUGE
|
||||
_METRIC.fields_by_name['counter'].message_type = _COUNTER
|
||||
_METRIC.fields_by_name['summary'].message_type = _SUMMARY
|
||||
_METRIC.fields_by_name['untyped'].message_type = _UNTYPED
|
||||
_METRIC.fields_by_name['histogram'].message_type = _HISTOGRAM
|
||||
_METRICFAMILY.fields_by_name['type'].enum_type = _METRICTYPE
|
||||
_METRICFAMILY.fields_by_name['metric'].message_type = _METRIC
|
||||
DESCRIPTOR.message_types_by_name['LabelPair'] = _LABELPAIR
|
||||
DESCRIPTOR.message_types_by_name['Gauge'] = _GAUGE
|
||||
DESCRIPTOR.message_types_by_name['Counter'] = _COUNTER
|
||||
DESCRIPTOR.message_types_by_name['Quantile'] = _QUANTILE
|
||||
DESCRIPTOR.message_types_by_name['Summary'] = _SUMMARY
|
||||
DESCRIPTOR.message_types_by_name['Untyped'] = _UNTYPED
|
||||
DESCRIPTOR.message_types_by_name['Histogram'] = _HISTOGRAM
|
||||
DESCRIPTOR.message_types_by_name['Bucket'] = _BUCKET
|
||||
DESCRIPTOR.message_types_by_name['Metric'] = _METRIC
|
||||
DESCRIPTOR.message_types_by_name['MetricFamily'] = _METRICFAMILY
|
||||
DESCRIPTOR.enum_types_by_name['MetricType'] = _METRICTYPE
|
||||
|
||||
LabelPair = _reflection.GeneratedProtocolMessageType('LabelPair', (_message.Message,), dict(
|
||||
DESCRIPTOR = _LABELPAIR,
|
||||
__module__ = 'metrics_pb2'
|
||||
# @@protoc_insertion_point(class_scope:io.prometheus.client.LabelPair)
|
||||
))
|
||||
_sym_db.RegisterMessage(LabelPair)
|
||||
|
||||
Gauge = _reflection.GeneratedProtocolMessageType('Gauge', (_message.Message,), dict(
|
||||
DESCRIPTOR = _GAUGE,
|
||||
__module__ = 'metrics_pb2'
|
||||
# @@protoc_insertion_point(class_scope:io.prometheus.client.Gauge)
|
||||
))
|
||||
_sym_db.RegisterMessage(Gauge)
|
||||
|
||||
Counter = _reflection.GeneratedProtocolMessageType('Counter', (_message.Message,), dict(
|
||||
DESCRIPTOR = _COUNTER,
|
||||
__module__ = 'metrics_pb2'
|
||||
# @@protoc_insertion_point(class_scope:io.prometheus.client.Counter)
|
||||
))
|
||||
_sym_db.RegisterMessage(Counter)
|
||||
|
||||
Quantile = _reflection.GeneratedProtocolMessageType('Quantile', (_message.Message,), dict(
|
||||
DESCRIPTOR = _QUANTILE,
|
||||
__module__ = 'metrics_pb2'
|
||||
# @@protoc_insertion_point(class_scope:io.prometheus.client.Quantile)
|
||||
))
|
||||
_sym_db.RegisterMessage(Quantile)
|
||||
|
||||
Summary = _reflection.GeneratedProtocolMessageType('Summary', (_message.Message,), dict(
|
||||
DESCRIPTOR = _SUMMARY,
|
||||
__module__ = 'metrics_pb2'
|
||||
# @@protoc_insertion_point(class_scope:io.prometheus.client.Summary)
|
||||
))
|
||||
_sym_db.RegisterMessage(Summary)
|
||||
|
||||
Untyped = _reflection.GeneratedProtocolMessageType('Untyped', (_message.Message,), dict(
|
||||
DESCRIPTOR = _UNTYPED,
|
||||
__module__ = 'metrics_pb2'
|
||||
# @@protoc_insertion_point(class_scope:io.prometheus.client.Untyped)
|
||||
))
|
||||
_sym_db.RegisterMessage(Untyped)
|
||||
|
||||
Histogram = _reflection.GeneratedProtocolMessageType('Histogram', (_message.Message,), dict(
|
||||
DESCRIPTOR = _HISTOGRAM,
|
||||
__module__ = 'metrics_pb2'
|
||||
# @@protoc_insertion_point(class_scope:io.prometheus.client.Histogram)
|
||||
))
|
||||
_sym_db.RegisterMessage(Histogram)
|
||||
|
||||
Bucket = _reflection.GeneratedProtocolMessageType('Bucket', (_message.Message,), dict(
|
||||
DESCRIPTOR = _BUCKET,
|
||||
__module__ = 'metrics_pb2'
|
||||
# @@protoc_insertion_point(class_scope:io.prometheus.client.Bucket)
|
||||
))
|
||||
_sym_db.RegisterMessage(Bucket)
|
||||
|
||||
Metric = _reflection.GeneratedProtocolMessageType('Metric', (_message.Message,), dict(
|
||||
DESCRIPTOR = _METRIC,
|
||||
__module__ = 'metrics_pb2'
|
||||
# @@protoc_insertion_point(class_scope:io.prometheus.client.Metric)
|
||||
))
|
||||
_sym_db.RegisterMessage(Metric)
|
||||
|
||||
MetricFamily = _reflection.GeneratedProtocolMessageType('MetricFamily', (_message.Message,), dict(
|
||||
DESCRIPTOR = _METRICFAMILY,
|
||||
__module__ = 'metrics_pb2'
|
||||
# @@protoc_insertion_point(class_scope:io.prometheus.client.MetricFamily)
|
||||
))
|
||||
_sym_db.RegisterMessage(MetricFamily)
|
||||
|
||||
|
||||
DESCRIPTOR.has_options = True
|
||||
DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\024io.prometheus.client'))
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
5
vendor/github.com/prometheus/client_model/ruby/.gitignore
generated
vendored
Normal file
5
vendor/github.com/prometheus/client_model/ruby/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
*.gem
|
||||
.bundle
|
||||
Gemfile.lock
|
||||
pkg
|
||||
vendor/bundle
|
||||
4
vendor/github.com/prometheus/client_model/ruby/Gemfile
generated
vendored
Normal file
4
vendor/github.com/prometheus/client_model/ruby/Gemfile
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in prometheus-client-model.gemspec
|
||||
gemspec
|
||||
201
vendor/github.com/prometheus/client_model/ruby/LICENSE
generated
vendored
Normal file
201
vendor/github.com/prometheus/client_model/ruby/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
17
vendor/github.com/prometheus/client_model/ruby/Makefile
generated
vendored
Normal file
17
vendor/github.com/prometheus/client_model/ruby/Makefile
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
VENDOR_BUNDLE = vendor/bundle
|
||||
|
||||
build: $(VENDOR_BUNDLE)/.bundled
|
||||
BEEFCAKE_NAMESPACE=Prometheus::Client protoc --beefcake_out lib/prometheus/client/model -I .. ../metrics.proto
|
||||
|
||||
$(VENDOR_BUNDLE):
|
||||
mkdir -p $@
|
||||
|
||||
$(VENDOR_BUNDLE)/.bundled: $(VENDOR_BUNDLE) Gemfile
|
||||
bundle install --quiet --path $<
|
||||
@touch $@
|
||||
|
||||
clean:
|
||||
-rm -f lib/prometheus/client/model/metrics.pb.rb
|
||||
-rm -rf $(VENDOR_BUNDLE)
|
||||
|
||||
.PHONY: build clean
|
||||
31
vendor/github.com/prometheus/client_model/ruby/README.md
generated
vendored
Normal file
31
vendor/github.com/prometheus/client_model/ruby/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Prometheus Ruby client model
|
||||
|
||||
Data model artifacts for the [Prometheus Ruby client][1].
|
||||
|
||||
## Installation
|
||||
|
||||
gem install prometheus-client-model
|
||||
|
||||
## Usage
|
||||
|
||||
Build the artifacts from the protobuf specification:
|
||||
|
||||
make build
|
||||
|
||||
While this Gem's main purpose is to define the Prometheus data types for the
|
||||
[client][1], it's possible to use it without the client to decode a stream of
|
||||
delimited protobuf messages:
|
||||
|
||||
```ruby
|
||||
require 'open-uri'
|
||||
require 'prometheus/client/model'
|
||||
|
||||
CONTENT_TYPE = 'application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited'
|
||||
|
||||
stream = open('http://localhost:9090/metrics', 'Accept' => CONTENT_TYPE).read
|
||||
while family = Prometheus::Client::MetricFamily.read_delimited(stream)
|
||||
puts family
|
||||
end
|
||||
```
|
||||
|
||||
[1]: https://github.com/prometheus/client_ruby
|
||||
1
vendor/github.com/prometheus/client_model/ruby/Rakefile
generated
vendored
Normal file
1
vendor/github.com/prometheus/client_model/ruby/Rakefile
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
require "bundler/gem_tasks"
|
||||
2
vendor/github.com/prometheus/client_model/ruby/lib/prometheus/client/model.rb
generated
vendored
Normal file
2
vendor/github.com/prometheus/client_model/ruby/lib/prometheus/client/model.rb
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
require 'prometheus/client/model/metrics.pb'
|
||||
require 'prometheus/client/model/version'
|
||||
111
vendor/github.com/prometheus/client_model/ruby/lib/prometheus/client/model/metrics.pb.rb
generated
vendored
Normal file
111
vendor/github.com/prometheus/client_model/ruby/lib/prometheus/client/model/metrics.pb.rb
generated
vendored
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
## Generated from metrics.proto for io.prometheus.client
|
||||
require "beefcake"
|
||||
|
||||
module Prometheus
|
||||
module Client
|
||||
|
||||
module MetricType
|
||||
COUNTER = 0
|
||||
GAUGE = 1
|
||||
SUMMARY = 2
|
||||
UNTYPED = 3
|
||||
HISTOGRAM = 4
|
||||
end
|
||||
|
||||
class LabelPair
|
||||
include Beefcake::Message
|
||||
end
|
||||
|
||||
class Gauge
|
||||
include Beefcake::Message
|
||||
end
|
||||
|
||||
class Counter
|
||||
include Beefcake::Message
|
||||
end
|
||||
|
||||
class Quantile
|
||||
include Beefcake::Message
|
||||
end
|
||||
|
||||
class Summary
|
||||
include Beefcake::Message
|
||||
end
|
||||
|
||||
class Untyped
|
||||
include Beefcake::Message
|
||||
end
|
||||
|
||||
class Histogram
|
||||
include Beefcake::Message
|
||||
end
|
||||
|
||||
class Bucket
|
||||
include Beefcake::Message
|
||||
end
|
||||
|
||||
class Metric
|
||||
include Beefcake::Message
|
||||
end
|
||||
|
||||
class MetricFamily
|
||||
include Beefcake::Message
|
||||
end
|
||||
|
||||
class LabelPair
|
||||
optional :name, :string, 1
|
||||
optional :value, :string, 2
|
||||
end
|
||||
|
||||
class Gauge
|
||||
optional :value, :double, 1
|
||||
end
|
||||
|
||||
class Counter
|
||||
optional :value, :double, 1
|
||||
end
|
||||
|
||||
class Quantile
|
||||
optional :quantile, :double, 1
|
||||
optional :value, :double, 2
|
||||
end
|
||||
|
||||
class Summary
|
||||
optional :sample_count, :uint64, 1
|
||||
optional :sample_sum, :double, 2
|
||||
repeated :quantile, Quantile, 3
|
||||
end
|
||||
|
||||
class Untyped
|
||||
optional :value, :double, 1
|
||||
end
|
||||
|
||||
class Histogram
|
||||
optional :sample_count, :uint64, 1
|
||||
optional :sample_sum, :double, 2
|
||||
repeated :bucket, Bucket, 3
|
||||
end
|
||||
|
||||
class Bucket
|
||||
optional :cumulative_count, :uint64, 1
|
||||
optional :upper_bound, :double, 2
|
||||
end
|
||||
|
||||
class Metric
|
||||
repeated :label, LabelPair, 1
|
||||
optional :gauge, Gauge, 2
|
||||
optional :counter, Counter, 3
|
||||
optional :summary, Summary, 4
|
||||
optional :untyped, Untyped, 5
|
||||
optional :histogram, Histogram, 7
|
||||
optional :timestamp_ms, :int64, 6
|
||||
end
|
||||
|
||||
class MetricFamily
|
||||
optional :name, :string, 1
|
||||
optional :help, :string, 2
|
||||
optional :type, MetricType, 3
|
||||
repeated :metric, Metric, 4
|
||||
end
|
||||
end
|
||||
end
|
||||
7
vendor/github.com/prometheus/client_model/ruby/lib/prometheus/client/model/version.rb
generated
vendored
Normal file
7
vendor/github.com/prometheus/client_model/ruby/lib/prometheus/client/model/version.rb
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
module Prometheus
|
||||
module Client
|
||||
module Model
|
||||
VERSION = '0.1.0'
|
||||
end
|
||||
end
|
||||
end
|
||||
22
vendor/github.com/prometheus/client_model/ruby/prometheus-client-model.gemspec
generated
vendored
Normal file
22
vendor/github.com/prometheus/client_model/ruby/prometheus-client-model.gemspec
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# coding: utf-8
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'prometheus/client/model/version'
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = 'prometheus-client-model'
|
||||
spec.version = Prometheus::Client::Model::VERSION
|
||||
spec.authors = ['Tobias Schmidt']
|
||||
spec.email = ['tobidt@gmail.com']
|
||||
spec.summary = 'Data model artifacts for the Prometheus Ruby client'
|
||||
spec.homepage = 'https://github.com/prometheus/client_model/tree/master/ruby'
|
||||
spec.license = 'Apache 2.0'
|
||||
|
||||
spec.files = %w[README.md LICENSE] + Dir.glob('{lib/**/*}')
|
||||
spec.require_paths = ['lib']
|
||||
|
||||
spec.add_dependency 'beefcake', '>= 0.4.0'
|
||||
|
||||
spec.add_development_dependency 'bundler', '~> 1.3'
|
||||
spec.add_development_dependency 'rake'
|
||||
end
|
||||
23
vendor/github.com/prometheus/client_model/setup.py
generated
vendored
Normal file
23
vendor/github.com/prometheus/client_model/setup.py
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name = 'prometheus_client_model',
|
||||
version = '0.0.1',
|
||||
author = 'Matt T. Proud',
|
||||
author_email = 'matt.proud@gmail.com',
|
||||
description = 'Data model artifacts for the Prometheus client.',
|
||||
license = 'Apache License 2.0',
|
||||
url = 'http://github.com/prometheus/client_model',
|
||||
packages = ['prometheus', 'prometheus/client', 'prometheus/client/model'],
|
||||
package_dir = {'': 'python'},
|
||||
requires = ['protobuf(==2.4.1)'],
|
||||
platforms = 'Platform Independent',
|
||||
classifiers = ['Development Status :: 3 - Alpha',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: System Administrators',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: OS Independent',
|
||||
'Topic :: Software Development :: Testing',
|
||||
'Topic :: System :: Monitoring'])
|
||||
7683
vendor/github.com/prometheus/client_model/src/main/java/io/prometheus/client/Metrics.java
generated
vendored
Normal file
7683
vendor/github.com/prometheus/client_model/src/main/java/io/prometheus/client/Metrics.java
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
7
vendor/github.com/prometheus/common/.travis.yml
generated
vendored
Normal file
7
vendor/github.com/prometheus/common/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
sudo: false
|
||||
|
||||
language: go
|
||||
go:
|
||||
- 1.4.3
|
||||
- 1.5.1
|
||||
- tip
|
||||
11
vendor/github.com/prometheus/common/AUTHORS.md
generated
vendored
Normal file
11
vendor/github.com/prometheus/common/AUTHORS.md
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Maintainers of this repository:
|
||||
|
||||
* Fabian Reinartz <fabian@soundcloud.com>
|
||||
|
||||
The following individuals have contributed code to this repository
|
||||
(listed in alphabetical order):
|
||||
|
||||
* Björn Rabenstein <beorn@soundcloud.com>
|
||||
* Fabian Reinartz <fabian@soundcloud.com>
|
||||
* Julius Volz <julius@soundcloud.com>
|
||||
* Miguel Molina <hi@mvader.me>
|
||||
18
vendor/github.com/prometheus/common/CONTRIBUTING.md
generated
vendored
Normal file
18
vendor/github.com/prometheus/common/CONTRIBUTING.md
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Contributing
|
||||
|
||||
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 plan to do something more involved, first discuss your ideas
|
||||
on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers).
|
||||
This will avoid unnecessary work and surely give you and us a good deal
|
||||
of inspiration.
|
||||
|
||||
* Relevant coding style guidelines are the [Go Code Review
|
||||
Comments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments)
|
||||
and the _Formatting and style_ section of Peter Bourgon's [Go: Best
|
||||
Practices for Production
|
||||
Environments](http://peter.bourgon.org/go-in-production/#formatting-and-style).
|
||||
201
vendor/github.com/prometheus/common/LICENSE
generated
vendored
Normal file
201
vendor/github.com/prometheus/common/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
5
vendor/github.com/prometheus/common/NOTICE
generated
vendored
Normal file
5
vendor/github.com/prometheus/common/NOTICE
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Common libraries shared by Prometheus Go components.
|
||||
Copyright 2015 The Prometheus Authors
|
||||
|
||||
This product includes software developed at
|
||||
SoundCloud Ltd. (http://soundcloud.com/).
|
||||
8
vendor/github.com/prometheus/common/README.md
generated
vendored
Normal file
8
vendor/github.com/prometheus/common/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Common
|
||||
[](https://travis-ci.org/prometheus/common)
|
||||
|
||||
This repository contains Go libraries that are shared across Prometheus
|
||||
components and libraries.
|
||||
|
||||
* **model**: Shared data structures
|
||||
* **expfmt**: Decoding and encoding for the exposition format
|
||||
171
vendor/github.com/prometheus/common/expfmt/bench_test.go
generated
vendored
Normal file
171
vendor/github.com/prometheus/common/expfmt/bench_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
// 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.
|
||||
|
||||
package expfmt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
var parser TextParser
|
||||
|
||||
// Benchmarks to show how much penalty text format parsing actually inflicts.
|
||||
//
|
||||
// Example results on Linux 3.13.0, Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz, go1.4.
|
||||
//
|
||||
// BenchmarkParseText 1000 1188535 ns/op 205085 B/op 6135 allocs/op
|
||||
// BenchmarkParseTextGzip 1000 1376567 ns/op 246224 B/op 6151 allocs/op
|
||||
// BenchmarkParseProto 10000 172790 ns/op 52258 B/op 1160 allocs/op
|
||||
// BenchmarkParseProtoGzip 5000 324021 ns/op 94931 B/op 1211 allocs/op
|
||||
// BenchmarkParseProtoMap 10000 187946 ns/op 58714 B/op 1203 allocs/op
|
||||
//
|
||||
// CONCLUSION: The overhead for the map is negligible. Text format needs ~5x more allocations.
|
||||
// Without compression, it needs ~7x longer, but with compression (the more relevant scenario),
|
||||
// the difference becomes less relevant, only ~4x.
|
||||
//
|
||||
// The test data contains 248 samples.
|
||||
//
|
||||
// BenchmarkProcessor002ParseOnly in the extraction package is not quite
|
||||
// comparable to the benchmarks here, but it gives an idea: JSON parsing is even
|
||||
// slower than text parsing and needs a comparable amount of allocs.
|
||||
|
||||
// BenchmarkParseText benchmarks the parsing of a text-format scrape into metric
|
||||
// family DTOs.
|
||||
func BenchmarkParseText(b *testing.B) {
|
||||
b.StopTimer()
|
||||
data, err := ioutil.ReadFile("testdata/text")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := parser.TextToMetricFamilies(bytes.NewReader(data)); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkParseTextGzip benchmarks the parsing of a gzipped text-format scrape
|
||||
// into metric family DTOs.
|
||||
func BenchmarkParseTextGzip(b *testing.B) {
|
||||
b.StopTimer()
|
||||
data, err := ioutil.ReadFile("testdata/text.gz")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
in, err := gzip.NewReader(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if _, err := parser.TextToMetricFamilies(in); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkParseProto benchmarks the parsing of a protobuf-format scrape into
|
||||
// metric family DTOs. Note that this does not build a map of metric families
|
||||
// (as the text version does), because it is not required for Prometheus
|
||||
// ingestion either. (However, it is required for the text-format parsing, as
|
||||
// the metric family might be sprinkled all over the text, while the
|
||||
// protobuf-format guarantees bundling at one place.)
|
||||
func BenchmarkParseProto(b *testing.B) {
|
||||
b.StopTimer()
|
||||
data, err := ioutil.ReadFile("testdata/protobuf")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
family := &dto.MetricFamily{}
|
||||
in := bytes.NewReader(data)
|
||||
for {
|
||||
family.Reset()
|
||||
if _, err := pbutil.ReadDelimited(in, family); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkParseProtoGzip is like BenchmarkParseProto above, but parses gzipped
|
||||
// protobuf format.
|
||||
func BenchmarkParseProtoGzip(b *testing.B) {
|
||||
b.StopTimer()
|
||||
data, err := ioutil.ReadFile("testdata/protobuf.gz")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
family := &dto.MetricFamily{}
|
||||
in, err := gzip.NewReader(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
for {
|
||||
family.Reset()
|
||||
if _, err := pbutil.ReadDelimited(in, family); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkParseProtoMap is like BenchmarkParseProto but DOES put the parsed
|
||||
// metric family DTOs into a map. This is not happening during Prometheus
|
||||
// ingestion. It is just here to measure the overhead of that map creation and
|
||||
// separate it from the overhead of the text format parsing.
|
||||
func BenchmarkParseProtoMap(b *testing.B) {
|
||||
b.StopTimer()
|
||||
data, err := ioutil.ReadFile("testdata/protobuf")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
families := map[string]*dto.MetricFamily{}
|
||||
in := bytes.NewReader(data)
|
||||
for {
|
||||
family := &dto.MetricFamily{}
|
||||
if _, err := pbutil.ReadDelimited(in, family); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
b.Fatal(err)
|
||||
}
|
||||
families[family.GetName()] = family
|
||||
}
|
||||
}
|
||||
}
|
||||
411
vendor/github.com/prometheus/common/expfmt/decode.go
generated
vendored
Normal file
411
vendor/github.com/prometheus/common/expfmt/decode.go
generated
vendored
Normal file
|
|
@ -0,0 +1,411 @@
|
|||
// 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.
|
||||
|
||||
package expfmt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"mime"
|
||||
"net/http"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
// Decoder types decode an input stream into metric families.
|
||||
type Decoder interface {
|
||||
Decode(*dto.MetricFamily) error
|
||||
}
|
||||
|
||||
type DecodeOptions struct {
|
||||
// Timestamp is added to each value from the stream that has no explicit timestamp set.
|
||||
Timestamp model.Time
|
||||
}
|
||||
|
||||
// ResponseFormat extracts the correct format from a HTTP response header.
|
||||
// If no matching format can be found FormatUnknown is returned.
|
||||
func ResponseFormat(h http.Header) Format {
|
||||
ct := h.Get(hdrContentType)
|
||||
|
||||
mediatype, params, err := mime.ParseMediaType(ct)
|
||||
if err != nil {
|
||||
return FmtUnknown
|
||||
}
|
||||
|
||||
const (
|
||||
textType = "text/plain"
|
||||
jsonType = "application/json"
|
||||
)
|
||||
|
||||
switch mediatype {
|
||||
case ProtoType:
|
||||
if p, ok := params["proto"]; ok && p != ProtoProtocol {
|
||||
return FmtUnknown
|
||||
}
|
||||
if e, ok := params["encoding"]; ok && e != "delimited" {
|
||||
return FmtUnknown
|
||||
}
|
||||
return FmtProtoDelim
|
||||
|
||||
case textType:
|
||||
if v, ok := params["version"]; ok && v != TextVersion {
|
||||
return FmtUnknown
|
||||
}
|
||||
return FmtText
|
||||
|
||||
case jsonType:
|
||||
var prometheusAPIVersion string
|
||||
|
||||
if params["schema"] == "prometheus/telemetry" && params["version"] != "" {
|
||||
prometheusAPIVersion = params["version"]
|
||||
} else {
|
||||
prometheusAPIVersion = h.Get("X-Prometheus-API-Version")
|
||||
}
|
||||
|
||||
switch prometheusAPIVersion {
|
||||
case "0.0.2", "":
|
||||
return fmtJSON2
|
||||
default:
|
||||
return FmtUnknown
|
||||
}
|
||||
}
|
||||
|
||||
return FmtUnknown
|
||||
}
|
||||
|
||||
// NewDecoder returns a new decoder based on the given input format.
|
||||
// If the input format does not imply otherwise, a text format decoder is returned.
|
||||
func NewDecoder(r io.Reader, format Format) Decoder {
|
||||
switch format {
|
||||
case FmtProtoDelim:
|
||||
return &protoDecoder{r: r}
|
||||
case fmtJSON2:
|
||||
return newJSON2Decoder(r)
|
||||
}
|
||||
return &textDecoder{r: r}
|
||||
}
|
||||
|
||||
// protoDecoder implements the Decoder interface for protocol buffers.
|
||||
type protoDecoder struct {
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
// Decode implements the Decoder interface.
|
||||
func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
|
||||
_, err := pbutil.ReadDelimited(d.r, v)
|
||||
return err
|
||||
}
|
||||
|
||||
// textDecoder implements the Decoder interface for the text protcol.
|
||||
type textDecoder struct {
|
||||
r io.Reader
|
||||
p TextParser
|
||||
fams []*dto.MetricFamily
|
||||
}
|
||||
|
||||
// Decode implements the Decoder interface.
|
||||
func (d *textDecoder) Decode(v *dto.MetricFamily) error {
|
||||
// TODO(fabxc): Wrap this as a line reader to make streaming safer.
|
||||
if len(d.fams) == 0 {
|
||||
// No cached metric families, read everything and parse metrics.
|
||||
fams, err := d.p.TextToMetricFamilies(d.r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(fams) == 0 {
|
||||
return io.EOF
|
||||
}
|
||||
d.fams = make([]*dto.MetricFamily, 0, len(fams))
|
||||
for _, f := range fams {
|
||||
d.fams = append(d.fams, f)
|
||||
}
|
||||
}
|
||||
|
||||
*v = *d.fams[0]
|
||||
d.fams = d.fams[1:]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type SampleDecoder struct {
|
||||
Dec Decoder
|
||||
Opts *DecodeOptions
|
||||
|
||||
f dto.MetricFamily
|
||||
}
|
||||
|
||||
func (sd *SampleDecoder) Decode(s *model.Vector) error {
|
||||
if err := sd.Dec.Decode(&sd.f); err != nil {
|
||||
return err
|
||||
}
|
||||
*s = extractSamples(&sd.f, sd.Opts)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Extract samples builds a slice of samples from the provided metric families.
|
||||
func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) model.Vector {
|
||||
var all model.Vector
|
||||
for _, f := range fams {
|
||||
all = append(all, extractSamples(f, o)...)
|
||||
}
|
||||
return all
|
||||
}
|
||||
|
||||
func extractSamples(f *dto.MetricFamily, o *DecodeOptions) model.Vector {
|
||||
switch f.GetType() {
|
||||
case dto.MetricType_COUNTER:
|
||||
return extractCounter(o, f)
|
||||
case dto.MetricType_GAUGE:
|
||||
return extractGauge(o, f)
|
||||
case dto.MetricType_SUMMARY:
|
||||
return extractSummary(o, f)
|
||||
case dto.MetricType_UNTYPED:
|
||||
return extractUntyped(o, f)
|
||||
case dto.MetricType_HISTOGRAM:
|
||||
return extractHistogram(o, f)
|
||||
}
|
||||
panic("expfmt.extractSamples: unknown metric family type")
|
||||
}
|
||||
|
||||
func extractCounter(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
|
||||
samples := make(model.Vector, 0, len(f.Metric))
|
||||
|
||||
for _, m := range f.Metric {
|
||||
if m.Counter == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
lset := make(model.LabelSet, len(m.Label)+1)
|
||||
for _, p := range m.Label {
|
||||
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||
}
|
||||
lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
||||
|
||||
smpl := &model.Sample{
|
||||
Metric: model.Metric(lset),
|
||||
Value: model.SampleValue(m.Counter.GetValue()),
|
||||
}
|
||||
|
||||
if m.TimestampMs != nil {
|
||||
smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
|
||||
} else {
|
||||
smpl.Timestamp = o.Timestamp
|
||||
}
|
||||
|
||||
samples = append(samples, smpl)
|
||||
}
|
||||
|
||||
return samples
|
||||
}
|
||||
|
||||
func extractGauge(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
|
||||
samples := make(model.Vector, 0, len(f.Metric))
|
||||
|
||||
for _, m := range f.Metric {
|
||||
if m.Gauge == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
lset := make(model.LabelSet, len(m.Label)+1)
|
||||
for _, p := range m.Label {
|
||||
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||
}
|
||||
lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
||||
|
||||
smpl := &model.Sample{
|
||||
Metric: model.Metric(lset),
|
||||
Value: model.SampleValue(m.Gauge.GetValue()),
|
||||
}
|
||||
|
||||
if m.TimestampMs != nil {
|
||||
smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
|
||||
} else {
|
||||
smpl.Timestamp = o.Timestamp
|
||||
}
|
||||
|
||||
samples = append(samples, smpl)
|
||||
}
|
||||
|
||||
return samples
|
||||
}
|
||||
|
||||
func extractUntyped(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
|
||||
samples := make(model.Vector, 0, len(f.Metric))
|
||||
|
||||
for _, m := range f.Metric {
|
||||
if m.Untyped == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
lset := make(model.LabelSet, len(m.Label)+1)
|
||||
for _, p := range m.Label {
|
||||
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||
}
|
||||
lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
||||
|
||||
smpl := &model.Sample{
|
||||
Metric: model.Metric(lset),
|
||||
Value: model.SampleValue(m.Untyped.GetValue()),
|
||||
}
|
||||
|
||||
if m.TimestampMs != nil {
|
||||
smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
|
||||
} else {
|
||||
smpl.Timestamp = o.Timestamp
|
||||
}
|
||||
|
||||
samples = append(samples, smpl)
|
||||
}
|
||||
|
||||
return samples
|
||||
}
|
||||
|
||||
func extractSummary(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
|
||||
samples := make(model.Vector, 0, len(f.Metric))
|
||||
|
||||
for _, m := range f.Metric {
|
||||
if m.Summary == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
timestamp := o.Timestamp
|
||||
if m.TimestampMs != nil {
|
||||
timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
|
||||
}
|
||||
|
||||
for _, q := range m.Summary.Quantile {
|
||||
lset := make(model.LabelSet, len(m.Label)+2)
|
||||
for _, p := range m.Label {
|
||||
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||
}
|
||||
// BUG(matt): Update other names to "quantile".
|
||||
lset[model.LabelName(model.QuantileLabel)] = model.LabelValue(fmt.Sprint(q.GetQuantile()))
|
||||
lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
|
||||
|
||||
samples = append(samples, &model.Sample{
|
||||
Metric: model.Metric(lset),
|
||||
Value: model.SampleValue(q.GetValue()),
|
||||
Timestamp: timestamp,
|
||||
})
|
||||
}
|
||||
|
||||
lset := make(model.LabelSet, len(m.Label)+1)
|
||||
for _, p := range m.Label {
|
||||
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||
}
|
||||
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
|
||||
|
||||
samples = append(samples, &model.Sample{
|
||||
Metric: model.Metric(lset),
|
||||
Value: model.SampleValue(m.Summary.GetSampleSum()),
|
||||
Timestamp: timestamp,
|
||||
})
|
||||
|
||||
lset = make(model.LabelSet, len(m.Label)+1)
|
||||
for _, p := range m.Label {
|
||||
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||
}
|
||||
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
|
||||
|
||||
samples = append(samples, &model.Sample{
|
||||
Metric: model.Metric(lset),
|
||||
Value: model.SampleValue(m.Summary.GetSampleCount()),
|
||||
Timestamp: timestamp,
|
||||
})
|
||||
}
|
||||
|
||||
return samples
|
||||
}
|
||||
|
||||
func extractHistogram(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
|
||||
samples := make(model.Vector, 0, len(f.Metric))
|
||||
|
||||
for _, m := range f.Metric {
|
||||
if m.Histogram == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
timestamp := o.Timestamp
|
||||
if m.TimestampMs != nil {
|
||||
timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
|
||||
}
|
||||
|
||||
infSeen := false
|
||||
|
||||
for _, q := range m.Histogram.Bucket {
|
||||
lset := make(model.LabelSet, len(m.Label)+2)
|
||||
for _, p := range m.Label {
|
||||
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||
}
|
||||
lset[model.LabelName(model.BucketLabel)] = model.LabelValue(fmt.Sprint(q.GetUpperBound()))
|
||||
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
|
||||
|
||||
if math.IsInf(q.GetUpperBound(), +1) {
|
||||
infSeen = true
|
||||
}
|
||||
|
||||
samples = append(samples, &model.Sample{
|
||||
Metric: model.Metric(lset),
|
||||
Value: model.SampleValue(q.GetCumulativeCount()),
|
||||
Timestamp: timestamp,
|
||||
})
|
||||
}
|
||||
|
||||
lset := make(model.LabelSet, len(m.Label)+1)
|
||||
for _, p := range m.Label {
|
||||
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||
}
|
||||
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
|
||||
|
||||
samples = append(samples, &model.Sample{
|
||||
Metric: model.Metric(lset),
|
||||
Value: model.SampleValue(m.Histogram.GetSampleSum()),
|
||||
Timestamp: timestamp,
|
||||
})
|
||||
|
||||
lset = make(model.LabelSet, len(m.Label)+1)
|
||||
for _, p := range m.Label {
|
||||
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||
}
|
||||
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
|
||||
|
||||
count := &model.Sample{
|
||||
Metric: model.Metric(lset),
|
||||
Value: model.SampleValue(m.Histogram.GetSampleCount()),
|
||||
Timestamp: timestamp,
|
||||
}
|
||||
samples = append(samples, count)
|
||||
|
||||
if !infSeen {
|
||||
// Append an infinity bucket sample.
|
||||
lset := make(model.LabelSet, len(m.Label)+2)
|
||||
for _, p := range m.Label {
|
||||
lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
|
||||
}
|
||||
lset[model.LabelName(model.BucketLabel)] = model.LabelValue("+Inf")
|
||||
lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
|
||||
|
||||
samples = append(samples, &model.Sample{
|
||||
Metric: model.Metric(lset),
|
||||
Value: count.Value,
|
||||
Timestamp: timestamp,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return samples
|
||||
}
|
||||
356
vendor/github.com/prometheus/common/expfmt/decode_test.go
generated
vendored
Normal file
356
vendor/github.com/prometheus/common/expfmt/decode_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
// 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.
|
||||
|
||||
package expfmt
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
func TestTextDecoder(t *testing.T) {
|
||||
var (
|
||||
ts = model.Now()
|
||||
in = `
|
||||
# Only a quite simple scenario with two metric families.
|
||||
# More complicated tests of the parser itself can be found in the text package.
|
||||
# TYPE mf2 counter
|
||||
mf2 3
|
||||
mf1{label="value1"} -3.14 123456
|
||||
mf1{label="value2"} 42
|
||||
mf2 4
|
||||
`
|
||||
out = model.Vector{
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "mf1",
|
||||
"label": "value1",
|
||||
},
|
||||
Value: -3.14,
|
||||
Timestamp: 123456,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "mf1",
|
||||
"label": "value2",
|
||||
},
|
||||
Value: 42,
|
||||
Timestamp: ts,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "mf2",
|
||||
},
|
||||
Value: 3,
|
||||
Timestamp: ts,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "mf2",
|
||||
},
|
||||
Value: 4,
|
||||
Timestamp: ts,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
dec := &SampleDecoder{
|
||||
Dec: &textDecoder{r: strings.NewReader(in)},
|
||||
Opts: &DecodeOptions{
|
||||
Timestamp: ts,
|
||||
},
|
||||
}
|
||||
var all model.Vector
|
||||
for {
|
||||
var smpls model.Vector
|
||||
err := dec.Decode(&smpls)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
all = append(all, smpls...)
|
||||
}
|
||||
sort.Sort(all)
|
||||
sort.Sort(out)
|
||||
if !reflect.DeepEqual(all, out) {
|
||||
t.Fatalf("output does not match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProtoDecoder(t *testing.T) {
|
||||
|
||||
var testTime = model.Now()
|
||||
|
||||
scenarios := []struct {
|
||||
in string
|
||||
expected model.Vector
|
||||
}{
|
||||
{
|
||||
in: "",
|
||||
},
|
||||
{
|
||||
in: "\x8f\x01\n\rrequest_count\x12\x12Number of requests\x18\x00\"0\n#\n\x0fsome_label_name\x12\x10some_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00E\xc0\"6\n)\n\x12another_label_name\x12\x13another_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00U@",
|
||||
expected: model.Vector{
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_count",
|
||||
"some_label_name": "some_label_value",
|
||||
},
|
||||
Value: -42,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_count",
|
||||
"another_label_name": "another_label_value",
|
||||
},
|
||||
Value: 84,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
in: "\xb9\x01\n\rrequest_count\x12\x12Number of requests\x18\x02\"O\n#\n\x0fsome_label_name\x12\x10some_label_value\"(\x1a\x12\t\xaeG\xe1z\x14\xae\xef?\x11\x00\x00\x00\x00\x00\x00E\xc0\x1a\x12\t+\x87\x16\xd9\xce\xf7\xef?\x11\x00\x00\x00\x00\x00\x00U\xc0\"A\n)\n\x12another_label_name\x12\x13another_label_value\"\x14\x1a\x12\t\x00\x00\x00\x00\x00\x00\xe0?\x11\x00\x00\x00\x00\x00\x00$@",
|
||||
expected: model.Vector{
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_count_count",
|
||||
"some_label_name": "some_label_value",
|
||||
},
|
||||
Value: 0,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_count_sum",
|
||||
"some_label_name": "some_label_value",
|
||||
},
|
||||
Value: 0,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_count",
|
||||
"some_label_name": "some_label_value",
|
||||
"quantile": "0.99",
|
||||
},
|
||||
Value: -42,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_count",
|
||||
"some_label_name": "some_label_value",
|
||||
"quantile": "0.999",
|
||||
},
|
||||
Value: -84,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_count_count",
|
||||
"another_label_name": "another_label_value",
|
||||
},
|
||||
Value: 0,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_count_sum",
|
||||
"another_label_name": "another_label_value",
|
||||
},
|
||||
Value: 0,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_count",
|
||||
"another_label_name": "another_label_value",
|
||||
"quantile": "0.5",
|
||||
},
|
||||
Value: 10,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
in: "\x8d\x01\n\x1drequest_duration_microseconds\x12\x15The response latency.\x18\x04\"S:Q\b\x85\x15\x11\xcd\xcc\xccL\x8f\xcb:A\x1a\v\b{\x11\x00\x00\x00\x00\x00\x00Y@\x1a\f\b\x9c\x03\x11\x00\x00\x00\x00\x00\x00^@\x1a\f\b\xd0\x04\x11\x00\x00\x00\x00\x00\x00b@\x1a\f\b\xf4\v\x11\x9a\x99\x99\x99\x99\x99e@\x1a\f\b\x85\x15\x11\x00\x00\x00\x00\x00\x00\xf0\u007f",
|
||||
expected: model.Vector{
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_duration_microseconds_bucket",
|
||||
"le": "100",
|
||||
},
|
||||
Value: 123,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_duration_microseconds_bucket",
|
||||
"le": "120",
|
||||
},
|
||||
Value: 412,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_duration_microseconds_bucket",
|
||||
"le": "144",
|
||||
},
|
||||
Value: 592,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_duration_microseconds_bucket",
|
||||
"le": "172.8",
|
||||
},
|
||||
Value: 1524,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_duration_microseconds_bucket",
|
||||
"le": "+Inf",
|
||||
},
|
||||
Value: 2693,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_duration_microseconds_sum",
|
||||
},
|
||||
Value: 1756047.3,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_duration_microseconds_count",
|
||||
},
|
||||
Value: 2693,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// The metric type is unset in this protobuf, which needs to be handled
|
||||
// correctly by the decoder.
|
||||
in: "\x1c\n\rrequest_count\"\v\x1a\t\t\x00\x00\x00\x00\x00\x00\xf0?",
|
||||
expected: model.Vector{
|
||||
&model.Sample{
|
||||
Metric: model.Metric{
|
||||
model.MetricNameLabel: "request_count",
|
||||
},
|
||||
Value: 1,
|
||||
Timestamp: testTime,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, scenario := range scenarios {
|
||||
dec := &SampleDecoder{
|
||||
Dec: &protoDecoder{r: strings.NewReader(scenario.in)},
|
||||
Opts: &DecodeOptions{
|
||||
Timestamp: testTime,
|
||||
},
|
||||
}
|
||||
|
||||
var all model.Vector
|
||||
for {
|
||||
var smpls model.Vector
|
||||
err := dec.Decode(&smpls)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
all = append(all, smpls...)
|
||||
}
|
||||
sort.Sort(all)
|
||||
sort.Sort(scenario.expected)
|
||||
if !reflect.DeepEqual(all, scenario.expected) {
|
||||
t.Fatalf("%d. output does not match, want: %#v, got %#v", i, scenario.expected, all)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testDiscriminatorHTTPHeader(t testing.TB) {
|
||||
var scenarios = []struct {
|
||||
input map[string]string
|
||||
output Format
|
||||
err error
|
||||
}{
|
||||
{
|
||||
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`},
|
||||
output: FmtProtoDelim,
|
||||
},
|
||||
{
|
||||
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="illegal"; encoding="delimited"`},
|
||||
output: FmtUnknown,
|
||||
},
|
||||
{
|
||||
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="illegal"`},
|
||||
output: FmtUnknown,
|
||||
},
|
||||
{
|
||||
input: map[string]string{"Content-Type": `text/plain; version=0.0.4`},
|
||||
output: FmtText,
|
||||
},
|
||||
{
|
||||
input: map[string]string{"Content-Type": `text/plain`},
|
||||
output: FmtText,
|
||||
},
|
||||
{
|
||||
input: map[string]string{"Content-Type": `text/plain; version=0.0.3`},
|
||||
output: FmtUnknown,
|
||||
},
|
||||
}
|
||||
|
||||
for i, scenario := range scenarios {
|
||||
var header http.Header
|
||||
|
||||
if len(scenario.input) > 0 {
|
||||
header = http.Header{}
|
||||
}
|
||||
|
||||
for key, value := range scenario.input {
|
||||
header.Add(key, value)
|
||||
}
|
||||
|
||||
actual := ResponseFormat(header)
|
||||
|
||||
if scenario.output != actual {
|
||||
t.Errorf("%d. expected %s, got %s", i, scenario.output, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiscriminatorHTTPHeader(t *testing.T) {
|
||||
testDiscriminatorHTTPHeader(t)
|
||||
}
|
||||
|
||||
func BenchmarkDiscriminatorHTTPHeader(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
testDiscriminatorHTTPHeader(b)
|
||||
}
|
||||
}
|
||||
88
vendor/github.com/prometheus/common/expfmt/encode.go
generated
vendored
Normal file
88
vendor/github.com/prometheus/common/expfmt/encode.go
generated
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// 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.
|
||||
|
||||
package expfmt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"bitbucket.org/ww/goautoneg"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
// Encoder types encode metric families into an underlying wire protocol.
|
||||
type Encoder interface {
|
||||
Encode(*dto.MetricFamily) error
|
||||
}
|
||||
|
||||
type encoder func(*dto.MetricFamily) error
|
||||
|
||||
func (e encoder) Encode(v *dto.MetricFamily) error {
|
||||
return e(v)
|
||||
}
|
||||
|
||||
// Negotiate returns the Content-Type based on the given Accept header.
|
||||
// If no appropriate accepted type is found, FmtText is returned.
|
||||
func Negotiate(h http.Header) Format {
|
||||
for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
|
||||
// Check for protocol buffer
|
||||
if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
|
||||
switch ac.Params["encoding"] {
|
||||
case "delimited":
|
||||
return FmtProtoDelim
|
||||
case "text":
|
||||
return FmtProtoText
|
||||
case "compact-text":
|
||||
return FmtProtoCompact
|
||||
}
|
||||
}
|
||||
// Check for text format.
|
||||
ver := ac.Params["version"]
|
||||
if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
|
||||
return FmtText
|
||||
}
|
||||
}
|
||||
return FmtText
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder based on content type negotiation.
|
||||
func NewEncoder(w io.Writer, format Format) Encoder {
|
||||
switch format {
|
||||
case FmtProtoDelim:
|
||||
return encoder(func(v *dto.MetricFamily) error {
|
||||
_, err := pbutil.WriteDelimited(w, v)
|
||||
return err
|
||||
})
|
||||
case FmtProtoCompact:
|
||||
return encoder(func(v *dto.MetricFamily) error {
|
||||
_, err := fmt.Fprintln(w, v.String())
|
||||
return err
|
||||
})
|
||||
case FmtProtoText:
|
||||
return encoder(func(v *dto.MetricFamily) error {
|
||||
_, err := fmt.Fprintln(w, proto.MarshalTextString(v))
|
||||
return err
|
||||
})
|
||||
case FmtText:
|
||||
return encoder(func(v *dto.MetricFamily) error {
|
||||
_, err := MetricFamilyToText(w, v)
|
||||
return err
|
||||
})
|
||||
}
|
||||
panic("expfmt.NewEncoder: unknown format")
|
||||
}
|
||||
40
vendor/github.com/prometheus/common/expfmt/expfmt.go
generated
vendored
Normal file
40
vendor/github.com/prometheus/common/expfmt/expfmt.go
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// 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.
|
||||
|
||||
// A package for reading and writing Prometheus metrics.
|
||||
package expfmt
|
||||
|
||||
type Format string
|
||||
|
||||
const (
|
||||
TextVersion = "0.0.4"
|
||||
|
||||
ProtoType = `application/vnd.google.protobuf`
|
||||
ProtoProtocol = `io.prometheus.client.MetricFamily`
|
||||
ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";"
|
||||
|
||||
// The Content-Type values for the different wire protocols.
|
||||
FmtUnknown Format = `<unknown>`
|
||||
FmtText Format = `text/plain; version=` + TextVersion
|
||||
FmtProtoDelim Format = ProtoFmt + ` encoding=delimited`
|
||||
FmtProtoText Format = ProtoFmt + ` encoding=text`
|
||||
FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text`
|
||||
|
||||
// fmtJSON2 is hidden as it is deprecated.
|
||||
fmtJSON2 Format = `application/json; version=0.0.2`
|
||||
)
|
||||
|
||||
const (
|
||||
hdrContentType = "Content-Type"
|
||||
hdrAccept = "Accept"
|
||||
)
|
||||
36
vendor/github.com/prometheus/common/expfmt/fuzz.go
generated
vendored
Normal file
36
vendor/github.com/prometheus/common/expfmt/fuzz.go
generated
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// 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.
|
||||
|
||||
// Build only when actually fuzzing
|
||||
// +build gofuzz
|
||||
|
||||
package expfmt
|
||||
|
||||
import "bytes"
|
||||
|
||||
// Fuzz text metric parser with with github.com/dvyukov/go-fuzz:
|
||||
//
|
||||
// go-fuzz-build github.com/prometheus/client_golang/text
|
||||
// go-fuzz -bin text-fuzz.zip -workdir fuzz
|
||||
//
|
||||
// Further input samples should go in the folder fuzz/corpus.
|
||||
func Fuzz(in []byte) int {
|
||||
parser := TextParser{}
|
||||
_, err := parser.TextToMetricFamilies(bytes.NewReader(in))
|
||||
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
2
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_0
generated
vendored
Normal file
2
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_0
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
|
||||
6
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_1
generated
vendored
Normal file
6
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_1
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
minimal_metric 1.234
|
||||
another_metric -3e3 103948
|
||||
# Even that:
|
||||
no_labels{} 3
|
||||
# HELP line for non-existing metric will be ignored.
|
||||
12
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_2
generated
vendored
Normal file
12
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_2
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
# A normal comment.
|
||||
#
|
||||
# TYPE name counter
|
||||
name{labelname="val1",basename="basevalue"} NaN
|
||||
name {labelname="val2",basename="base\"v\\al\nue"} 0.23 1234567890
|
||||
# HELP name two-line\n doc str\\ing
|
||||
|
||||
# HELP name2 doc str"ing 2
|
||||
# TYPE name2 gauge
|
||||
name2{labelname="val2" ,basename = "basevalue2" } +Inf 54321
|
||||
name2{ labelname = "val1" , }-Inf
|
||||
22
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_3
generated
vendored
Normal file
22
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_3
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
# TYPE my_summary summary
|
||||
my_summary{n1="val1",quantile="0.5"} 110
|
||||
decoy -1 -2
|
||||
my_summary{n1="val1",quantile="0.9"} 140 1
|
||||
my_summary_count{n1="val1"} 42
|
||||
# Latest timestamp wins in case of a summary.
|
||||
my_summary_sum{n1="val1"} 4711 2
|
||||
fake_sum{n1="val1"} 2001
|
||||
# TYPE another_summary summary
|
||||
another_summary_count{n2="val2",n1="val1"} 20
|
||||
my_summary_count{n2="val2",n1="val1"} 5 5
|
||||
another_summary{n1="val1",n2="val2",quantile=".3"} -1.2
|
||||
my_summary_sum{n1="val2"} 08 15
|
||||
my_summary{n1="val3", quantile="0.2"} 4711
|
||||
my_summary{n1="val1",n2="val2",quantile="-12.34",} NaN
|
||||
# some
|
||||
# funny comments
|
||||
# HELP
|
||||
# HELP
|
||||
# HELP my_summary
|
||||
# HELP my_summary
|
||||
10
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_4
generated
vendored
Normal file
10
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_4
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# HELP request_duration_microseconds The response latency.
|
||||
# TYPE request_duration_microseconds histogram
|
||||
request_duration_microseconds_bucket{le="100"} 123
|
||||
request_duration_microseconds_bucket{le="120"} 412
|
||||
request_duration_microseconds_bucket{le="144"} 592
|
||||
request_duration_microseconds_bucket{le="172.8"} 1524
|
||||
request_duration_microseconds_bucket{le="+Inf"} 2693
|
||||
request_duration_microseconds_sum 1.7560473e+06
|
||||
request_duration_microseconds_count 2693
|
||||
1
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_0
generated
vendored
Normal file
1
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_0
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
bla 3.14
|
||||
1
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_1
generated
vendored
Normal file
1
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_1
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
metric{label="\t"} 3.14
|
||||
1
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_10
generated
vendored
Normal file
1
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_10
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
metric{label="bla"} 3.14 2 3
|
||||
1
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_11
generated
vendored
Normal file
1
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_11
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
metric{label="bla"} blubb
|
||||
3
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_12
generated
vendored
Normal file
3
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_12
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
# HELP metric one
|
||||
# HELP metric two
|
||||
3
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_13
generated
vendored
Normal file
3
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_13
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
# TYPE metric counter
|
||||
# TYPE metric untyped
|
||||
3
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_14
generated
vendored
Normal file
3
vendor/github.com/prometheus/common/expfmt/fuzz/corpus/from_test_parse_error_14
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
metric 4.12
|
||||
# TYPE metric counter
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue