init
This commit is contained in:
		
							
								
								
									
										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. | ||||
							
								
								
									
										23
									
								
								vendor/github.com/prometheus/client_golang/NOTICE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/prometheus/client_golang/NOTICE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| 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: | ||||
|  | ||||
| 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 | ||||
							
								
								
									
										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 | ||||
							
								
								
									
										1
									
								
								vendor/github.com/prometheus/client_golang/prometheus/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/prometheus/client_golang/prometheus/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| See [](https://godoc.org/github.com/prometheus/client_golang/prometheus). | ||||
							
								
								
									
										120
									
								
								vendor/github.com/prometheus/client_golang/prometheus/collector.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								vendor/github.com/prometheus/client_golang/prometheus/collector.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| // 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 Registerer.Register. | ||||
| // | ||||
| // The stock metrics provided by this package (Gauge, Counter, Summary, | ||||
| // Histogram, Untyped) 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. | ||||
| 	// | ||||
| 	// Sending no descriptor at all marks the Collector as “unchecked”, | ||||
| 	// i.e. no checks will be performed at registration time, and the | ||||
| 	// Collector may yield any Metric it sees fit in its Collect method. | ||||
| 	// | ||||
| 	// This method idempotently sends the same descriptors throughout the | ||||
| 	// lifetime of the Collector. It may be called concurrently and | ||||
| 	// therefore must be implemented in a concurrency safe way. | ||||
| 	// | ||||
| 	// 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 the Prometheus registry 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 | ||||
| 	// (unless the Collector is unchecked, see above). 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) | ||||
| } | ||||
|  | ||||
| // DescribeByCollect is a helper to implement the Describe method of a custom | ||||
| // Collector. It collects the metrics from the provided Collector and sends | ||||
| // their descriptors to the provided channel. | ||||
| // | ||||
| // If a Collector collects the same metrics throughout its lifetime, its | ||||
| // Describe method can simply be implemented as: | ||||
| // | ||||
| //   func (c customCollector) Describe(ch chan<- *Desc) { | ||||
| //   	DescribeByCollect(c, ch) | ||||
| //   } | ||||
| // | ||||
| // However, this will not work if the metrics collected change dynamically over | ||||
| // the lifetime of the Collector in a way that their combined set of descriptors | ||||
| // changes as well. The shortcut implementation will then violate the contract | ||||
| // of the Describe method. If a Collector sometimes collects no metrics at all | ||||
| // (for example vectors like CounterVec, GaugeVec, etc., which only collect | ||||
| // metrics after a metric with a fully specified label set has been accessed), | ||||
| // it might even get registered as an unchecked Collecter (cf. the Register | ||||
| // method of the Registerer interface). Hence, only use this shortcut | ||||
| // implementation of Describe if you are certain to fulfill the contract. | ||||
| // | ||||
| // The Collector example demonstrates a use of DescribeByCollect. | ||||
| func DescribeByCollect(c Collector, descs chan<- *Desc) { | ||||
| 	metrics := make(chan Metric) | ||||
| 	go func() { | ||||
| 		c.Collect(metrics) | ||||
| 		close(metrics) | ||||
| 	}() | ||||
| 	for m := range metrics { | ||||
| 		descs <- m.Desc() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // selfCollector implements Collector for a single Metric so 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 | ||||
| } | ||||
							
								
								
									
										277
									
								
								vendor/github.com/prometheus/client_golang/prometheus/counter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								vendor/github.com/prometheus/client_golang/prometheus/counter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,277 @@ | ||||
| // 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" | ||||
| 	"math" | ||||
| 	"sync/atomic" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| // 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 | ||||
|  | ||||
| 	// Inc increments the counter by 1. Use Add to increment it by arbitrary | ||||
| 	// non-negative values. | ||||
| 	Inc() | ||||
| 	// Add adds the given value to the counter. It panics if the value is < | ||||
| 	// 0. | ||||
| 	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. | ||||
| // | ||||
| // The returned implementation tracks the counter value in two separate | ||||
| // variables, a float64 and a uint64. The latter is used to track calls of the | ||||
| // Inc method and calls of the Add method with a value that can be represented | ||||
| // as a uint64. This allows atomic increments of the counter with optimal | ||||
| // performance. (It is common to have an Inc call in very hot execution paths.) | ||||
| // Both internal tracking values are added up in the Write method. This has to | ||||
| // be taken into account when it comes to precision and overflow behavior. | ||||
| func NewCounter(opts CounterOpts) Counter { | ||||
| 	desc := NewDesc( | ||||
| 		BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), | ||||
| 		opts.Help, | ||||
| 		nil, | ||||
| 		opts.ConstLabels, | ||||
| 	) | ||||
| 	result := &counter{desc: desc, labelPairs: desc.constLabelPairs} | ||||
| 	result.init(result) // Init self-collection. | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| type counter struct { | ||||
| 	// valBits contains the bits of the represented float64 value, while | ||||
| 	// valInt stores values that are exact integers. Both have to go first | ||||
| 	// in the struct to guarantee alignment for atomic operations. | ||||
| 	// http://golang.org/pkg/sync/atomic/#pkg-note-BUG | ||||
| 	valBits uint64 | ||||
| 	valInt  uint64 | ||||
|  | ||||
| 	selfCollector | ||||
| 	desc *Desc | ||||
|  | ||||
| 	labelPairs []*dto.LabelPair | ||||
| } | ||||
|  | ||||
| func (c *counter) Desc() *Desc { | ||||
| 	return c.desc | ||||
| } | ||||
|  | ||||
| func (c *counter) Add(v float64) { | ||||
| 	if v < 0 { | ||||
| 		panic(errors.New("counter cannot decrease in value")) | ||||
| 	} | ||||
| 	ival := uint64(v) | ||||
| 	if float64(ival) == v { | ||||
| 		atomic.AddUint64(&c.valInt, ival) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	for { | ||||
| 		oldBits := atomic.LoadUint64(&c.valBits) | ||||
| 		newBits := math.Float64bits(math.Float64frombits(oldBits) + v) | ||||
| 		if atomic.CompareAndSwapUint64(&c.valBits, oldBits, newBits) { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *counter) Inc() { | ||||
| 	atomic.AddUint64(&c.valInt, 1) | ||||
| } | ||||
|  | ||||
| func (c *counter) Write(out *dto.Metric) error { | ||||
| 	fval := math.Float64frombits(atomic.LoadUint64(&c.valBits)) | ||||
| 	ival := atomic.LoadUint64(&c.valInt) | ||||
| 	val := fval + float64(ival) | ||||
|  | ||||
| 	return populateMetric(CounterValue, val, c.labelPairs, out) | ||||
| } | ||||
|  | ||||
| // 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. | ||||
| type CounterVec struct { | ||||
| 	*metricVec | ||||
| } | ||||
|  | ||||
| // NewCounterVec creates a new CounterVec based on the provided CounterOpts and | ||||
| // partitioned by the given label names. | ||||
| func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec { | ||||
| 	desc := NewDesc( | ||||
| 		BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), | ||||
| 		opts.Help, | ||||
| 		labelNames, | ||||
| 		opts.ConstLabels, | ||||
| 	) | ||||
| 	return &CounterVec{ | ||||
| 		metricVec: newMetricVec(desc, func(lvs ...string) Metric { | ||||
| 			if len(lvs) != len(desc.variableLabels) { | ||||
| 				panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) | ||||
| 			} | ||||
| 			result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs)} | ||||
| 			result.init(result) // Init self-collection. | ||||
| 			return result | ||||
| 		}), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetMetricWithLabelValues returns the Counter 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 Counter is created. | ||||
| // | ||||
| // It is possible to call this method without using the returned Counter to only | ||||
| // create the new Counter but leave it at its starting value 0. See also the | ||||
| // SummaryVec example. | ||||
| // | ||||
| // Keeping the Counter 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 Counter from the CounterVec. In that case, | ||||
| // the Counter will still exist, but it will not be exported anymore, even if a | ||||
| // Counter with the same label values is created later. | ||||
| // | ||||
| // An error is returned if the number of label values is not the same as the | ||||
| // number of VariableLabels in Desc (minus any curried labels). | ||||
| // | ||||
| // 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 (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) { | ||||
| 	metric, err := v.metricVec.getMetricWithLabelValues(lvs...) | ||||
| 	if metric != nil { | ||||
| 		return metric.(Counter), err | ||||
| 	} | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| // GetMetricWith returns the Counter 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 Counter is created. Implications of | ||||
| // creating a Counter without using it and keeping the Counter 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 (minus any curried labels). | ||||
| // | ||||
| // This method is used for the same purpose as | ||||
| // GetMetricWithLabelValues(...string). See there for pros and cons of the two | ||||
| // methods. | ||||
| func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) { | ||||
| 	metric, err := v.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. Not returning an | ||||
| // error allows shortcuts like | ||||
| //     myVec.WithLabelValues("404", "GET").Add(42) | ||||
| func (v *CounterVec) WithLabelValues(lvs ...string) Counter { | ||||
| 	c, err := v.GetMetricWithLabelValues(lvs...) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| // With works as GetMetricWith, but panics where GetMetricWithLabels would have | ||||
| // returned an error. Not returning an error allows shortcuts like | ||||
| //     myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42) | ||||
| func (v *CounterVec) With(labels Labels) Counter { | ||||
| 	c, err := v.GetMetricWith(labels) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| // CurryWith returns a vector curried with the provided labels, i.e. the | ||||
| // returned vector has those labels pre-set for all labeled operations performed | ||||
| // on it. The cardinality of the curried vector is reduced accordingly. The | ||||
| // order of the remaining labels stays the same (just with the curried labels | ||||
| // taken out of the sequence – which is relevant for the | ||||
| // (GetMetric)WithLabelValues methods). It is possible to curry a curried | ||||
| // vector, but only with labels not yet used for currying before. | ||||
| // | ||||
| // The metrics contained in the CounterVec are shared between the curried and | ||||
| // uncurried vectors. They are just accessed differently. Curried and uncurried | ||||
| // vectors behave identically in terms of collection. Only one must be | ||||
| // registered with a given registry (usually the uncurried version). The Reset | ||||
| // method deletes all metrics, even if called on a curried vector. | ||||
| func (v *CounterVec) CurryWith(labels Labels) (*CounterVec, error) { | ||||
| 	vec, err := v.curryWith(labels) | ||||
| 	if vec != nil { | ||||
| 		return &CounterVec{vec}, err | ||||
| 	} | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| // MustCurryWith works as CurryWith but panics where CurryWith would have | ||||
| // returned an error. | ||||
| func (v *CounterVec) MustCurryWith(labels Labels) *CounterVec { | ||||
| 	vec, err := v.CurryWith(labels) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return vec | ||||
| } | ||||
|  | ||||
| // 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) | ||||
| } | ||||
							
								
								
									
										184
									
								
								vendor/github.com/prometheus/client_golang/prometheus/desc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								vendor/github.com/prometheus/client_golang/prometheus/desc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | ||||
| // Copyright 2016 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package prometheus | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"github.com/prometheus/common/model" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| // 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 occurred 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 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 Collector example for a usage pattern. | ||||
| func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *Desc { | ||||
| 	d := &Desc{ | ||||
| 		fqName:         fqName, | ||||
| 		help:           help, | ||||
| 		variableLabels: variableLabels, | ||||
| 	} | ||||
| 	if !model.IsValidMetricName(model.LabelValue(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]) | ||||
| 	} | ||||
| 	// Validate the const label values. They can't have a wrong cardinality, so | ||||
| 	// use in len(labelValues) as expectedNumberOfValues. | ||||
| 	if err := validateLabelValues(labelValues, len(labelValues)); err != nil { | ||||
| 		d.err = err | ||||
| 		return d | ||||
| 	} | ||||
| 	// 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 | ||||
| 	} | ||||
|  | ||||
| 	vh := hashNew() | ||||
| 	for _, val := range labelValues { | ||||
| 		vh = hashAdd(vh, val) | ||||
| 		vh = hashAddByte(vh, separatorByte) | ||||
| 	} | ||||
| 	d.id = vh | ||||
| 	// 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. | ||||
| 	lh := hashNew() | ||||
| 	lh = hashAdd(lh, help) | ||||
| 	lh = hashAddByte(lh, separatorByte) | ||||
| 	for _, labelName := range labelNames { | ||||
| 		lh = hashAdd(lh, labelName) | ||||
| 		lh = hashAddByte(lh, separatorByte) | ||||
| 	} | ||||
| 	d.dimHash = lh | ||||
|  | ||||
| 	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, | ||||
| 	) | ||||
| } | ||||
							
								
								
									
										201
									
								
								vendor/github.com/prometheus/client_golang/prometheus/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								vendor/github.com/prometheus/client_golang/prometheus/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,201 @@ | ||||
| // 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 is the core instrumentation package. It provides metrics | ||||
| // primitives to instrument code for monitoring. It also offers a registry for | ||||
| // metrics. Sub-packages allow to expose the registered metrics via HTTP | ||||
| // (package promhttp) or push them to a Pushgateway (package push). There is | ||||
| // also a sub-package promauto, which provides metrics constructors with | ||||
| // automatic registration. | ||||
| // | ||||
| // All exported functions and methods are safe to be used concurrently unless | ||||
| // specified otherwise. | ||||
| // | ||||
| // A Basic Example | ||||
| // | ||||
| // As a starting point, a very basic usage example: | ||||
| // | ||||
| //    package main | ||||
| // | ||||
| //    import ( | ||||
| //    	"log" | ||||
| //    	"net/http" | ||||
| // | ||||
| //    	"github.com/prometheus/client_golang/prometheus" | ||||
| //    	"github.com/prometheus/client_golang/prometheus/promhttp" | ||||
| //    ) | ||||
| // | ||||
| //    var ( | ||||
| //    	cpuTemp = prometheus.NewGauge(prometheus.GaugeOpts{ | ||||
| //    		Name: "cpu_temperature_celsius", | ||||
| //    		Help: "Current temperature of the CPU.", | ||||
| //    	}) | ||||
| //    	hdFailures = prometheus.NewCounterVec( | ||||
| //    		prometheus.CounterOpts{ | ||||
| //    			Name: "hd_errors_total", | ||||
| //    			Help: "Number of hard-disk errors.", | ||||
| //    		}, | ||||
| //    		[]string{"device"}, | ||||
| //    	) | ||||
| //    ) | ||||
| // | ||||
| //    func init() { | ||||
| //    	// Metrics have to be registered to be exposed: | ||||
| //    	prometheus.MustRegister(cpuTemp) | ||||
| //    	prometheus.MustRegister(hdFailures) | ||||
| //    } | ||||
| // | ||||
| //    func main() { | ||||
| //    	cpuTemp.Set(65.3) | ||||
| //    	hdFailures.With(prometheus.Labels{"device":"/dev/sda"}).Inc() | ||||
| // | ||||
| //    	// The Handler function provides a default handler to expose metrics | ||||
| //    	// via an HTTP server. "/metrics" is the usual endpoint for that. | ||||
| //    	http.Handle("/metrics", promhttp.Handler()) | ||||
| //    	log.Fatal(http.ListenAndServe(":8080", nil)) | ||||
| //    } | ||||
| // | ||||
| // | ||||
| // This is a complete program that exports two metrics, a Gauge and a Counter, | ||||
| // the latter with a label attached to turn it into a (one-dimensional) vector. | ||||
| // | ||||
| // Metrics | ||||
| // | ||||
| // The number of exported identifiers in this package might appear a bit | ||||
| // overwhelming. However, in addition to the basic plumbing shown in the example | ||||
| // above, you only need to understand the different metric types and their | ||||
| // vector versions for basic usage. Furthermore, if you are not concerned with | ||||
| // fine-grained control of when and how to register metrics with the registry, | ||||
| // have a look at the promauto package, which will effectively allow you to | ||||
| // ignore registration altogether in simple cases. | ||||
| // | ||||
| // Above, you have already touched the Counter and the Gauge. There are two more | ||||
| // advanced metric types: the Summary and Histogram. A more thorough description | ||||
| // of those four metric types can be found in the Prometheus docs: | ||||
| // https://prometheus.io/docs/concepts/metric_types/ | ||||
| // | ||||
| // A fifth "type" of metric is Untyped. It behaves like a Gauge, but signals the | ||||
| // Prometheus server not to assume anything about its type. | ||||
| // | ||||
| // In addition to the fundamental metric types Gauge, Counter, Summary, | ||||
| // Histogram, and Untyped, 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, | ||||
| // HistogramVec, and UntypedVec. | ||||
| // | ||||
| // While only the fundamental metric types implement the Metric interface, both | ||||
| // the metrics and their vector versions implement the Collector interface. A | ||||
| // Collector manages the collection of a number of Metrics, but for convenience, | ||||
| // a Metric can also “collect itself”. Note that Gauge, Counter, Summary, | ||||
| // Histogram, and Untyped are interfaces themselves while GaugeVec, CounterVec, | ||||
| // SummaryVec, HistogramVec, and UntypedVec are not. | ||||
| // | ||||
| // To create instances of Metrics and their vector versions, you need a suitable | ||||
| // …Opts struct, i.e. GaugeOpts, CounterOpts, SummaryOpts, HistogramOpts, or | ||||
| // UntypedOpts. | ||||
| // | ||||
| // Custom Collectors and constant Metrics | ||||
| // | ||||
| // While you could create your own implementations of Metric, most likely you | ||||
| // will only ever implement the Collector interface on your own. At a first | ||||
| // glance, a custom Collector seems handy to bundle Metrics for common | ||||
| // registration (with the prime example of the different metric vectors above, | ||||
| // which bundle all the metrics of the same name but with different labels). | ||||
| // | ||||
| // There is a more involved use case, too: If you already have metrics | ||||
| // available, created outside of the Prometheus context, you don't need the | ||||
| // interface of the various Metric types. You essentially want to mirror the | ||||
| // existing numbers into Prometheus Metrics during collection. An own | ||||
| // implementation of the Collector interface is perfect for that. You can create | ||||
| // Metric instances “on the fly” using NewConstMetric, NewConstHistogram, and | ||||
| // NewConstSummary (and their respective Must… versions). That will happen in | ||||
| // the Collect method. The Describe method has to return separate Desc | ||||
| // instances, representative of the “throw-away” metrics to be created later. | ||||
| // NewDesc comes in handy to create those Desc instances. Alternatively, you | ||||
| // could return no Desc at all, which will marke the Collector “unchecked”.  No | ||||
| // checks are porformed at registration time, but metric consistency will still | ||||
| // be ensured at scrape time, i.e. any inconsistencies will lead to scrape | ||||
| // errors. Thus, with unchecked Collectors, the responsibility to not collect | ||||
| // metrics that lead to inconsistencies in the total scrape result lies with the | ||||
| // implementer of the Collector. While this is not a desirable state, it is | ||||
| // sometimes necessary. The typical use case is a situatios where the exact | ||||
| // metrics to be returned by a Collector cannot be predicted at registration | ||||
| // time, but the implementer has sufficient knowledge of the whole system to | ||||
| // guarantee metric consistency. | ||||
| // | ||||
| // The Collector example illustrates the use case. You can also look at the | ||||
| // source code of the processCollector (mirroring process metrics), the | ||||
| // goCollector (mirroring Go metrics), or the expvarCollector (mirroring expvar | ||||
| // metrics) as examples that are used in this package itself. | ||||
| // | ||||
| // If you just need to call a function to get a single float value to collect as | ||||
| // a metric, GaugeFunc, CounterFunc, or UntypedFunc might be interesting | ||||
| // shortcuts. | ||||
| // | ||||
| // Advanced Uses of the Registry | ||||
| // | ||||
| // While MustRegister is the by far most common way of registering a Collector, | ||||
| // sometimes you might want to handle the errors the registration might cause. | ||||
| // As suggested by the name, MustRegister panics if an error occurs. With the | ||||
| // Register function, the error is returned and can be handled. | ||||
| // | ||||
| // An error is returned if the registered Collector is incompatible or | ||||
| // inconsistent with already registered metrics. The registry aims for | ||||
| // consistency of the collected metrics according to the Prometheus data model. | ||||
| // Inconsistencies are ideally detected at registration time, not at collect | ||||
| // time. The former will usually be detected at start-up time of a program, | ||||
| // while the latter will only happen at scrape time, possibly not even on the | ||||
| // first scrape if the inconsistency only becomes relevant later. That is the | ||||
| // main reason why a Collector and a Metric have to describe themselves to the | ||||
| // registry. | ||||
| // | ||||
| // So far, everything we did operated on the so-called default registry, as it | ||||
| // can be found in the global DefaultRegisterer variable. With NewRegistry, you | ||||
| // can create a custom registry, or you can even implement the Registerer or | ||||
| // Gatherer interfaces yourself. The methods Register and Unregister work in the | ||||
| // same way on a custom registry as the global functions Register and Unregister | ||||
| // on the default registry. | ||||
| // | ||||
| // There are a number of uses for custom registries: You can use registries with | ||||
| // special properties, see NewPedanticRegistry. You can avoid global state, as | ||||
| // it is imposed by the DefaultRegisterer. You can use multiple registries at | ||||
| // the same time to expose different metrics in different ways.  You can use | ||||
| // separate registries for testing purposes. | ||||
| // | ||||
| // Also note that the DefaultRegisterer comes registered with a Collector for Go | ||||
| // runtime metrics (via NewGoCollector) and a Collector for process metrics (via | ||||
| // NewProcessCollector). With a custom registry, you are in control and decide | ||||
| // yourself about the Collectors to register. | ||||
| // | ||||
| // HTTP Exposition | ||||
| // | ||||
| // The Registry implements the Gatherer interface. The caller of the Gather | ||||
| // method can then expose the gathered metrics in some way. Usually, the metrics | ||||
| // are served via HTTP on the /metrics endpoint. That's happening in the example | ||||
| // above. The tools to expose metrics via HTTP are in the promhttp sub-package. | ||||
| // (The top-level functions in the prometheus package are deprecated.) | ||||
| // | ||||
| // Pushing to the Pushgateway | ||||
| // | ||||
| // Function for pushing to the Pushgateway can be found in the push sub-package. | ||||
| // | ||||
| // Graphite Bridge | ||||
| // | ||||
| // Functions and examples to push metrics from a Gatherer to Graphite can be | ||||
| // found in the graphite sub-package. | ||||
| // | ||||
| // Other Means of Exposition | ||||
| // | ||||
| // More ways of exposing metrics can easily be added by following the approaches | ||||
| // of the existing implementations. | ||||
| package prometheus | ||||
							
								
								
									
										119
									
								
								vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								vendor/github.com/prometheus/client_golang/prometheus/expvar_collector.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" | ||||
| ) | ||||
|  | ||||
| type expvarCollector struct { | ||||
| 	exports map[string]*Desc | ||||
| } | ||||
|  | ||||
| // NewExpvarCollector returns a newly allocated expvar Collector that still has | ||||
| // to be registered with a Prometheus registry. | ||||
| // | ||||
| // An expvar Collector 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 expvar Collector is inherently slower | ||||
| // than native Prometheus metrics. Thus, the expvar Collector is probably great | ||||
| // for experiments and prototying, but you should seriously consider a more | ||||
| // direct implementation of Prometheus metrics for monitoring production | ||||
| // systems. | ||||
| // | ||||
| // 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) Collector { | ||||
| 	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) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										42
									
								
								vendor/github.com/prometheus/client_golang/prometheus/fnv.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/prometheus/client_golang/prometheus/fnv.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| // Copyright 2018 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 | ||||
|  | ||||
| // Inline and byte-free variant of hash/fnv's fnv64a. | ||||
|  | ||||
| const ( | ||||
| 	offset64 = 14695981039346656037 | ||||
| 	prime64  = 1099511628211 | ||||
| ) | ||||
|  | ||||
| // hashNew initializies a new fnv64a hash value. | ||||
| func hashNew() uint64 { | ||||
| 	return offset64 | ||||
| } | ||||
|  | ||||
| // hashAdd adds a string to a fnv64a hash value, returning the updated hash. | ||||
| func hashAdd(h uint64, s string) uint64 { | ||||
| 	for i := 0; i < len(s); i++ { | ||||
| 		h ^= uint64(s[i]) | ||||
| 		h *= prime64 | ||||
| 	} | ||||
| 	return h | ||||
| } | ||||
|  | ||||
| // hashAddByte adds a byte to a fnv64a hash value, returning the updated hash. | ||||
| func hashAddByte(h uint64, b byte) uint64 { | ||||
| 	h ^= uint64(b) | ||||
| 	h *= prime64 | ||||
| 	return h | ||||
| } | ||||
							
								
								
									
										286
									
								
								vendor/github.com/prometheus/client_golang/prometheus/gauge.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								vendor/github.com/prometheus/client_golang/prometheus/gauge.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,286 @@ | ||||
| // 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" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| // 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. Use Add to increment it by arbitrary | ||||
| 	// values. | ||||
| 	Inc() | ||||
| 	// Dec decrements the Gauge by 1. Use Sub to decrement it by arbitrary | ||||
| 	// values. | ||||
| 	Dec() | ||||
| 	// Add adds the given value to the Gauge. (The value can be negative, | ||||
| 	// resulting in a decrease of the Gauge.) | ||||
| 	Add(float64) | ||||
| 	// Sub subtracts the given value from the Gauge. (The value can be | ||||
| 	// negative, resulting in an increase of the Gauge.) | ||||
| 	Sub(float64) | ||||
|  | ||||
| 	// SetToCurrentTime sets the Gauge to the current Unix time in seconds. | ||||
| 	SetToCurrentTime() | ||||
| } | ||||
|  | ||||
| // GaugeOpts is an alias for Opts. See there for doc comments. | ||||
| type GaugeOpts Opts | ||||
|  | ||||
| // NewGauge creates a new Gauge based on the provided GaugeOpts. | ||||
| // | ||||
| // The returned implementation is optimized for a fast Set method. If you have a | ||||
| // choice for managing the value of a Gauge via Set vs. Inc/Dec/Add/Sub, pick | ||||
| // the former. For example, the Inc method of the returned Gauge is slower than | ||||
| // the Inc method of a Counter returned by NewCounter. This matches the typical | ||||
| // scenarios for Gauges and Counters, where the former tends to be Set-heavy and | ||||
| // the latter Inc-heavy. | ||||
| func NewGauge(opts GaugeOpts) Gauge { | ||||
| 	desc := NewDesc( | ||||
| 		BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), | ||||
| 		opts.Help, | ||||
| 		nil, | ||||
| 		opts.ConstLabels, | ||||
| 	) | ||||
| 	result := &gauge{desc: desc, labelPairs: desc.constLabelPairs} | ||||
| 	result.init(result) // Init self-collection. | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| type gauge struct { | ||||
| 	// valBits contains the bits of the represented float64 value. It has | ||||
| 	// to go first in the struct to guarantee alignment for atomic | ||||
| 	// operations.  http://golang.org/pkg/sync/atomic/#pkg-note-BUG | ||||
| 	valBits uint64 | ||||
|  | ||||
| 	selfCollector | ||||
|  | ||||
| 	desc       *Desc | ||||
| 	labelPairs []*dto.LabelPair | ||||
| } | ||||
|  | ||||
| func (g *gauge) Desc() *Desc { | ||||
| 	return g.desc | ||||
| } | ||||
|  | ||||
| func (g *gauge) Set(val float64) { | ||||
| 	atomic.StoreUint64(&g.valBits, math.Float64bits(val)) | ||||
| } | ||||
|  | ||||
| func (g *gauge) SetToCurrentTime() { | ||||
| 	g.Set(float64(time.Now().UnixNano()) / 1e9) | ||||
| } | ||||
|  | ||||
| func (g *gauge) Inc() { | ||||
| 	g.Add(1) | ||||
| } | ||||
|  | ||||
| func (g *gauge) Dec() { | ||||
| 	g.Add(-1) | ||||
| } | ||||
|  | ||||
| func (g *gauge) Add(val float64) { | ||||
| 	for { | ||||
| 		oldBits := atomic.LoadUint64(&g.valBits) | ||||
| 		newBits := math.Float64bits(math.Float64frombits(oldBits) + val) | ||||
| 		if atomic.CompareAndSwapUint64(&g.valBits, oldBits, newBits) { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (g *gauge) Sub(val float64) { | ||||
| 	g.Add(val * -1) | ||||
| } | ||||
|  | ||||
| func (g *gauge) Write(out *dto.Metric) error { | ||||
| 	val := math.Float64frombits(atomic.LoadUint64(&g.valBits)) | ||||
| 	return populateMetric(GaugeValue, val, g.labelPairs, out) | ||||
| } | ||||
|  | ||||
| // 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. | ||||
| func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec { | ||||
| 	desc := NewDesc( | ||||
| 		BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), | ||||
| 		opts.Help, | ||||
| 		labelNames, | ||||
| 		opts.ConstLabels, | ||||
| 	) | ||||
| 	return &GaugeVec{ | ||||
| 		metricVec: newMetricVec(desc, func(lvs ...string) Metric { | ||||
| 			if len(lvs) != len(desc.variableLabels) { | ||||
| 				panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) | ||||
| 			} | ||||
| 			result := &gauge{desc: desc, labelPairs: makeLabelPairs(desc, lvs)} | ||||
| 			result.init(result) // Init self-collection. | ||||
| 			return result | ||||
| 		}), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetMetricWithLabelValues returns the Gauge 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 Gauge is created. | ||||
| // | ||||
| // It is possible to call this method without using the returned Gauge to only | ||||
| // create the new Gauge but leave it at its starting value 0. See also the | ||||
| // SummaryVec example. | ||||
| // | ||||
| // Keeping the Gauge 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 Gauge from the GaugeVec. In that case, the | ||||
| // Gauge will still exist, but it will not be exported anymore, even if a | ||||
| // Gauge 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 (minus any curried labels). | ||||
| // | ||||
| // 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). | ||||
| func (v *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) { | ||||
| 	metric, err := v.metricVec.getMetricWithLabelValues(lvs...) | ||||
| 	if metric != nil { | ||||
| 		return metric.(Gauge), err | ||||
| 	} | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| // GetMetricWith returns the Gauge 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 Gauge is created. Implications of | ||||
| // creating a Gauge without using it and keeping the Gauge 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 (minus any curried labels). | ||||
| // | ||||
| // This method is used for the same purpose as | ||||
| // GetMetricWithLabelValues(...string). See there for pros and cons of the two | ||||
| // methods. | ||||
| func (v *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) { | ||||
| 	metric, err := v.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. Not returning an | ||||
| // error allows shortcuts like | ||||
| //     myVec.WithLabelValues("404", "GET").Add(42) | ||||
| func (v *GaugeVec) WithLabelValues(lvs ...string) Gauge { | ||||
| 	g, err := v.GetMetricWithLabelValues(lvs...) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return g | ||||
| } | ||||
|  | ||||
| // With works as GetMetricWith, but panics where GetMetricWithLabels would have | ||||
| // returned an error. Not returning an error allows shortcuts like | ||||
| //     myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42) | ||||
| func (v *GaugeVec) With(labels Labels) Gauge { | ||||
| 	g, err := v.GetMetricWith(labels) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return g | ||||
| } | ||||
|  | ||||
| // CurryWith returns a vector curried with the provided labels, i.e. the | ||||
| // returned vector has those labels pre-set for all labeled operations performed | ||||
| // on it. The cardinality of the curried vector is reduced accordingly. The | ||||
| // order of the remaining labels stays the same (just with the curried labels | ||||
| // taken out of the sequence – which is relevant for the | ||||
| // (GetMetric)WithLabelValues methods). It is possible to curry a curried | ||||
| // vector, but only with labels not yet used for currying before. | ||||
| // | ||||
| // The metrics contained in the GaugeVec are shared between the curried and | ||||
| // uncurried vectors. They are just accessed differently. Curried and uncurried | ||||
| // vectors behave identically in terms of collection. Only one must be | ||||
| // registered with a given registry (usually the uncurried version). The Reset | ||||
| // method deletes all metrics, even if called on a curried vector. | ||||
| func (v *GaugeVec) CurryWith(labels Labels) (*GaugeVec, error) { | ||||
| 	vec, err := v.curryWith(labels) | ||||
| 	if vec != nil { | ||||
| 		return &GaugeVec{vec}, err | ||||
| 	} | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| // MustCurryWith works as CurryWith but panics where CurryWith would have | ||||
| // returned an error. | ||||
| func (v *GaugeVec) MustCurryWith(labels Labels) *GaugeVec { | ||||
| 	vec, err := v.CurryWith(labels) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return vec | ||||
| } | ||||
|  | ||||
| // 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) | ||||
| } | ||||
							
								
								
									
										301
									
								
								vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								vendor/github.com/prometheus/client_golang/prometheus/go_collector.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,301 @@ | ||||
| // Copyright 2018 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" | ||||
| 	"runtime" | ||||
| 	"runtime/debug" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type goCollector struct { | ||||
| 	goroutinesDesc *Desc | ||||
| 	threadsDesc    *Desc | ||||
| 	gcDesc         *Desc | ||||
| 	goInfoDesc     *Desc | ||||
|  | ||||
| 	// metrics to describe and collect | ||||
| 	metrics memStatsMetrics | ||||
| } | ||||
|  | ||||
| // NewGoCollector returns a collector which exports metrics about the current Go | ||||
| // process. This includes memory stats. To collect those, runtime.ReadMemStats | ||||
| // is called. This causes a stop-the-world, which is very short with Go1.9+ | ||||
| // (~25µs). However, with older Go versions, the stop-the-world duration depends | ||||
| // on the heap size and can be quite significant (~1.7 ms/GiB as per | ||||
| // https://go-review.googlesource.com/c/go/+/34937). | ||||
| func NewGoCollector() Collector { | ||||
| 	return &goCollector{ | ||||
| 		goroutinesDesc: NewDesc( | ||||
| 			"go_goroutines", | ||||
| 			"Number of goroutines that currently exist.", | ||||
| 			nil, nil), | ||||
| 		threadsDesc: NewDesc( | ||||
| 			"go_threads", | ||||
| 			"Number of OS threads created.", | ||||
| 			nil, nil), | ||||
| 		gcDesc: NewDesc( | ||||
| 			"go_gc_duration_seconds", | ||||
| 			"A summary of the GC invocation durations.", | ||||
| 			nil, nil), | ||||
| 		goInfoDesc: NewDesc( | ||||
| 			"go_info", | ||||
| 			"Information about the Go environment.", | ||||
| 			nil, Labels{"version": runtime.Version()}), | ||||
| 		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 from system.", | ||||
| 					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"), | ||||
| 					"Number of heap bytes released to OS.", | ||||
| 					nil, nil, | ||||
| 				), | ||||
| 				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) }, | ||||
| 				valType: GaugeValue, | ||||
| 			}, { | ||||
| 				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) / 1e9 }, | ||||
| 				valType: GaugeValue, | ||||
| 			}, { | ||||
| 				desc: NewDesc( | ||||
| 					memstatNamespace("gc_cpu_fraction"), | ||||
| 					"The fraction of this program's available CPU time used by the GC since the program started.", | ||||
| 					nil, nil, | ||||
| 				), | ||||
| 				eval:    func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction }, | ||||
| 				valType: GaugeValue, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 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.goroutinesDesc | ||||
| 	ch <- c.threadsDesc | ||||
| 	ch <- c.gcDesc | ||||
| 	ch <- c.goInfoDesc | ||||
| 	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) { | ||||
| 	ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine())) | ||||
| 	n, _ := runtime.ThreadCreateProfile(nil) | ||||
| 	ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n)) | ||||
|  | ||||
| 	var stats debug.GCStats | ||||
| 	stats.PauseQuantiles = make([]time.Duration, 5) | ||||
| 	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), stats.PauseTotal.Seconds(), quantiles) | ||||
|  | ||||
| 	ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1) | ||||
|  | ||||
| 	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 | ||||
| } | ||||
							
								
								
									
										614
									
								
								vendor/github.com/prometheus/client_golang/prometheus/histogram.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										614
									
								
								vendor/github.com/prometheus/client_golang/prometheus/histogram.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,614 @@ | ||||
| // 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" | ||||
| 	"math" | ||||
| 	"runtime" | ||||
| 	"sort" | ||||
| 	"sync" | ||||
| 	"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" | ||||
|  | ||||
| // 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. | ||||
| var ( | ||||
| 	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 to a non-empty string. All other fields are optional | ||||
| // and can safely be left at their zero value, although it is strongly | ||||
| // encouraged to set a Help string. | ||||
| 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. | ||||
| 	// | ||||
| 	// 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. | ||||
| 	// | ||||
| 	// ConstLabels are only used rarely. In particular, do not use them to | ||||
| 	// attach the same labels to all your metrics. Those use cases are | ||||
| 	// better covered by target labels set by the scraping Prometheus | ||||
| 	// server, or by one specific metric (e.g. a build_info or a | ||||
| 	// machine_role metric). See also | ||||
| 	// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels | ||||
| 	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(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) | ||||
| 	} | ||||
|  | ||||
| 	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), | ||||
| 		counts:      [2]*histogramCounts{&histogramCounts{}, &histogramCounts{}}, | ||||
| 	} | ||||
| 	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 | ||||
| 	// for both states: | ||||
| 	h.counts[0].buckets = make([]uint64, len(h.upperBounds)) | ||||
| 	h.counts[1].buckets = make([]uint64, len(h.upperBounds)) | ||||
|  | ||||
| 	h.init(h) // Init self-collection. | ||||
| 	return h | ||||
| } | ||||
|  | ||||
| type histogramCounts 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 | ||||
| 	buckets []uint64 | ||||
| } | ||||
|  | ||||
| type histogram struct { | ||||
| 	// countAndHotIdx is a complicated one. For lock-free yet atomic | ||||
| 	// observations, we need to save the total count of observations again, | ||||
| 	// combined with the index of the currently-hot counts struct, so that | ||||
| 	// we can perform the operation on both values atomically. The least | ||||
| 	// significant bit defines the hot counts struct. The remaining 63 bits | ||||
| 	// represent the total count of observations. This happens under the | ||||
| 	// assumption that the 63bit count will never overflow. Rationale: An | ||||
| 	// observations takes about 30ns. Let's assume it could happen in | ||||
| 	// 10ns. Overflowing the counter will then take at least (2^63)*10ns, | ||||
| 	// which is about 3000 years. | ||||
| 	// | ||||
| 	// This has to be first in the struct for 64bit alignment. See | ||||
| 	// http://golang.org/pkg/sync/atomic/#pkg-note-BUG | ||||
| 	countAndHotIdx uint64 | ||||
|  | ||||
| 	selfCollector | ||||
| 	desc     *Desc | ||||
| 	writeMtx sync.Mutex // Only used in the Write method. | ||||
|  | ||||
| 	upperBounds []float64 | ||||
|  | ||||
| 	// Two counts, one is "hot" for lock-free observations, the other is | ||||
| 	// "cold" for writing out a dto.Metric. It has to be an array of | ||||
| 	// pointers to guarantee 64bit alignment of the histogramCounts, see | ||||
| 	// http://golang.org/pkg/sync/atomic/#pkg-note-BUG. | ||||
| 	counts [2]*histogramCounts | ||||
| 	hotIdx int // Index of currently-hot counts. Only used within Write. | ||||
|  | ||||
| 	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) | ||||
|  | ||||
| 	// We increment h.countAndHotIdx by 2 so that the counter in the upper | ||||
| 	// 63 bits gets incremented by 1. At the same time, we get the new value | ||||
| 	// back, which we can use to find the currently-hot counts. | ||||
| 	n := atomic.AddUint64(&h.countAndHotIdx, 2) | ||||
| 	hotCounts := h.counts[n%2] | ||||
|  | ||||
| 	if i < len(h.upperBounds) { | ||||
| 		atomic.AddUint64(&hotCounts.buckets[i], 1) | ||||
| 	} | ||||
| 	for { | ||||
| 		oldBits := atomic.LoadUint64(&hotCounts.sumBits) | ||||
| 		newBits := math.Float64bits(math.Float64frombits(oldBits) + v) | ||||
| 		if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	// Increment count last as we take it as a signal that the observation | ||||
| 	// is complete. | ||||
| 	atomic.AddUint64(&hotCounts.count, 1) | ||||
| } | ||||
|  | ||||
| func (h *histogram) Write(out *dto.Metric) error { | ||||
| 	var ( | ||||
| 		his                   = &dto.Histogram{} | ||||
| 		buckets               = make([]*dto.Bucket, len(h.upperBounds)) | ||||
| 		hotCounts, coldCounts *histogramCounts | ||||
| 		count                 uint64 | ||||
| 	) | ||||
|  | ||||
| 	// For simplicity, we mutex the rest of this method. It is not in the | ||||
| 	// hot path, i.e.  Observe is called much more often than Write. The | ||||
| 	// complication of making Write lock-free isn't worth it. | ||||
| 	h.writeMtx.Lock() | ||||
| 	defer h.writeMtx.Unlock() | ||||
|  | ||||
| 	// This is a bit arcane, which is why the following spells out this if | ||||
| 	// clause in English: | ||||
| 	// | ||||
| 	// If the currently-hot counts struct is #0, we atomically increment | ||||
| 	// h.countAndHotIdx by 1 so that from now on Observe will use the counts | ||||
| 	// struct #1. Furthermore, the atomic increment gives us the new value, | ||||
| 	// which, in its most significant 63 bits, tells us the count of | ||||
| 	// observations done so far up to and including currently ongoing | ||||
| 	// observations still using the counts struct just changed from hot to | ||||
| 	// cold. To have a normal uint64 for the count, we bitshift by 1 and | ||||
| 	// save the result in count. We also set h.hotIdx to 1 for the next | ||||
| 	// Write call, and we will refer to counts #1 as hotCounts and to counts | ||||
| 	// #0 as coldCounts. | ||||
| 	// | ||||
| 	// If the currently-hot counts struct is #1, we do the corresponding | ||||
| 	// things the other way round. We have to _decrement_ h.countAndHotIdx | ||||
| 	// (which is a bit arcane in itself, as we have to express -1 with an | ||||
| 	// unsigned int...). | ||||
| 	if h.hotIdx == 0 { | ||||
| 		count = atomic.AddUint64(&h.countAndHotIdx, 1) >> 1 | ||||
| 		h.hotIdx = 1 | ||||
| 		hotCounts = h.counts[1] | ||||
| 		coldCounts = h.counts[0] | ||||
| 	} else { | ||||
| 		count = atomic.AddUint64(&h.countAndHotIdx, ^uint64(0)) >> 1 // Decrement. | ||||
| 		h.hotIdx = 0 | ||||
| 		hotCounts = h.counts[0] | ||||
| 		coldCounts = h.counts[1] | ||||
| 	} | ||||
|  | ||||
| 	// Now we have to wait for the now-declared-cold counts to actually cool | ||||
| 	// down, i.e. wait for all observations still using it to finish. That's | ||||
| 	// the case once the count in the cold counts struct is the same as the | ||||
| 	// one atomically retrieved from the upper 63bits of h.countAndHotIdx. | ||||
| 	for { | ||||
| 		if count == atomic.LoadUint64(&coldCounts.count) { | ||||
| 			break | ||||
| 		} | ||||
| 		runtime.Gosched() // Let observations get work done. | ||||
| 	} | ||||
|  | ||||
| 	his.SampleCount = proto.Uint64(count) | ||||
| 	his.SampleSum = proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))) | ||||
| 	var cumCount uint64 | ||||
| 	for i, upperBound := range h.upperBounds { | ||||
| 		cumCount += atomic.LoadUint64(&coldCounts.buckets[i]) | ||||
| 		buckets[i] = &dto.Bucket{ | ||||
| 			CumulativeCount: proto.Uint64(cumCount), | ||||
| 			UpperBound:      proto.Float64(upperBound), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	his.Bucket = buckets | ||||
| 	out.Histogram = his | ||||
| 	out.Label = h.labelPairs | ||||
|  | ||||
| 	// Finally add all the cold counts to the new hot counts and reset the cold counts. | ||||
| 	atomic.AddUint64(&hotCounts.count, count) | ||||
| 	atomic.StoreUint64(&coldCounts.count, 0) | ||||
| 	for { | ||||
| 		oldBits := atomic.LoadUint64(&hotCounts.sumBits) | ||||
| 		newBits := math.Float64bits(math.Float64frombits(oldBits) + his.GetSampleSum()) | ||||
| 		if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { | ||||
| 			atomic.StoreUint64(&coldCounts.sumBits, 0) | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	for i := range h.upperBounds { | ||||
| 		atomic.AddUint64(&hotCounts.buckets[i], atomic.LoadUint64(&coldCounts.buckets[i])) | ||||
| 		atomic.StoreUint64(&coldCounts.buckets[i], 0) | ||||
| 	} | ||||
| 	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. | ||||
| func NewHistogramVec(opts HistogramOpts, labelNames []string) *HistogramVec { | ||||
| 	desc := NewDesc( | ||||
| 		BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), | ||||
| 		opts.Help, | ||||
| 		labelNames, | ||||
| 		opts.ConstLabels, | ||||
| 	) | ||||
| 	return &HistogramVec{ | ||||
| 		metricVec: newMetricVec(desc, func(lvs ...string) Metric { | ||||
| 			return newHistogram(desc, opts, lvs...) | ||||
| 		}), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetMetricWithLabelValues returns the Histogram 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 Histogram is created. | ||||
| // | ||||
| // It is possible to call this method without using the returned Histogram to only | ||||
| // create the new Histogram but leave it at its starting value, a Histogram without | ||||
| // any observations. | ||||
| // | ||||
| // Keeping the Histogram 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 Histogram from the HistogramVec. In that case, the | ||||
| // Histogram will still exist, but it will not be exported anymore, even if a | ||||
| // Histogram 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 (minus any curried labels). | ||||
| // | ||||
| // 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 (v *HistogramVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) { | ||||
| 	metric, err := v.metricVec.getMetricWithLabelValues(lvs...) | ||||
| 	if metric != nil { | ||||
| 		return metric.(Observer), err | ||||
| 	} | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| // GetMetricWith returns the Histogram 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 Histogram is created. Implications of | ||||
| // creating a Histogram without using it and keeping the Histogram 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 (minus any curried labels). | ||||
| // | ||||
| // This method is used for the same purpose as | ||||
| // GetMetricWithLabelValues(...string). See there for pros and cons of the two | ||||
| // methods. | ||||
| func (v *HistogramVec) GetMetricWith(labels Labels) (Observer, error) { | ||||
| 	metric, err := v.metricVec.getMetricWith(labels) | ||||
| 	if metric != nil { | ||||
| 		return metric.(Observer), err | ||||
| 	} | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| // WithLabelValues works as GetMetricWithLabelValues, but panics where | ||||
| // GetMetricWithLabelValues would have returned an error. Not returning an | ||||
| // error allows shortcuts like | ||||
| //     myVec.WithLabelValues("404", "GET").Observe(42.21) | ||||
| func (v *HistogramVec) WithLabelValues(lvs ...string) Observer { | ||||
| 	h, err := v.GetMetricWithLabelValues(lvs...) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return h | ||||
| } | ||||
|  | ||||
| // With works as GetMetricWith but panics where GetMetricWithLabels would have | ||||
| // returned an error. Not returning an error allows shortcuts like | ||||
| //     myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Observe(42.21) | ||||
| func (v *HistogramVec) With(labels Labels) Observer { | ||||
| 	h, err := v.GetMetricWith(labels) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return h | ||||
| } | ||||
|  | ||||
| // CurryWith returns a vector curried with the provided labels, i.e. the | ||||
| // returned vector has those labels pre-set for all labeled operations performed | ||||
| // on it. The cardinality of the curried vector is reduced accordingly. The | ||||
| // order of the remaining labels stays the same (just with the curried labels | ||||
| // taken out of the sequence – which is relevant for the | ||||
| // (GetMetric)WithLabelValues methods). It is possible to curry a curried | ||||
| // vector, but only with labels not yet used for currying before. | ||||
| // | ||||
| // The metrics contained in the HistogramVec are shared between the curried and | ||||
| // uncurried vectors. They are just accessed differently. Curried and uncurried | ||||
| // vectors behave identically in terms of collection. Only one must be | ||||
| // registered with a given registry (usually the uncurried version). The Reset | ||||
| // method deletes all metrics, even if called on a curried vector. | ||||
| func (v *HistogramVec) CurryWith(labels Labels) (ObserverVec, error) { | ||||
| 	vec, err := v.curryWith(labels) | ||||
| 	if vec != nil { | ||||
| 		return &HistogramVec{vec}, err | ||||
| 	} | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| // MustCurryWith works as CurryWith but panics where CurryWith would have | ||||
| // returned an error. | ||||
| func (v *HistogramVec) MustCurryWith(labels Labels) ObserverVec { | ||||
| 	vec, err := v.CurryWith(labels) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return vec | ||||
| } | ||||
|  | ||||
| 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 or if Desc is invalid. | ||||
| func NewConstHistogram( | ||||
| 	desc *Desc, | ||||
| 	count uint64, | ||||
| 	sum float64, | ||||
| 	buckets map[float64]uint64, | ||||
| 	labelValues ...string, | ||||
| ) (Metric, error) { | ||||
| 	if desc.err != nil { | ||||
| 		return nil, desc.err | ||||
| 	} | ||||
| 	if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	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() | ||||
| } | ||||
							
								
								
									
										504
									
								
								vendor/github.com/prometheus/client_golang/prometheus/http.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										504
									
								
								vendor/github.com/prometheus/client_golang/prometheus/http.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,504 @@ | ||||
| // 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" | ||||
| 	"compress/gzip" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/prometheus/common/expfmt" | ||||
| ) | ||||
|  | ||||
| // TODO(beorn7): Remove this whole file. It is a partial mirror of | ||||
| // promhttp/http.go (to avoid circular import chains) where everything HTTP | ||||
| // related should live. The functions here are just for avoiding | ||||
| // breakage. Everything is deprecated. | ||||
|  | ||||
| const ( | ||||
| 	contentTypeHeader     = "Content-Type" | ||||
| 	contentLengthHeader   = "Content-Length" | ||||
| 	contentEncodingHeader = "Content-Encoding" | ||||
| 	acceptEncodingHeader  = "Accept-Encoding" | ||||
| ) | ||||
|  | ||||
| var gzipPool = sync.Pool{ | ||||
| 	New: func() interface{} { | ||||
| 		return gzip.NewWriter(nil) | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| // Handler returns an HTTP handler for the DefaultGatherer. It is | ||||
| // already instrumented with InstrumentHandler (using "prometheus" as handler | ||||
| // name). | ||||
| // | ||||
| // Deprecated: Please note the issues described in the doc comment of | ||||
| // InstrumentHandler. You might want to consider using promhttp.Handler instead. | ||||
| func Handler() http.Handler { | ||||
| 	return InstrumentHandler("prometheus", UninstrumentedHandler()) | ||||
| } | ||||
|  | ||||
| // UninstrumentedHandler returns an HTTP handler for the DefaultGatherer. | ||||
| // | ||||
| // Deprecated: Use promhttp.HandlerFor(DefaultGatherer, promhttp.HandlerOpts{}) | ||||
| // instead. See there for further documentation. | ||||
| func UninstrumentedHandler() http.Handler { | ||||
| 	return http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { | ||||
| 		mfs, err := DefaultGatherer.Gather() | ||||
| 		if err != nil { | ||||
| 			httpError(rsp, err) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		contentType := expfmt.Negotiate(req.Header) | ||||
| 		header := rsp.Header() | ||||
| 		header.Set(contentTypeHeader, string(contentType)) | ||||
|  | ||||
| 		w := io.Writer(rsp) | ||||
| 		if gzipAccepted(req.Header) { | ||||
| 			header.Set(contentEncodingHeader, "gzip") | ||||
| 			gz := gzipPool.Get().(*gzip.Writer) | ||||
| 			defer gzipPool.Put(gz) | ||||
|  | ||||
| 			gz.Reset(w) | ||||
| 			defer gz.Close() | ||||
|  | ||||
| 			w = gz | ||||
| 		} | ||||
|  | ||||
| 		enc := expfmt.NewEncoder(w, contentType) | ||||
|  | ||||
| 		for _, mf := range mfs { | ||||
| 			if err := enc.Encode(mf); err != nil { | ||||
| 				httpError(rsp, err) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| 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() | ||||
| }) | ||||
|  | ||||
| // 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"). | ||||
| // | ||||
| // Deprecated: InstrumentHandler has several issues. Use the tooling provided in | ||||
| // package promhttp instead. The issues are the following: (1) It uses Summaries | ||||
| // rather than Histograms. Summaries are not useful if aggregation across | ||||
| // multiple instances is required. (2) It uses microseconds as unit, which is | ||||
| // deprecated and should be replaced by seconds. (3) The size of the request is | ||||
| // calculated in a separate goroutine. Since this calculator requires access to | ||||
| // the request header, it creates a race with any writes to the header performed | ||||
| // during request handling.  httputil.ReverseProxy is a prominent example for a | ||||
| // handler performing such writes. (4) It has additional issues with HTTP/2, cf. | ||||
| // https://github.com/prometheus/client_golang/issues/272. | ||||
| func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFunc { | ||||
| 	return InstrumentHandlerFunc(handlerName, handler.ServeHTTP) | ||||
| } | ||||
|  | ||||
| // InstrumentHandlerFunc wraps the given function for instrumentation. It | ||||
| // otherwise works in the same way as InstrumentHandler (and shares the same | ||||
| // issues). | ||||
| // | ||||
| // Deprecated: InstrumentHandlerFunc is deprecated for the same reasons as | ||||
| // InstrumentHandler is. Use the tooling provided in package promhttp instead. | ||||
| func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc { | ||||
| 	return InstrumentHandlerFuncWithOpts( | ||||
| 		SummaryOpts{ | ||||
| 			Subsystem:   "http", | ||||
| 			ConstLabels: Labels{"handler": handlerName}, | ||||
| 			Objectives:  map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, | ||||
| 		}, | ||||
| 		handlerFunc, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| // InstrumentHandlerWithOpts works like InstrumentHandler (and shares the same | ||||
| // issues) 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. | ||||
| // | ||||
| // Deprecated: InstrumentHandlerWithOpts is deprecated for the same reasons as | ||||
| // InstrumentHandler is. Use the tooling provided in package promhttp instead. | ||||
| func InstrumentHandlerWithOpts(opts SummaryOpts, handler http.Handler) http.HandlerFunc { | ||||
| 	return InstrumentHandlerFuncWithOpts(opts, handler.ServeHTTP) | ||||
| } | ||||
|  | ||||
| // InstrumentHandlerFuncWithOpts works like InstrumentHandlerFunc (and shares | ||||
| // the same issues) but provides more flexibility (at the cost of a more complex | ||||
| // call syntax). See InstrumentHandlerWithOpts for details how the provided | ||||
| // SummaryOpts are used. | ||||
| // | ||||
| // Deprecated: InstrumentHandlerFuncWithOpts is deprecated for the same reasons | ||||
| // as InstrumentHandler is. Use the tooling provided in package promhttp instead. | ||||
| func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc { | ||||
| 	reqCnt := NewCounterVec( | ||||
| 		CounterOpts{ | ||||
| 			Namespace:   opts.Namespace, | ||||
| 			Subsystem:   opts.Subsystem, | ||||
| 			Name:        "requests_total", | ||||
| 			Help:        "Total number of HTTP requests made.", | ||||
| 			ConstLabels: opts.ConstLabels, | ||||
| 		}, | ||||
| 		instLabels, | ||||
| 	) | ||||
| 	if err := Register(reqCnt); err != nil { | ||||
| 		if are, ok := err.(AlreadyRegisteredError); ok { | ||||
| 			reqCnt = are.ExistingCollector.(*CounterVec) | ||||
| 		} else { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	opts.Name = "request_duration_microseconds" | ||||
| 	opts.Help = "The HTTP request latencies in microseconds." | ||||
| 	reqDur := NewSummary(opts) | ||||
| 	if err := Register(reqDur); err != nil { | ||||
| 		if are, ok := err.(AlreadyRegisteredError); ok { | ||||
| 			reqDur = are.ExistingCollector.(Summary) | ||||
| 		} else { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	opts.Name = "request_size_bytes" | ||||
| 	opts.Help = "The HTTP request sizes in bytes." | ||||
| 	reqSz := NewSummary(opts) | ||||
| 	if err := Register(reqSz); err != nil { | ||||
| 		if are, ok := err.(AlreadyRegisteredError); ok { | ||||
| 			reqSz = are.ExistingCollector.(Summary) | ||||
| 		} else { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	opts.Name = "response_size_bytes" | ||||
| 	opts.Help = "The HTTP response sizes in bytes." | ||||
| 	resSz := NewSummary(opts) | ||||
| 	if err := Register(resSz); err != nil { | ||||
| 		if are, ok := err.(AlreadyRegisteredError); ok { | ||||
| 			resSz = are.ExistingCollector.(Summary) | ||||
| 		} else { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		now := time.Now() | ||||
|  | ||||
| 		delegate := &responseWriterDelegator{ResponseWriter: w} | ||||
| 		out := computeApproximateRequestSize(r) | ||||
|  | ||||
| 		_, 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) | ||||
| 		reqCnt.WithLabelValues(method, code).Inc() | ||||
| 		reqDur.Observe(elapsed) | ||||
| 		resSz.Observe(float64(delegate.written)) | ||||
| 		reqSz.Observe(float64(<-out)) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func computeApproximateRequestSize(r *http.Request) <-chan int { | ||||
| 	// Get URL length in current goroutine for avoiding a race condition. | ||||
| 	// HandlerFunc that runs in parallel may modify the URL. | ||||
| 	s := 0 | ||||
| 	if r.URL != nil { | ||||
| 		s += len(r.URL.String()) | ||||
| 	} | ||||
|  | ||||
| 	out := make(chan int, 1) | ||||
|  | ||||
| 	go func() { | ||||
| 		s += len(r.Method) | ||||
| 		s += len(r.Proto) | ||||
| 		for name, values := range r.Header { | ||||
| 			s += len(name) | ||||
| 			for _, value := range values { | ||||
| 				s += len(value) | ||||
| 			} | ||||
| 		} | ||||
| 		s += len(r.Host) | ||||
|  | ||||
| 		// 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 | ||||
| 		close(out) | ||||
| 	}() | ||||
|  | ||||
| 	return out | ||||
| } | ||||
|  | ||||
| type responseWriterDelegator struct { | ||||
| 	http.ResponseWriter | ||||
|  | ||||
| 	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) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // gzipAccepted returns whether the client will accept gzip-encoded content. | ||||
| func gzipAccepted(header http.Header) bool { | ||||
| 	a := header.Get(acceptEncodingHeader) | ||||
| 	parts := strings.Split(a, ",") | ||||
| 	for _, part := range parts { | ||||
| 		part = strings.TrimSpace(part) | ||||
| 		if part == "gzip" || strings.HasPrefix(part, "gzip;") { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // httpError removes any content-encoding header and then calls http.Error with | ||||
| // the provided error and http.StatusInternalServerErrer. Error contents is | ||||
| // supposed to be uncompressed plain text. However, same as with a plain | ||||
| // http.Error, any header settings will be void if the header has already been | ||||
| // sent. The error message will still be written to the writer, but it will | ||||
| // probably be of limited use. | ||||
| func httpError(rsp http.ResponseWriter, err error) { | ||||
| 	rsp.Header().Del(contentEncodingHeader) | ||||
| 	http.Error( | ||||
| 		rsp, | ||||
| 		"An error has occurred while serving metrics:\n\n"+err.Error(), | ||||
| 		http.StatusInternalServerError, | ||||
| 	) | ||||
| } | ||||
							
								
								
									
										85
									
								
								vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								vendor/github.com/prometheus/client_golang/prometheus/internal/metric.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| // Copyright 2018 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 internal | ||||
|  | ||||
| import ( | ||||
| 	"sort" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| // metricSorter is a sortable slice of *dto.Metric. | ||||
| 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 | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// We should never arrive here. Multiple metrics with the same | ||||
| 	// label set in the same scrape will lead to undefined ingestion | ||||
| 	// behavior. However, as above, we have to provide stable sorting | ||||
| 	// here, even for inconsistent metrics. So sort equal metrics | ||||
| 	// by their timestamp, with missing timestamps (implying "now") | ||||
| 	// coming last. | ||||
| 	if s[i].TimestampMs == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	if s[j].TimestampMs == nil { | ||||
| 		return true | ||||
| 	} | ||||
| 	return s[i].GetTimestampMs() < s[j].GetTimestampMs() | ||||
| } | ||||
|  | ||||
| // NormalizeMetricFamilies returns a MetricFamily slice with empty | ||||
| // MetricFamilies pruned and the remaining MetricFamilies sorted by name within | ||||
| // the slice, with the contained Metrics sorted within each MetricFamily. | ||||
| func NormalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily { | ||||
| 	for _, mf := range metricFamiliesByName { | ||||
| 		sort.Sort(metricSorter(mf.Metric)) | ||||
| 	} | ||||
| 	names := make([]string, 0, len(metricFamiliesByName)) | ||||
| 	for name, mf := range metricFamiliesByName { | ||||
| 		if len(mf.Metric) > 0 { | ||||
| 			names = append(names, name) | ||||
| 		} | ||||
| 	} | ||||
| 	sort.Strings(names) | ||||
| 	result := make([]*dto.MetricFamily, 0, len(names)) | ||||
| 	for _, name := range names { | ||||
| 		result = append(result, metricFamiliesByName[name]) | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
							
								
								
									
										87
									
								
								vendor/github.com/prometheus/client_golang/prometheus/labels.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								vendor/github.com/prometheus/client_golang/prometheus/labels.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| // Copyright 2018 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" | ||||
| 	"strings" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/prometheus/common/model" | ||||
| ) | ||||
|  | ||||
| // 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 | ||||
|  | ||||
| // reservedLabelPrefix is a prefix which is not legal in user-supplied | ||||
| // label names. | ||||
| const reservedLabelPrefix = "__" | ||||
|  | ||||
| var errInconsistentCardinality = errors.New("inconsistent label cardinality") | ||||
|  | ||||
| func makeInconsistentCardinalityError(fqName string, labels, labelValues []string) error { | ||||
| 	return fmt.Errorf( | ||||
| 		"%s: %q has %d variable labels named %q but %d values %q were provided", | ||||
| 		errInconsistentCardinality, fqName, | ||||
| 		len(labels), labels, | ||||
| 		len(labelValues), labelValues, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { | ||||
| 	if len(labels) != expectedNumberOfValues { | ||||
| 		return fmt.Errorf( | ||||
| 			"%s: expected %d label values but got %d in %#v", | ||||
| 			errInconsistentCardinality, expectedNumberOfValues, | ||||
| 			len(labels), labels, | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	for name, val := range labels { | ||||
| 		if !utf8.ValidString(val) { | ||||
| 			return fmt.Errorf("label %s: value %q is not valid UTF-8", name, val) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func validateLabelValues(vals []string, expectedNumberOfValues int) error { | ||||
| 	if len(vals) != expectedNumberOfValues { | ||||
| 		return fmt.Errorf( | ||||
| 			"%s: expected %d label values but got %d in %#v", | ||||
| 			errInconsistentCardinality, expectedNumberOfValues, | ||||
| 			len(vals), vals, | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	for _, val := range vals { | ||||
| 		if !utf8.ValidString(val) { | ||||
| 			return fmt.Errorf("label value %q is not valid UTF-8", val) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func checkLabelName(l string) bool { | ||||
| 	return model.LabelName(l).IsValid() && !strings.HasPrefix(l, reservedLabelPrefix) | ||||
| } | ||||
							
								
								
									
										174
									
								
								vendor/github.com/prometheus/client_golang/prometheus/metric.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								vendor/github.com/prometheus/client_golang/prometheus/metric.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | ||||
| // 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" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
|  | ||||
| 	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. Implementations of Metric in this package are Gauge, Counter, | ||||
| // Histogram, Summary, and Untyped. | ||||
| 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. | ||||
| 	// | ||||
| 	// Metric implementations 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. | ||||
| 	// | ||||
| 	// While populating dto.Metric, it is the responsibility of the | ||||
| 	// implementation to ensure validity of the Metric protobuf (like valid | ||||
| 	// UTF-8 strings or syntactically valid metric and label names). It is | ||||
| 	// recommended to sort labels lexicographically. Callers of Write should | ||||
| 	// still make sure of sorting if they depend on it. | ||||
| 	Write(*dto.Metric) error | ||||
| 	// TODO(beorn7): The original rationale of passing in a pre-allocated | ||||
| 	// dto.Metric protobuf to save allocations has disappeared. The | ||||
| 	// signature of this method should be changed to "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 to a non-empty string. All other fields are | ||||
| // optional and can safely be left at their zero value, although it is strongly | ||||
| // encouraged to set a Help string. | ||||
| 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. | ||||
| 	// | ||||
| 	// 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. | ||||
| 	// | ||||
| 	// ConstLabels are only used rarely. In particular, do not use them to | ||||
| 	// attach the same labels to all your metrics. Those use cases are | ||||
| 	// better covered by target labels set by the scraping Prometheus | ||||
| 	// server, or by one specific metric (e.g. a build_info or a | ||||
| 	// machine_role metric). See also | ||||
| 	// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels | ||||
| 	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. | ||||
| 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 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 } | ||||
|  | ||||
| type timestampedMetric struct { | ||||
| 	Metric | ||||
| 	t time.Time | ||||
| } | ||||
|  | ||||
| func (m timestampedMetric) Write(pb *dto.Metric) error { | ||||
| 	e := m.Metric.Write(pb) | ||||
| 	pb.TimestampMs = proto.Int64(m.t.Unix()*1000 + int64(m.t.Nanosecond()/1000000)) | ||||
| 	return e | ||||
| } | ||||
|  | ||||
| // NewMetricWithTimestamp returns a new Metric wrapping the provided Metric in a | ||||
| // way that it has an explicit timestamp set to the provided Time. This is only | ||||
| // useful in rare cases as the timestamp of a Prometheus metric should usually | ||||
| // be set by the Prometheus server during scraping. Exceptions include mirroring | ||||
| // metrics with given timestamps from other metric | ||||
| // sources. | ||||
| // | ||||
| // NewMetricWithTimestamp works best with MustNewConstMetric, | ||||
| // MustNewConstHistogram, and MustNewConstSummary, see example. | ||||
| // | ||||
| // Currently, the exposition formats used by Prometheus are limited to | ||||
| // millisecond resolution. Thus, the provided time will be rounded down to the | ||||
| // next full millisecond value. | ||||
| func NewMetricWithTimestamp(t time.Time, m Metric) Metric { | ||||
| 	return timestampedMetric{Metric: m, t: t} | ||||
| } | ||||
							
								
								
									
										52
									
								
								vendor/github.com/prometheus/client_golang/prometheus/observer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/prometheus/client_golang/prometheus/observer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package prometheus | ||||
|  | ||||
| // Observer is the interface that wraps the Observe method, which is used by | ||||
| // Histogram and Summary to add observations. | ||||
| type Observer interface { | ||||
| 	Observe(float64) | ||||
| } | ||||
|  | ||||
| // The ObserverFunc type is an adapter to allow the use of ordinary | ||||
| // functions as Observers. If f is a function with the appropriate | ||||
| // signature, ObserverFunc(f) is an Observer that calls f. | ||||
| // | ||||
| // This adapter is usually used in connection with the Timer type, and there are | ||||
| // two general use cases: | ||||
| // | ||||
| // The most common one is to use a Gauge as the Observer for a Timer. | ||||
| // See the "Gauge" Timer example. | ||||
| // | ||||
| // The more advanced use case is to create a function that dynamically decides | ||||
| // which Observer to use for observing the duration. See the "Complex" Timer | ||||
| // example. | ||||
| type ObserverFunc func(float64) | ||||
|  | ||||
| // Observe calls f(value). It implements Observer. | ||||
| func (f ObserverFunc) Observe(value float64) { | ||||
| 	f(value) | ||||
| } | ||||
|  | ||||
| // ObserverVec is an interface implemented by `HistogramVec` and `SummaryVec`. | ||||
| type ObserverVec interface { | ||||
| 	GetMetricWith(Labels) (Observer, error) | ||||
| 	GetMetricWithLabelValues(lvs ...string) (Observer, error) | ||||
| 	With(Labels) Observer | ||||
| 	WithLabelValues(...string) Observer | ||||
| 	CurryWith(Labels) (ObserverVec, error) | ||||
| 	MustCurryWith(Labels) ObserverVec | ||||
|  | ||||
| 	Collector | ||||
| } | ||||
							
								
								
									
										204
									
								
								vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								vendor/github.com/prometheus/client_golang/prometheus/process_collector.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | ||||
| // 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 ( | ||||
| 	"errors" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/prometheus/procfs" | ||||
| ) | ||||
|  | ||||
| type processCollector struct { | ||||
| 	collectFn       func(chan<- Metric) | ||||
| 	pidFn           func() (int, error) | ||||
| 	reportErrors    bool | ||||
| 	cpuTotal        *Desc | ||||
| 	openFDs, maxFDs *Desc | ||||
| 	vsize, maxVsize *Desc | ||||
| 	rss             *Desc | ||||
| 	startTime       *Desc | ||||
| } | ||||
|  | ||||
| // ProcessCollectorOpts defines the behavior of a process metrics collector | ||||
| // created with NewProcessCollector. | ||||
| type ProcessCollectorOpts struct { | ||||
| 	// PidFn returns the PID of the process the collector collects metrics | ||||
| 	// for. It is called upon each collection. By default, the PID of the | ||||
| 	// current process is used, as determined on construction time by | ||||
| 	// calling os.Getpid(). | ||||
| 	PidFn func() (int, error) | ||||
| 	// If non-empty, each of the collected metrics is prefixed by the | ||||
| 	// provided string and an underscore ("_"). | ||||
| 	Namespace string | ||||
| 	// If true, any error encountered during collection is reported as an | ||||
| 	// invalid metric (see NewInvalidMetric). Otherwise, errors are ignored | ||||
| 	// and the collected metrics will be incomplete. (Possibly, no metrics | ||||
| 	// will be collected at all.) While that's usually not desired, it is | ||||
| 	// appropriate for the common "mix-in" of process metrics, where process | ||||
| 	// metrics are nice to have, but failing to collect them should not | ||||
| 	// disrupt the collection of the remaining metrics. | ||||
| 	ReportErrors bool | ||||
| } | ||||
|  | ||||
| // 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. The detailed behavior is defined by the provided | ||||
| // ProcessCollectorOpts. The zero value of ProcessCollectorOpts creates a | ||||
| // collector for the current process with an empty namespace string and no error | ||||
| // reporting. | ||||
| // | ||||
| // Currently, the collector depends on a Linux-style proc filesystem and | ||||
| // therefore only exports metrics for Linux. | ||||
| // | ||||
| // Note: An older version of this function had the following signature: | ||||
| // | ||||
| //     NewProcessCollector(pid int, namespace string) Collector | ||||
| // | ||||
| // Most commonly, it was called as | ||||
| // | ||||
| //     NewProcessCollector(os.Getpid(), "") | ||||
| // | ||||
| // The following call of the current version is equivalent to the above: | ||||
| // | ||||
| //     NewProcessCollector(ProcessCollectorOpts{}) | ||||
| func NewProcessCollector(opts ProcessCollectorOpts) Collector { | ||||
| 	ns := "" | ||||
| 	if len(opts.Namespace) > 0 { | ||||
| 		ns = opts.Namespace + "_" | ||||
| 	} | ||||
|  | ||||
| 	c := &processCollector{ | ||||
| 		reportErrors: opts.ReportErrors, | ||||
| 		cpuTotal: NewDesc( | ||||
| 			ns+"process_cpu_seconds_total", | ||||
| 			"Total user and system CPU time spent in seconds.", | ||||
| 			nil, nil, | ||||
| 		), | ||||
| 		openFDs: NewDesc( | ||||
| 			ns+"process_open_fds", | ||||
| 			"Number of open file descriptors.", | ||||
| 			nil, nil, | ||||
| 		), | ||||
| 		maxFDs: NewDesc( | ||||
| 			ns+"process_max_fds", | ||||
| 			"Maximum number of open file descriptors.", | ||||
| 			nil, nil, | ||||
| 		), | ||||
| 		vsize: NewDesc( | ||||
| 			ns+"process_virtual_memory_bytes", | ||||
| 			"Virtual memory size in bytes.", | ||||
| 			nil, nil, | ||||
| 		), | ||||
| 		maxVsize: NewDesc( | ||||
| 			ns+"process_virtual_memory_max_bytes", | ||||
| 			"Maximum amount of virtual memory available in bytes.", | ||||
| 			nil, nil, | ||||
| 		), | ||||
| 		rss: NewDesc( | ||||
| 			ns+"process_resident_memory_bytes", | ||||
| 			"Resident memory size in bytes.", | ||||
| 			nil, nil, | ||||
| 		), | ||||
| 		startTime: NewDesc( | ||||
| 			ns+"process_start_time_seconds", | ||||
| 			"Start time of the process since unix epoch in seconds.", | ||||
| 			nil, nil, | ||||
| 		), | ||||
| 	} | ||||
|  | ||||
| 	if opts.PidFn == nil { | ||||
| 		pid := os.Getpid() | ||||
| 		c.pidFn = func() (int, error) { return pid, nil } | ||||
| 	} else { | ||||
| 		c.pidFn = opts.PidFn | ||||
| 	} | ||||
|  | ||||
| 	// Set up process metric collection if supported by the runtime. | ||||
| 	if _, err := procfs.NewStat(); err == nil { | ||||
| 		c.collectFn = c.processCollect | ||||
| 	} else { | ||||
| 		c.collectFn = func(ch chan<- Metric) { | ||||
| 			c.reportError(ch, nil, errors.New("process metrics not supported on this platform")) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return c | ||||
| } | ||||
|  | ||||
| // Describe returns all descriptions of the collector. | ||||
| func (c *processCollector) Describe(ch chan<- *Desc) { | ||||
| 	ch <- c.cpuTotal | ||||
| 	ch <- c.openFDs | ||||
| 	ch <- c.maxFDs | ||||
| 	ch <- c.vsize | ||||
| 	ch <- c.maxVsize | ||||
| 	ch <- c.rss | ||||
| 	ch <- c.startTime | ||||
| } | ||||
|  | ||||
| // Collect returns the current state of all metrics of the collector. | ||||
| func (c *processCollector) Collect(ch chan<- Metric) { | ||||
| 	c.collectFn(ch) | ||||
| } | ||||
|  | ||||
| func (c *processCollector) processCollect(ch chan<- Metric) { | ||||
| 	pid, err := c.pidFn() | ||||
| 	if err != nil { | ||||
| 		c.reportError(ch, nil, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	p, err := procfs.NewProc(pid) | ||||
| 	if err != nil { | ||||
| 		c.reportError(ch, nil, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if stat, err := p.NewStat(); err == nil { | ||||
| 		ch <- MustNewConstMetric(c.cpuTotal, CounterValue, stat.CPUTime()) | ||||
| 		ch <- MustNewConstMetric(c.vsize, GaugeValue, float64(stat.VirtualMemory())) | ||||
| 		ch <- MustNewConstMetric(c.rss, GaugeValue, float64(stat.ResidentMemory())) | ||||
| 		if startTime, err := stat.StartTime(); err == nil { | ||||
| 			ch <- MustNewConstMetric(c.startTime, GaugeValue, startTime) | ||||
| 		} else { | ||||
| 			c.reportError(ch, c.startTime, err) | ||||
| 		} | ||||
| 	} else { | ||||
| 		c.reportError(ch, nil, err) | ||||
| 	} | ||||
|  | ||||
| 	if fds, err := p.FileDescriptorsLen(); err == nil { | ||||
| 		ch <- MustNewConstMetric(c.openFDs, GaugeValue, float64(fds)) | ||||
| 	} else { | ||||
| 		c.reportError(ch, c.openFDs, err) | ||||
| 	} | ||||
|  | ||||
| 	if limits, err := p.NewLimits(); err == nil { | ||||
| 		ch <- MustNewConstMetric(c.maxFDs, GaugeValue, float64(limits.OpenFiles)) | ||||
| 		ch <- MustNewConstMetric(c.maxVsize, GaugeValue, float64(limits.AddressSpace)) | ||||
| 	} else { | ||||
| 		c.reportError(ch, nil, err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *processCollector) reportError(ch chan<- Metric, desc *Desc, err error) { | ||||
| 	if !c.reportErrors { | ||||
| 		return | ||||
| 	} | ||||
| 	if desc == nil { | ||||
| 		desc = NewInvalidDesc(err) | ||||
| 	} | ||||
| 	ch <- NewInvalidMetric(desc, err) | ||||
| } | ||||
							
								
								
									
										199
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	closeNotifier = 1 << iota | ||||
| 	flusher | ||||
| 	hijacker | ||||
| 	readerFrom | ||||
| 	pusher | ||||
| ) | ||||
|  | ||||
| type delegator interface { | ||||
| 	http.ResponseWriter | ||||
|  | ||||
| 	Status() int | ||||
| 	Written() int64 | ||||
| } | ||||
|  | ||||
| type responseWriterDelegator struct { | ||||
| 	http.ResponseWriter | ||||
|  | ||||
| 	handler, method    string | ||||
| 	status             int | ||||
| 	written            int64 | ||||
| 	wroteHeader        bool | ||||
| 	observeWriteHeader func(int) | ||||
| } | ||||
|  | ||||
| func (r *responseWriterDelegator) Status() int { | ||||
| 	return r.status | ||||
| } | ||||
|  | ||||
| func (r *responseWriterDelegator) Written() int64 { | ||||
| 	return r.written | ||||
| } | ||||
|  | ||||
| func (r *responseWriterDelegator) WriteHeader(code int) { | ||||
| 	r.status = code | ||||
| 	r.wroteHeader = true | ||||
| 	r.ResponseWriter.WriteHeader(code) | ||||
| 	if r.observeWriteHeader != nil { | ||||
| 		r.observeWriteHeader(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 closeNotifierDelegator struct{ *responseWriterDelegator } | ||||
| type flusherDelegator struct{ *responseWriterDelegator } | ||||
| type hijackerDelegator struct{ *responseWriterDelegator } | ||||
| type readerFromDelegator struct{ *responseWriterDelegator } | ||||
|  | ||||
| func (d closeNotifierDelegator) CloseNotify() <-chan bool { | ||||
| 	return d.ResponseWriter.(http.CloseNotifier).CloseNotify() | ||||
| } | ||||
| func (d flusherDelegator) Flush() { | ||||
| 	d.ResponseWriter.(http.Flusher).Flush() | ||||
| } | ||||
| func (d hijackerDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) { | ||||
| 	return d.ResponseWriter.(http.Hijacker).Hijack() | ||||
| } | ||||
| func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) { | ||||
| 	if !d.wroteHeader { | ||||
| 		d.WriteHeader(http.StatusOK) | ||||
| 	} | ||||
| 	n, err := d.ResponseWriter.(io.ReaderFrom).ReadFrom(re) | ||||
| 	d.written += n | ||||
| 	return n, err | ||||
| } | ||||
|  | ||||
| var pickDelegator = make([]func(*responseWriterDelegator) delegator, 32) | ||||
|  | ||||
| func init() { | ||||
| 	// TODO(beorn7): Code generation would help here. | ||||
| 	pickDelegator[0] = func(d *responseWriterDelegator) delegator { // 0 | ||||
| 		return d | ||||
| 	} | ||||
| 	pickDelegator[closeNotifier] = func(d *responseWriterDelegator) delegator { // 1 | ||||
| 		return closeNotifierDelegator{d} | ||||
| 	} | ||||
| 	pickDelegator[flusher] = func(d *responseWriterDelegator) delegator { // 2 | ||||
| 		return flusherDelegator{d} | ||||
| 	} | ||||
| 	pickDelegator[flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 3 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[hijacker] = func(d *responseWriterDelegator) delegator { // 4 | ||||
| 		return hijackerDelegator{d} | ||||
| 	} | ||||
| 	pickDelegator[hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 5 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Hijacker | ||||
| 			http.CloseNotifier | ||||
| 		}{d, hijackerDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 6 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 		}{d, hijackerDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 7 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom] = func(d *responseWriterDelegator) delegator { // 8 | ||||
| 		return readerFromDelegator{d} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 9 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			io.ReaderFrom | ||||
| 			http.CloseNotifier | ||||
| 		}{d, readerFromDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 10 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			io.ReaderFrom | ||||
| 			http.Flusher | ||||
| 		}{d, readerFromDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 11 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			io.ReaderFrom | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 12 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 		}{d, readerFromDelegator{d}, hijackerDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 13 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.CloseNotifier | ||||
| 		}{d, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 14 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 		}{d, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 15 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										181
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| // +build go1.8 | ||||
|  | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| type pusherDelegator struct{ *responseWriterDelegator } | ||||
|  | ||||
| func (d pusherDelegator) Push(target string, opts *http.PushOptions) error { | ||||
| 	return d.ResponseWriter.(http.Pusher).Push(target, opts) | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	pickDelegator[pusher] = func(d *responseWriterDelegator) delegator { // 16 | ||||
| 		return pusherDelegator{d} | ||||
| 	} | ||||
| 	pickDelegator[pusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 17 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+flusher] = func(d *responseWriterDelegator) delegator { // 18 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Flusher | ||||
| 		}{d, pusherDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 19 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker] = func(d *responseWriterDelegator) delegator { // 20 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 		}{d, pusherDelegator{d}, hijackerDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 21 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 22 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 		}{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { //23 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom] = func(d *responseWriterDelegator) delegator { // 24 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 25 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 26 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Flusher | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 27 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 28 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 29 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 30 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}} | ||||
| 	} | ||||
| 	pickDelegator[pusher+readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 31 | ||||
| 		return struct { | ||||
| 			*responseWriterDelegator | ||||
| 			http.Pusher | ||||
| 			io.ReaderFrom | ||||
| 			http.Hijacker | ||||
| 			http.Flusher | ||||
| 			http.CloseNotifier | ||||
| 		}{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator { | ||||
| 	d := &responseWriterDelegator{ | ||||
| 		ResponseWriter:     w, | ||||
| 		observeWriteHeader: observeWriteHeaderFunc, | ||||
| 	} | ||||
|  | ||||
| 	id := 0 | ||||
| 	if _, ok := w.(http.CloseNotifier); ok { | ||||
| 		id += closeNotifier | ||||
| 	} | ||||
| 	if _, ok := w.(http.Flusher); ok { | ||||
| 		id += flusher | ||||
| 	} | ||||
| 	if _, ok := w.(http.Hijacker); ok { | ||||
| 		id += hijacker | ||||
| 	} | ||||
| 	if _, ok := w.(io.ReaderFrom); ok { | ||||
| 		id += readerFrom | ||||
| 	} | ||||
| 	if _, ok := w.(http.Pusher); ok { | ||||
| 		id += pusher | ||||
| 	} | ||||
|  | ||||
| 	return pickDelegator[id](d) | ||||
| } | ||||
							
								
								
									
										44
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| // +build !go1.8 | ||||
|  | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator { | ||||
| 	d := &responseWriterDelegator{ | ||||
| 		ResponseWriter:     w, | ||||
| 		observeWriteHeader: observeWriteHeaderFunc, | ||||
| 	} | ||||
|  | ||||
| 	id := 0 | ||||
| 	if _, ok := w.(http.CloseNotifier); ok { | ||||
| 		id += closeNotifier | ||||
| 	} | ||||
| 	if _, ok := w.(http.Flusher); ok { | ||||
| 		id += flusher | ||||
| 	} | ||||
| 	if _, ok := w.(http.Hijacker); ok { | ||||
| 		id += hijacker | ||||
| 	} | ||||
| 	if _, ok := w.(io.ReaderFrom); ok { | ||||
| 		id += readerFrom | ||||
| 	} | ||||
|  | ||||
| 	return pickDelegator[id](d) | ||||
| } | ||||
							
								
								
									
										311
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,311 @@ | ||||
| // Copyright 2016 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| // Package promhttp provides tooling around HTTP servers and clients. | ||||
| // | ||||
| // First, the package allows the creation of http.Handler instances to expose | ||||
| // Prometheus metrics via HTTP. promhttp.Handler acts on the | ||||
| // prometheus.DefaultGatherer. With HandlerFor, you can create a handler for a | ||||
| // custom registry or anything that implements the Gatherer interface. It also | ||||
| // allows the creation of handlers that act differently on errors or allow to | ||||
| // log errors. | ||||
| // | ||||
| // Second, the package provides tooling to instrument instances of http.Handler | ||||
| // via middleware. Middleware wrappers follow the naming scheme | ||||
| // InstrumentHandlerX, where X describes the intended use of the middleware. | ||||
| // See each function's doc comment for specific details. | ||||
| // | ||||
| // Finally, the package allows for an http.RoundTripper to be instrumented via | ||||
| // middleware. Middleware wrappers follow the naming scheme | ||||
| // InstrumentRoundTripperX, where X describes the intended use of the | ||||
| // middleware. See each function's doc comment for specific details. | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"compress/gzip" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/prometheus/common/expfmt" | ||||
|  | ||||
| 	"github.com/prometheus/client_golang/prometheus" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	contentTypeHeader     = "Content-Type" | ||||
| 	contentLengthHeader   = "Content-Length" | ||||
| 	contentEncodingHeader = "Content-Encoding" | ||||
| 	acceptEncodingHeader  = "Accept-Encoding" | ||||
| ) | ||||
|  | ||||
| var gzipPool = sync.Pool{ | ||||
| 	New: func() interface{} { | ||||
| 		return gzip.NewWriter(nil) | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| // Handler returns an http.Handler for the prometheus.DefaultGatherer, using | ||||
| // default HandlerOpts, i.e. it reports the first error as an HTTP error, it has | ||||
| // no error logging, and it applies compression if requested by the client. | ||||
| // | ||||
| // The returned http.Handler is already instrumented using the | ||||
| // InstrumentMetricHandler function and the prometheus.DefaultRegisterer. If you | ||||
| // create multiple http.Handlers by separate calls of the Handler function, the | ||||
| // metrics used for instrumentation will be shared between them, providing | ||||
| // global scrape counts. | ||||
| // | ||||
| // This function is meant to cover the bulk of basic use cases. If you are doing | ||||
| // anything that requires more customization (including using a non-default | ||||
| // Gatherer, different instrumentation, and non-default HandlerOpts), use the | ||||
| // HandlerFor function. See there for details. | ||||
| func Handler() http.Handler { | ||||
| 	return InstrumentMetricHandler( | ||||
| 		prometheus.DefaultRegisterer, HandlerFor(prometheus.DefaultGatherer, HandlerOpts{}), | ||||
| 	) | ||||
| } | ||||
|  | ||||
| // HandlerFor returns an uninstrumented http.Handler for the provided | ||||
| // Gatherer. The behavior of the Handler is defined by the provided | ||||
| // HandlerOpts. Thus, HandlerFor is useful to create http.Handlers for custom | ||||
| // Gatherers, with non-default HandlerOpts, and/or with custom (or no) | ||||
| // instrumentation. Use the InstrumentMetricHandler function to apply the same | ||||
| // kind of instrumentation as it is used by the Handler function. | ||||
| func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { | ||||
| 	var inFlightSem chan struct{} | ||||
| 	if opts.MaxRequestsInFlight > 0 { | ||||
| 		inFlightSem = make(chan struct{}, opts.MaxRequestsInFlight) | ||||
| 	} | ||||
|  | ||||
| 	h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { | ||||
| 		if inFlightSem != nil { | ||||
| 			select { | ||||
| 			case inFlightSem <- struct{}{}: // All good, carry on. | ||||
| 				defer func() { <-inFlightSem }() | ||||
| 			default: | ||||
| 				http.Error(rsp, fmt.Sprintf( | ||||
| 					"Limit of concurrent requests reached (%d), try again later.", opts.MaxRequestsInFlight, | ||||
| 				), http.StatusServiceUnavailable) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		mfs, err := reg.Gather() | ||||
| 		if err != nil { | ||||
| 			if opts.ErrorLog != nil { | ||||
| 				opts.ErrorLog.Println("error gathering metrics:", err) | ||||
| 			} | ||||
| 			switch opts.ErrorHandling { | ||||
| 			case PanicOnError: | ||||
| 				panic(err) | ||||
| 			case ContinueOnError: | ||||
| 				if len(mfs) == 0 { | ||||
| 					// Still report the error if no metrics have been gathered. | ||||
| 					httpError(rsp, err) | ||||
| 					return | ||||
| 				} | ||||
| 			case HTTPErrorOnError: | ||||
| 				httpError(rsp, err) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		contentType := expfmt.Negotiate(req.Header) | ||||
| 		header := rsp.Header() | ||||
| 		header.Set(contentTypeHeader, string(contentType)) | ||||
|  | ||||
| 		w := io.Writer(rsp) | ||||
| 		if !opts.DisableCompression && gzipAccepted(req.Header) { | ||||
| 			header.Set(contentEncodingHeader, "gzip") | ||||
| 			gz := gzipPool.Get().(*gzip.Writer) | ||||
| 			defer gzipPool.Put(gz) | ||||
|  | ||||
| 			gz.Reset(w) | ||||
| 			defer gz.Close() | ||||
|  | ||||
| 			w = gz | ||||
| 		} | ||||
|  | ||||
| 		enc := expfmt.NewEncoder(w, contentType) | ||||
|  | ||||
| 		var lastErr error | ||||
| 		for _, mf := range mfs { | ||||
| 			if err := enc.Encode(mf); err != nil { | ||||
| 				lastErr = err | ||||
| 				if opts.ErrorLog != nil { | ||||
| 					opts.ErrorLog.Println("error encoding and sending metric family:", err) | ||||
| 				} | ||||
| 				switch opts.ErrorHandling { | ||||
| 				case PanicOnError: | ||||
| 					panic(err) | ||||
| 				case ContinueOnError: | ||||
| 					// Handled later. | ||||
| 				case HTTPErrorOnError: | ||||
| 					httpError(rsp, err) | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if lastErr != nil { | ||||
| 			httpError(rsp, lastErr) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	if opts.Timeout <= 0 { | ||||
| 		return h | ||||
| 	} | ||||
| 	return http.TimeoutHandler(h, opts.Timeout, fmt.Sprintf( | ||||
| 		"Exceeded configured timeout of %v.\n", | ||||
| 		opts.Timeout, | ||||
| 	)) | ||||
| } | ||||
|  | ||||
| // InstrumentMetricHandler is usually used with an http.Handler returned by the | ||||
| // HandlerFor function. It instruments the provided http.Handler with two | ||||
| // metrics: A counter vector "promhttp_metric_handler_requests_total" to count | ||||
| // scrapes partitioned by HTTP status code, and a gauge | ||||
| // "promhttp_metric_handler_requests_in_flight" to track the number of | ||||
| // simultaneous scrapes. This function idempotently registers collectors for | ||||
| // both metrics with the provided Registerer. It panics if the registration | ||||
| // fails. The provided metrics are useful to see how many scrapes hit the | ||||
| // monitored target (which could be from different Prometheus servers or other | ||||
| // scrapers), and how often they overlap (which would result in more than one | ||||
| // scrape in flight at the same time). Note that the scrapes-in-flight gauge | ||||
| // will contain the scrape by which it is exposed, while the scrape counter will | ||||
| // only get incremented after the scrape is complete (as only then the status | ||||
| // code is known). For tracking scrape durations, use the | ||||
| // "scrape_duration_seconds" gauge created by the Prometheus server upon each | ||||
| // scrape. | ||||
| func InstrumentMetricHandler(reg prometheus.Registerer, handler http.Handler) http.Handler { | ||||
| 	cnt := prometheus.NewCounterVec( | ||||
| 		prometheus.CounterOpts{ | ||||
| 			Name: "promhttp_metric_handler_requests_total", | ||||
| 			Help: "Total number of scrapes by HTTP status code.", | ||||
| 		}, | ||||
| 		[]string{"code"}, | ||||
| 	) | ||||
| 	// Initialize the most likely HTTP status codes. | ||||
| 	cnt.WithLabelValues("200") | ||||
| 	cnt.WithLabelValues("500") | ||||
| 	cnt.WithLabelValues("503") | ||||
| 	if err := reg.Register(cnt); err != nil { | ||||
| 		if are, ok := err.(prometheus.AlreadyRegisteredError); ok { | ||||
| 			cnt = are.ExistingCollector.(*prometheus.CounterVec) | ||||
| 		} else { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	gge := prometheus.NewGauge(prometheus.GaugeOpts{ | ||||
| 		Name: "promhttp_metric_handler_requests_in_flight", | ||||
| 		Help: "Current number of scrapes being served.", | ||||
| 	}) | ||||
| 	if err := reg.Register(gge); err != nil { | ||||
| 		if are, ok := err.(prometheus.AlreadyRegisteredError); ok { | ||||
| 			gge = are.ExistingCollector.(prometheus.Gauge) | ||||
| 		} else { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return InstrumentHandlerCounter(cnt, InstrumentHandlerInFlight(gge, handler)) | ||||
| } | ||||
|  | ||||
| // HandlerErrorHandling defines how a Handler serving metrics will handle | ||||
| // errors. | ||||
| type HandlerErrorHandling int | ||||
|  | ||||
| // These constants cause handlers serving metrics to behave as described if | ||||
| // errors are encountered. | ||||
| const ( | ||||
| 	// Serve an HTTP status code 500 upon the first error | ||||
| 	// encountered. Report the error message in the body. | ||||
| 	HTTPErrorOnError HandlerErrorHandling = iota | ||||
| 	// Ignore errors and try to serve as many metrics as possible.  However, | ||||
| 	// if no metrics can be served, serve an HTTP status code 500 and the | ||||
| 	// last error message in the body. Only use this in deliberate "best | ||||
| 	// effort" metrics collection scenarios. It is recommended to at least | ||||
| 	// log errors (by providing an ErrorLog in HandlerOpts) to not mask | ||||
| 	// errors completely. | ||||
| 	ContinueOnError | ||||
| 	// Panic upon the first error encountered (useful for "crash only" apps). | ||||
| 	PanicOnError | ||||
| ) | ||||
|  | ||||
| // Logger is the minimal interface HandlerOpts needs for logging. Note that | ||||
| // log.Logger from the standard library implements this interface, and it is | ||||
| // easy to implement by custom loggers, if they don't do so already anyway. | ||||
| type Logger interface { | ||||
| 	Println(v ...interface{}) | ||||
| } | ||||
|  | ||||
| // HandlerOpts specifies options how to serve metrics via an http.Handler. The | ||||
| // zero value of HandlerOpts is a reasonable default. | ||||
| type HandlerOpts struct { | ||||
| 	// ErrorLog specifies an optional logger for errors collecting and | ||||
| 	// serving metrics. If nil, errors are not logged at all. | ||||
| 	ErrorLog Logger | ||||
| 	// ErrorHandling defines how errors are handled. Note that errors are | ||||
| 	// logged regardless of the configured ErrorHandling provided ErrorLog | ||||
| 	// is not nil. | ||||
| 	ErrorHandling HandlerErrorHandling | ||||
| 	// If DisableCompression is true, the handler will never compress the | ||||
| 	// response, even if requested by the client. | ||||
| 	DisableCompression bool | ||||
| 	// The number of concurrent HTTP requests is limited to | ||||
| 	// MaxRequestsInFlight. Additional requests are responded to with 503 | ||||
| 	// Service Unavailable and a suitable message in the body. If | ||||
| 	// MaxRequestsInFlight is 0 or negative, no limit is applied. | ||||
| 	MaxRequestsInFlight int | ||||
| 	// If handling a request takes longer than Timeout, it is responded to | ||||
| 	// with 503 ServiceUnavailable and a suitable Message. No timeout is | ||||
| 	// applied if Timeout is 0 or negative. Note that with the current | ||||
| 	// implementation, reaching the timeout simply ends the HTTP requests as | ||||
| 	// described above (and even that only if sending of the body hasn't | ||||
| 	// started yet), while the bulk work of gathering all the metrics keeps | ||||
| 	// running in the background (with the eventual result to be thrown | ||||
| 	// away). Until the implementation is improved, it is recommended to | ||||
| 	// implement a separate timeout in potentially slow Collectors. | ||||
| 	Timeout time.Duration | ||||
| } | ||||
|  | ||||
| // gzipAccepted returns whether the client will accept gzip-encoded content. | ||||
| func gzipAccepted(header http.Header) bool { | ||||
| 	a := header.Get(acceptEncodingHeader) | ||||
| 	parts := strings.Split(a, ",") | ||||
| 	for _, part := range parts { | ||||
| 		part = strings.TrimSpace(part) | ||||
| 		if part == "gzip" || strings.HasPrefix(part, "gzip;") { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // httpError removes any content-encoding header and then calls http.Error with | ||||
| // the provided error and http.StatusInternalServerErrer. Error contents is | ||||
| // supposed to be uncompressed plain text. However, same as with a plain | ||||
| // http.Error, any header settings will be void if the header has already been | ||||
| // sent. The error message will still be written to the writer, but it will | ||||
| // probably be of limited use. | ||||
| func httpError(rsp http.ResponseWriter, err error) { | ||||
| 	rsp.Header().Del(contentEncodingHeader) | ||||
| 	http.Error( | ||||
| 		rsp, | ||||
| 		"An error has occurred while serving metrics:\n\n"+err.Error(), | ||||
| 		http.StatusInternalServerError, | ||||
| 	) | ||||
| } | ||||
							
								
								
									
										97
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/prometheus/client_golang/prometheus" | ||||
| ) | ||||
|  | ||||
| // The RoundTripperFunc type is an adapter to allow the use of ordinary | ||||
| // functions as RoundTrippers. If f is a function with the appropriate | ||||
| // signature, RountTripperFunc(f) is a RoundTripper that calls f. | ||||
| type RoundTripperFunc func(req *http.Request) (*http.Response, error) | ||||
|  | ||||
| // RoundTrip implements the RoundTripper interface. | ||||
| func (rt RoundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { | ||||
| 	return rt(r) | ||||
| } | ||||
|  | ||||
| // InstrumentRoundTripperInFlight is a middleware that wraps the provided | ||||
| // http.RoundTripper. It sets the provided prometheus.Gauge to the number of | ||||
| // requests currently handled by the wrapped http.RoundTripper. | ||||
| // | ||||
| // See the example for ExampleInstrumentRoundTripperDuration for example usage. | ||||
| func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripper) RoundTripperFunc { | ||||
| 	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { | ||||
| 		gauge.Inc() | ||||
| 		defer gauge.Dec() | ||||
| 		return next.RoundTrip(r) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // InstrumentRoundTripperCounter is a middleware that wraps the provided | ||||
| // http.RoundTripper to observe the request result with the provided CounterVec. | ||||
| // The CounterVec must have zero, one, or two non-const non-curried labels. For | ||||
| // those, the only allowed label names are "code" and "method". The function | ||||
| // panics otherwise. Partitioning of the CounterVec happens by HTTP status code | ||||
| // and/or HTTP method if the respective instance label names are present in the | ||||
| // CounterVec. For unpartitioned counting, use a CounterVec with zero labels. | ||||
| // | ||||
| // If the wrapped RoundTripper panics or returns a non-nil error, the Counter | ||||
| // is not incremented. | ||||
| // | ||||
| // See the example for ExampleInstrumentRoundTripperDuration for example usage. | ||||
| func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper) RoundTripperFunc { | ||||
| 	code, method := checkLabels(counter) | ||||
|  | ||||
| 	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { | ||||
| 		resp, err := next.RoundTrip(r) | ||||
| 		if err == nil { | ||||
| 			counter.With(labels(code, method, r.Method, resp.StatusCode)).Inc() | ||||
| 		} | ||||
| 		return resp, err | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // InstrumentRoundTripperDuration is a middleware that wraps the provided | ||||
| // http.RoundTripper to observe the request duration with the provided | ||||
| // ObserverVec.  The ObserverVec must have zero, one, or two non-const | ||||
| // non-curried labels. For those, the only allowed label names are "code" and | ||||
| // "method". The function panics otherwise. The Observe method of the Observer | ||||
| // in the ObserverVec is called with the request duration in | ||||
| // seconds. Partitioning happens by HTTP status code and/or HTTP method if the | ||||
| // respective instance label names are present in the ObserverVec. For | ||||
| // unpartitioned observations, use an ObserverVec with zero labels. Note that | ||||
| // partitioning of Histograms is expensive and should be used judiciously. | ||||
| // | ||||
| // If the wrapped RoundTripper panics or returns a non-nil error, no values are | ||||
| // reported. | ||||
| // | ||||
| // Note that this method is only guaranteed to never observe negative durations | ||||
| // if used with Go1.9+. | ||||
| func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper) RoundTripperFunc { | ||||
| 	code, method := checkLabels(obs) | ||||
|  | ||||
| 	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { | ||||
| 		start := time.Now() | ||||
| 		resp, err := next.RoundTrip(r) | ||||
| 		if err == nil { | ||||
| 			obs.With(labels(code, method, r.Method, resp.StatusCode)).Observe(time.Since(start).Seconds()) | ||||
| 		} | ||||
| 		return resp, err | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										144
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| // +build go1.8 | ||||
|  | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
| 	"net/http" | ||||
| 	"net/http/httptrace" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // InstrumentTrace is used to offer flexibility in instrumenting the available | ||||
| // httptrace.ClientTrace hook functions. Each function is passed a float64 | ||||
| // representing the time in seconds since the start of the http request. A user | ||||
| // may choose to use separately buckets Histograms, or implement custom | ||||
| // instance labels on a per function basis. | ||||
| type InstrumentTrace struct { | ||||
| 	GotConn              func(float64) | ||||
| 	PutIdleConn          func(float64) | ||||
| 	GotFirstResponseByte func(float64) | ||||
| 	Got100Continue       func(float64) | ||||
| 	DNSStart             func(float64) | ||||
| 	DNSDone              func(float64) | ||||
| 	ConnectStart         func(float64) | ||||
| 	ConnectDone          func(float64) | ||||
| 	TLSHandshakeStart    func(float64) | ||||
| 	TLSHandshakeDone     func(float64) | ||||
| 	WroteHeaders         func(float64) | ||||
| 	Wait100Continue      func(float64) | ||||
| 	WroteRequest         func(float64) | ||||
| } | ||||
|  | ||||
| // InstrumentRoundTripperTrace is a middleware that wraps the provided | ||||
| // RoundTripper and reports times to hook functions provided in the | ||||
| // InstrumentTrace struct. Hook functions that are not present in the provided | ||||
| // InstrumentTrace struct are ignored. Times reported to the hook functions are | ||||
| // time since the start of the request. Only with Go1.9+, those times are | ||||
| // guaranteed to never be negative. (Earlier Go versions are not using a | ||||
| // monotonic clock.) Note that partitioning of Histograms is expensive and | ||||
| // should be used judiciously. | ||||
| // | ||||
| // For hook functions that receive an error as an argument, no observations are | ||||
| // made in the event of a non-nil error value. | ||||
| // | ||||
| // See the example for ExampleInstrumentRoundTripperDuration for example usage. | ||||
| func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc { | ||||
| 	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { | ||||
| 		start := time.Now() | ||||
|  | ||||
| 		trace := &httptrace.ClientTrace{ | ||||
| 			GotConn: func(_ httptrace.GotConnInfo) { | ||||
| 				if it.GotConn != nil { | ||||
| 					it.GotConn(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			PutIdleConn: func(err error) { | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if it.PutIdleConn != nil { | ||||
| 					it.PutIdleConn(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			DNSStart: func(_ httptrace.DNSStartInfo) { | ||||
| 				if it.DNSStart != nil { | ||||
| 					it.DNSStart(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			DNSDone: func(_ httptrace.DNSDoneInfo) { | ||||
| 				if it.DNSDone != nil { | ||||
| 					it.DNSDone(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			ConnectStart: func(_, _ string) { | ||||
| 				if it.ConnectStart != nil { | ||||
| 					it.ConnectStart(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			ConnectDone: func(_, _ string, err error) { | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if it.ConnectDone != nil { | ||||
| 					it.ConnectDone(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			GotFirstResponseByte: func() { | ||||
| 				if it.GotFirstResponseByte != nil { | ||||
| 					it.GotFirstResponseByte(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			Got100Continue: func() { | ||||
| 				if it.Got100Continue != nil { | ||||
| 					it.Got100Continue(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			TLSHandshakeStart: func() { | ||||
| 				if it.TLSHandshakeStart != nil { | ||||
| 					it.TLSHandshakeStart(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			TLSHandshakeDone: func(_ tls.ConnectionState, err error) { | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if it.TLSHandshakeDone != nil { | ||||
| 					it.TLSHandshakeDone(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			WroteHeaders: func() { | ||||
| 				if it.WroteHeaders != nil { | ||||
| 					it.WroteHeaders(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			Wait100Continue: func() { | ||||
| 				if it.Wait100Continue != nil { | ||||
| 					it.Wait100Continue(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 			WroteRequest: func(_ httptrace.WroteRequestInfo) { | ||||
| 				if it.WroteRequest != nil { | ||||
| 					it.WroteRequest(time.Since(start).Seconds()) | ||||
| 				} | ||||
| 			}, | ||||
| 		} | ||||
| 		r = r.WithContext(httptrace.WithClientTrace(context.Background(), trace)) | ||||
|  | ||||
| 		return next.RoundTrip(r) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										447
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										447
									
								
								vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,447 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package promhttp | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
|  | ||||
| 	"github.com/prometheus/client_golang/prometheus" | ||||
| ) | ||||
|  | ||||
| // magicString is used for the hacky label test in checkLabels. Remove once fixed. | ||||
| const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa" | ||||
|  | ||||
| // InstrumentHandlerInFlight is a middleware that wraps the provided | ||||
| // http.Handler. It sets the provided prometheus.Gauge to the number of | ||||
| // requests currently handled by the wrapped http.Handler. | ||||
| // | ||||
| // See the example for InstrumentHandlerDuration for example usage. | ||||
| func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handler { | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		g.Inc() | ||||
| 		defer g.Dec() | ||||
| 		next.ServeHTTP(w, r) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // InstrumentHandlerDuration is a middleware that wraps the provided | ||||
| // http.Handler to observe the request duration with the provided ObserverVec. | ||||
| // The ObserverVec must have zero, one, or two non-const non-curried labels. For | ||||
| // those, the only allowed label names are "code" and "method". The function | ||||
| // panics otherwise. The Observe method of the Observer in the ObserverVec is | ||||
| // called with the request duration in seconds. Partitioning happens by HTTP | ||||
| // status code and/or HTTP method if the respective instance label names are | ||||
| // present in the ObserverVec. For unpartitioned observations, use an | ||||
| // ObserverVec with zero labels. Note that partitioning of Histograms is | ||||
| // expensive and should be used judiciously. | ||||
| // | ||||
| // If the wrapped Handler does not set a status code, a status code of 200 is assumed. | ||||
| // | ||||
| // If the wrapped Handler panics, no values are reported. | ||||
| // | ||||
| // Note that this method is only guaranteed to never observe negative durations | ||||
| // if used with Go1.9+. | ||||
| func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc { | ||||
| 	code, method := checkLabels(obs) | ||||
|  | ||||
| 	if code { | ||||
| 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 			now := time.Now() | ||||
| 			d := newDelegator(w, nil) | ||||
| 			next.ServeHTTP(d, r) | ||||
|  | ||||
| 			obs.With(labels(code, method, r.Method, d.Status())).Observe(time.Since(now).Seconds()) | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		now := time.Now() | ||||
| 		next.ServeHTTP(w, r) | ||||
| 		obs.With(labels(code, method, r.Method, 0)).Observe(time.Since(now).Seconds()) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // InstrumentHandlerCounter is a middleware that wraps the provided http.Handler | ||||
| // to observe the request result with the provided CounterVec.  The CounterVec | ||||
| // must have zero, one, or two non-const non-curried labels. For those, the only | ||||
| // allowed label names are "code" and "method". The function panics | ||||
| // otherwise. Partitioning of the CounterVec happens by HTTP status code and/or | ||||
| // HTTP method if the respective instance label names are present in the | ||||
| // CounterVec. For unpartitioned counting, use a CounterVec with zero labels. | ||||
| // | ||||
| // If the wrapped Handler does not set a status code, a status code of 200 is assumed. | ||||
| // | ||||
| // If the wrapped Handler panics, the Counter is not incremented. | ||||
| // | ||||
| // See the example for InstrumentHandlerDuration for example usage. | ||||
| func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler) http.HandlerFunc { | ||||
| 	code, method := checkLabels(counter) | ||||
|  | ||||
| 	if code { | ||||
| 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 			d := newDelegator(w, nil) | ||||
| 			next.ServeHTTP(d, r) | ||||
| 			counter.With(labels(code, method, r.Method, d.Status())).Inc() | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		next.ServeHTTP(w, r) | ||||
| 		counter.With(labels(code, method, r.Method, 0)).Inc() | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided | ||||
| // http.Handler to observe with the provided ObserverVec the request duration | ||||
| // until the response headers are written. The ObserverVec must have zero, one, | ||||
| // or two non-const non-curried labels. For those, the only allowed label names | ||||
| // are "code" and "method". The function panics otherwise. The Observe method of | ||||
| // the Observer in the ObserverVec is called with the request duration in | ||||
| // seconds. Partitioning happens by HTTP status code and/or HTTP method if the | ||||
| // respective instance label names are present in the ObserverVec. For | ||||
| // unpartitioned observations, use an ObserverVec with zero labels. Note that | ||||
| // partitioning of Histograms is expensive and should be used judiciously. | ||||
| // | ||||
| // If the wrapped Handler panics before calling WriteHeader, no value is | ||||
| // reported. | ||||
| // | ||||
| // Note that this method is only guaranteed to never observe negative durations | ||||
| // if used with Go1.9+. | ||||
| // | ||||
| // See the example for InstrumentHandlerDuration for example usage. | ||||
| func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc { | ||||
| 	code, method := checkLabels(obs) | ||||
|  | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		now := time.Now() | ||||
| 		d := newDelegator(w, func(status int) { | ||||
| 			obs.With(labels(code, method, r.Method, status)).Observe(time.Since(now).Seconds()) | ||||
| 		}) | ||||
| 		next.ServeHTTP(d, r) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // InstrumentHandlerRequestSize is a middleware that wraps the provided | ||||
| // http.Handler to observe the request size with the provided ObserverVec.  The | ||||
| // ObserverVec must have zero, one, or two non-const non-curried labels. For | ||||
| // those, the only allowed label names are "code" and "method". The function | ||||
| // panics otherwise. The Observe method of the Observer in the ObserverVec is | ||||
| // called with the request size in bytes. Partitioning happens by HTTP status | ||||
| // code and/or HTTP method if the respective instance label names are present in | ||||
| // the ObserverVec. For unpartitioned observations, use an ObserverVec with zero | ||||
| // labels. Note that partitioning of Histograms is expensive and should be used | ||||
| // judiciously. | ||||
| // | ||||
| // If the wrapped Handler does not set a status code, a status code of 200 is assumed. | ||||
| // | ||||
| // If the wrapped Handler panics, no values are reported. | ||||
| // | ||||
| // See the example for InstrumentHandlerDuration for example usage. | ||||
| func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc { | ||||
| 	code, method := checkLabels(obs) | ||||
|  | ||||
| 	if code { | ||||
| 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 			d := newDelegator(w, nil) | ||||
| 			next.ServeHTTP(d, r) | ||||
| 			size := computeApproximateRequestSize(r) | ||||
| 			obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(size)) | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		next.ServeHTTP(w, r) | ||||
| 		size := computeApproximateRequestSize(r) | ||||
| 		obs.With(labels(code, method, r.Method, 0)).Observe(float64(size)) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // InstrumentHandlerResponseSize is a middleware that wraps the provided | ||||
| // http.Handler to observe the response size with the provided ObserverVec.  The | ||||
| // ObserverVec must have zero, one, or two non-const non-curried labels. For | ||||
| // those, the only allowed label names are "code" and "method". The function | ||||
| // panics otherwise. The Observe method of the Observer in the ObserverVec is | ||||
| // called with the response size in bytes. Partitioning happens by HTTP status | ||||
| // code and/or HTTP method if the respective instance label names are present in | ||||
| // the ObserverVec. For unpartitioned observations, use an ObserverVec with zero | ||||
| // labels. Note that partitioning of Histograms is expensive and should be used | ||||
| // judiciously. | ||||
| // | ||||
| // If the wrapped Handler does not set a status code, a status code of 200 is assumed. | ||||
| // | ||||
| // If the wrapped Handler panics, no values are reported. | ||||
| // | ||||
| // See the example for InstrumentHandlerDuration for example usage. | ||||
| func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler) http.Handler { | ||||
| 	code, method := checkLabels(obs) | ||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 		d := newDelegator(w, nil) | ||||
| 		next.ServeHTTP(d, r) | ||||
| 		obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(d.Written())) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func checkLabels(c prometheus.Collector) (code bool, method bool) { | ||||
| 	// TODO(beorn7): Remove this hacky way to check for instance labels | ||||
| 	// once Descriptors can have their dimensionality queried. | ||||
| 	var ( | ||||
| 		desc *prometheus.Desc | ||||
| 		m    prometheus.Metric | ||||
| 		pm   dto.Metric | ||||
| 		lvs  []string | ||||
| 	) | ||||
|  | ||||
| 	// Get the Desc from the Collector. | ||||
| 	descc := make(chan *prometheus.Desc, 1) | ||||
| 	c.Describe(descc) | ||||
|  | ||||
| 	select { | ||||
| 	case desc = <-descc: | ||||
| 	default: | ||||
| 		panic("no description provided by collector") | ||||
| 	} | ||||
| 	select { | ||||
| 	case <-descc: | ||||
| 		panic("more than one description provided by collector") | ||||
| 	default: | ||||
| 	} | ||||
|  | ||||
| 	close(descc) | ||||
|  | ||||
| 	// Create a ConstMetric with the Desc. Since we don't know how many | ||||
| 	// variable labels there are, try for as long as it needs. | ||||
| 	for err := errors.New("dummy"); err != nil; lvs = append(lvs, magicString) { | ||||
| 		m, err = prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, lvs...) | ||||
| 	} | ||||
|  | ||||
| 	// Write out the metric into a proto message and look at the labels. | ||||
| 	// If the value is not the magicString, it is a constLabel, which doesn't interest us. | ||||
| 	// If the label is curried, it doesn't interest us. | ||||
| 	// In all other cases, only "code" or "method" is allowed. | ||||
| 	if err := m.Write(&pm); err != nil { | ||||
| 		panic("error checking metric for labels") | ||||
| 	} | ||||
| 	for _, label := range pm.Label { | ||||
| 		name, value := label.GetName(), label.GetValue() | ||||
| 		if value != magicString || isLabelCurried(c, name) { | ||||
| 			continue | ||||
| 		} | ||||
| 		switch name { | ||||
| 		case "code": | ||||
| 			code = true | ||||
| 		case "method": | ||||
| 			method = true | ||||
| 		default: | ||||
| 			panic("metric partitioned with non-supported labels") | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func isLabelCurried(c prometheus.Collector, label string) bool { | ||||
| 	// This is even hackier than the label test above. | ||||
| 	// We essentially try to curry again and see if it works. | ||||
| 	// But for that, we need to type-convert to the two | ||||
| 	// types we use here, ObserverVec or *CounterVec. | ||||
| 	switch v := c.(type) { | ||||
| 	case *prometheus.CounterVec: | ||||
| 		if _, err := v.CurryWith(prometheus.Labels{label: "dummy"}); err == nil { | ||||
| 			return false | ||||
| 		} | ||||
| 	case prometheus.ObserverVec: | ||||
| 		if _, err := v.CurryWith(prometheus.Labels{label: "dummy"}); err == nil { | ||||
| 			return false | ||||
| 		} | ||||
| 	default: | ||||
| 		panic("unsupported metric vec type") | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // emptyLabels is a one-time allocation for non-partitioned metrics to avoid | ||||
| // unnecessary allocations on each request. | ||||
| var emptyLabels = prometheus.Labels{} | ||||
|  | ||||
| func labels(code, method bool, reqMethod string, status int) prometheus.Labels { | ||||
| 	if !(code || method) { | ||||
| 		return emptyLabels | ||||
| 	} | ||||
| 	labels := prometheus.Labels{} | ||||
|  | ||||
| 	if code { | ||||
| 		labels["code"] = sanitizeCode(status) | ||||
| 	} | ||||
| 	if method { | ||||
| 		labels["method"] = sanitizeMethod(reqMethod) | ||||
| 	} | ||||
|  | ||||
| 	return labels | ||||
| } | ||||
|  | ||||
| func computeApproximateRequestSize(r *http.Request) int { | ||||
| 	s := 0 | ||||
| 	if r.URL != nil { | ||||
| 		s += len(r.URL.String()) | ||||
| 	} | ||||
|  | ||||
| 	s += len(r.Method) | ||||
| 	s += len(r.Proto) | ||||
| 	for name, values := range r.Header { | ||||
| 		s += len(name) | ||||
| 		for _, value := range values { | ||||
| 			s += len(value) | ||||
| 		} | ||||
| 	} | ||||
| 	s += len(r.Host) | ||||
|  | ||||
| 	// N.B. r.Form and r.MultipartForm are assumed to be included in r.URL. | ||||
|  | ||||
| 	if r.ContentLength != -1 { | ||||
| 		s += int(r.ContentLength) | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| func sanitizeMethod(m string) string { | ||||
| 	switch m { | ||||
| 	case "GET", "get": | ||||
| 		return "get" | ||||
| 	case "PUT", "put": | ||||
| 		return "put" | ||||
| 	case "HEAD", "head": | ||||
| 		return "head" | ||||
| 	case "POST", "post": | ||||
| 		return "post" | ||||
| 	case "DELETE", "delete": | ||||
| 		return "delete" | ||||
| 	case "CONNECT", "connect": | ||||
| 		return "connect" | ||||
| 	case "OPTIONS", "options": | ||||
| 		return "options" | ||||
| 	case "NOTIFY", "notify": | ||||
| 		return "notify" | ||||
| 	default: | ||||
| 		return strings.ToLower(m) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // If the wrapped http.Handler has not set a status code, i.e. the value is | ||||
| // currently 0, santizeCode will return 200, for consistency with behavior in | ||||
| // the stdlib. | ||||
| func sanitizeCode(s int) string { | ||||
| 	switch s { | ||||
| 	case 100: | ||||
| 		return "100" | ||||
| 	case 101: | ||||
| 		return "101" | ||||
|  | ||||
| 	case 200, 0: | ||||
| 		return "200" | ||||
| 	case 201: | ||||
| 		return "201" | ||||
| 	case 202: | ||||
| 		return "202" | ||||
| 	case 203: | ||||
| 		return "203" | ||||
| 	case 204: | ||||
| 		return "204" | ||||
| 	case 205: | ||||
| 		return "205" | ||||
| 	case 206: | ||||
| 		return "206" | ||||
|  | ||||
| 	case 300: | ||||
| 		return "300" | ||||
| 	case 301: | ||||
| 		return "301" | ||||
| 	case 302: | ||||
| 		return "302" | ||||
| 	case 304: | ||||
| 		return "304" | ||||
| 	case 305: | ||||
| 		return "305" | ||||
| 	case 307: | ||||
| 		return "307" | ||||
|  | ||||
| 	case 400: | ||||
| 		return "400" | ||||
| 	case 401: | ||||
| 		return "401" | ||||
| 	case 402: | ||||
| 		return "402" | ||||
| 	case 403: | ||||
| 		return "403" | ||||
| 	case 404: | ||||
| 		return "404" | ||||
| 	case 405: | ||||
| 		return "405" | ||||
| 	case 406: | ||||
| 		return "406" | ||||
| 	case 407: | ||||
| 		return "407" | ||||
| 	case 408: | ||||
| 		return "408" | ||||
| 	case 409: | ||||
| 		return "409" | ||||
| 	case 410: | ||||
| 		return "410" | ||||
| 	case 411: | ||||
| 		return "411" | ||||
| 	case 412: | ||||
| 		return "412" | ||||
| 	case 413: | ||||
| 		return "413" | ||||
| 	case 414: | ||||
| 		return "414" | ||||
| 	case 415: | ||||
| 		return "415" | ||||
| 	case 416: | ||||
| 		return "416" | ||||
| 	case 417: | ||||
| 		return "417" | ||||
| 	case 418: | ||||
| 		return "418" | ||||
|  | ||||
| 	case 500: | ||||
| 		return "500" | ||||
| 	case 501: | ||||
| 		return "501" | ||||
| 	case 502: | ||||
| 		return "502" | ||||
| 	case 503: | ||||
| 		return "503" | ||||
| 	case 504: | ||||
| 		return "504" | ||||
| 	case 505: | ||||
| 		return "505" | ||||
|  | ||||
| 	case 428: | ||||
| 		return "428" | ||||
| 	case 429: | ||||
| 		return "429" | ||||
| 	case 431: | ||||
| 		return "431" | ||||
| 	case 511: | ||||
| 		return "511" | ||||
|  | ||||
| 	default: | ||||
| 		return strconv.Itoa(s) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										931
									
								
								vendor/github.com/prometheus/client_golang/prometheus/registry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										931
									
								
								vendor/github.com/prometheus/client_golang/prometheus/registry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,931 @@ | ||||
| // 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" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"github.com/prometheus/common/expfmt" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
|  | ||||
| 	"github.com/prometheus/client_golang/prometheus/internal" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// Capacity for the channel to collect metrics and descriptors. | ||||
| 	capMetricChan = 1000 | ||||
| 	capDescChan   = 10 | ||||
| ) | ||||
|  | ||||
| // DefaultRegisterer and DefaultGatherer are the implementations of the | ||||
| // Registerer and Gatherer interface a number of convenience functions in this | ||||
| // package act on. Initially, both variables point to the same Registry, which | ||||
| // has a process collector (currently on Linux only, see NewProcessCollector) | ||||
| // and a Go collector (see NewGoCollector, in particular the note about | ||||
| // stop-the-world implication with Go versions older than 1.9) already | ||||
| // registered. This approach to keep default instances as global state mirrors | ||||
| // the approach of other packages in the Go standard library. Note that there | ||||
| // are caveats. Change the variables with caution and only if you understand the | ||||
| // consequences. Users who want to avoid global state altogether should not use | ||||
| // the convenience functions and act on custom instances instead. | ||||
| var ( | ||||
| 	defaultRegistry              = NewRegistry() | ||||
| 	DefaultRegisterer Registerer = defaultRegistry | ||||
| 	DefaultGatherer   Gatherer   = defaultRegistry | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	MustRegister(NewProcessCollector(ProcessCollectorOpts{})) | ||||
| 	MustRegister(NewGoCollector()) | ||||
| } | ||||
|  | ||||
| // NewRegistry creates a new vanilla Registry without any Collectors | ||||
| // pre-registered. | ||||
| func NewRegistry() *Registry { | ||||
| 	return &Registry{ | ||||
| 		collectorsByID:  map[uint64]Collector{}, | ||||
| 		descIDs:         map[uint64]struct{}{}, | ||||
| 		dimHashesByName: map[string]uint64{}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NewPedanticRegistry returns a registry that checks during collection if each | ||||
| // collected Metric is consistent with its reported Desc, and if the Desc has | ||||
| // actually been registered with the registry. Unchecked Collectors (those whose | ||||
| // Describe methed does not yield any descriptors) are excluded from the check. | ||||
| // | ||||
| // Usually, a Registry will be happy as long as the union of all collected | ||||
| // Metrics is consistent and valid even if some metrics are not consistent with | ||||
| // their own Desc or a Desc provided by their registered Collector. Well-behaved | ||||
| // Collectors and Metrics will only provide consistent Descs. This Registry is | ||||
| // useful to test the implementation of Collectors and Metrics. | ||||
| func NewPedanticRegistry() *Registry { | ||||
| 	r := NewRegistry() | ||||
| 	r.pedanticChecksEnabled = true | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // Registerer is the interface for the part of a registry in charge of | ||||
| // registering and unregistering. Users of custom registries should use | ||||
| // Registerer as type for registration purposes (rather than the Registry type | ||||
| // directly). In that way, they are free to use custom Registerer implementation | ||||
| // (e.g. for testing purposes). | ||||
| type Registerer interface { | ||||
| 	// 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 documentation of metric.Desc. | ||||
| 	// | ||||
| 	// If the provided Collector is equal to a Collector already registered | ||||
| 	// (which includes the case of re-registering the same Collector), the | ||||
| 	// returned error is an instance of AlreadyRegisteredError, which | ||||
| 	// contains the previously registered Collector. | ||||
| 	// | ||||
| 	// A Collector whose Describe method does not yield any Desc is treated | ||||
| 	// as unchecked. Registration will always succeed. No check for | ||||
| 	// re-registering (see previous paragraph) is performed. Thus, the | ||||
| 	// caller is responsible for not double-registering the same unchecked | ||||
| 	// Collector, and for providing a Collector that will not cause | ||||
| 	// inconsistent metrics on collection. (This would lead to scrape | ||||
| 	// errors.) | ||||
| 	Register(Collector) error | ||||
| 	// MustRegister works like Register but registers any number of | ||||
| 	// Collectors and panics upon the first registration that causes an | ||||
| 	// error. | ||||
| 	MustRegister(...Collector) | ||||
| 	// 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. Note that an unchecked | ||||
| 	// Collector cannot be unregistered (as its Describe method does not | ||||
| 	// yield any descriptor). | ||||
| 	// | ||||
| 	// Note that even after unregistering, it will not be possible to | ||||
| 	// register a new Collector that is inconsistent with the unregistered | ||||
| 	// Collector, e.g. a Collector collecting metrics with the same name but | ||||
| 	// a different help string. The rationale here is that the same registry | ||||
| 	// instance must only collect consistent metrics throughout its | ||||
| 	// lifetime. | ||||
| 	Unregister(Collector) bool | ||||
| } | ||||
|  | ||||
| // Gatherer is the interface for the part of a registry in charge of gathering | ||||
| // the collected metrics into a number of MetricFamilies. The Gatherer interface | ||||
| // comes with the same general implication as described for the Registerer | ||||
| // interface. | ||||
| type Gatherer interface { | ||||
| 	// Gather calls the Collect method of the registered Collectors and then | ||||
| 	// gathers the collected metrics into a lexicographically sorted slice | ||||
| 	// of uniquely named MetricFamily protobufs. Gather ensures that the | ||||
| 	// returned slice is valid and self-consistent so that it can be used | ||||
| 	// for valid exposition. As an exception to the strict consistency | ||||
| 	// requirements described for metric.Desc, Gather will tolerate | ||||
| 	// different sets of label names for metrics of the same metric family. | ||||
| 	// | ||||
| 	// Even if an error occurs, Gather attempts to gather as many metrics as | ||||
| 	// possible. Hence, if a non-nil error is returned, the returned | ||||
| 	// MetricFamily slice could be nil (in case of a fatal error that | ||||
| 	// prevented any meaningful metric collection) or contain a number of | ||||
| 	// MetricFamily protobufs, some of which might be incomplete, and some | ||||
| 	// might be missing altogether. The returned error (which might be a | ||||
| 	// MultiError) explains the details. Note that this is mostly useful for | ||||
| 	// debugging purposes. If the gathered protobufs are to be used for | ||||
| 	// exposition in actual monitoring, it is almost always better to not | ||||
| 	// expose an incomplete result and instead disregard the returned | ||||
| 	// MetricFamily protobufs in case the returned error is non-nil. | ||||
| 	Gather() ([]*dto.MetricFamily, error) | ||||
| } | ||||
|  | ||||
| // Register registers the provided Collector with the DefaultRegisterer. | ||||
| // | ||||
| // Register is a shortcut for DefaultRegisterer.Register(c). See there for more | ||||
| // details. | ||||
| func Register(c Collector) error { | ||||
| 	return DefaultRegisterer.Register(c) | ||||
| } | ||||
|  | ||||
| // MustRegister registers the provided Collectors with the DefaultRegisterer and | ||||
| // panics if any error occurs. | ||||
| // | ||||
| // MustRegister is a shortcut for DefaultRegisterer.MustRegister(cs...). See | ||||
| // there for more details. | ||||
| func MustRegister(cs ...Collector) { | ||||
| 	DefaultRegisterer.MustRegister(cs...) | ||||
| } | ||||
|  | ||||
| // Unregister removes the registration of the provided Collector from the | ||||
| // DefaultRegisterer. | ||||
| // | ||||
| // Unregister is a shortcut for DefaultRegisterer.Unregister(c). See there for | ||||
| // more details. | ||||
| func Unregister(c Collector) bool { | ||||
| 	return DefaultRegisterer.Unregister(c) | ||||
| } | ||||
|  | ||||
| // GathererFunc turns a function into a Gatherer. | ||||
| type GathererFunc func() ([]*dto.MetricFamily, error) | ||||
|  | ||||
| // Gather implements Gatherer. | ||||
| func (gf GathererFunc) Gather() ([]*dto.MetricFamily, error) { | ||||
| 	return gf() | ||||
| } | ||||
|  | ||||
| // AlreadyRegisteredError is returned by the Register method if the Collector to | ||||
| // be registered has already been registered before, or a different Collector | ||||
| // that collects the same metrics has been registered before. Registration fails | ||||
| // in that case, but you can detect from the kind of error what has | ||||
| // happened. The error contains fields for the existing Collector and the | ||||
| // (rejected) new Collector that equals the existing one. This can be used to | ||||
| // find out if an equal Collector has been registered before and switch over to | ||||
| // using the old one, as demonstrated in the example. | ||||
| type AlreadyRegisteredError struct { | ||||
| 	ExistingCollector, NewCollector Collector | ||||
| } | ||||
|  | ||||
| func (err AlreadyRegisteredError) Error() string { | ||||
| 	return "duplicate metrics collector registration attempted" | ||||
| } | ||||
|  | ||||
| // MultiError is a slice of errors implementing the error interface. It is used | ||||
| // by a Gatherer to report multiple errors during MetricFamily gathering. | ||||
| type MultiError []error | ||||
|  | ||||
| func (errs MultiError) Error() string { | ||||
| 	if len(errs) == 0 { | ||||
| 		return "" | ||||
| 	} | ||||
| 	buf := &bytes.Buffer{} | ||||
| 	fmt.Fprintf(buf, "%d error(s) occurred:", len(errs)) | ||||
| 	for _, err := range errs { | ||||
| 		fmt.Fprintf(buf, "\n* %s", err) | ||||
| 	} | ||||
| 	return buf.String() | ||||
| } | ||||
|  | ||||
| // Append appends the provided error if it is not nil. | ||||
| func (errs *MultiError) Append(err error) { | ||||
| 	if err != nil { | ||||
| 		*errs = append(*errs, err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // MaybeUnwrap returns nil if len(errs) is 0. It returns the first and only | ||||
| // contained error as error if len(errs is 1). In all other cases, it returns | ||||
| // the MultiError directly. This is helpful for returning a MultiError in a way | ||||
| // that only uses the MultiError if needed. | ||||
| func (errs MultiError) MaybeUnwrap() error { | ||||
| 	switch len(errs) { | ||||
| 	case 0: | ||||
| 		return nil | ||||
| 	case 1: | ||||
| 		return errs[0] | ||||
| 	default: | ||||
| 		return errs | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Registry registers Prometheus collectors, collects their metrics, and gathers | ||||
| // them into MetricFamilies for exposition. It implements both Registerer and | ||||
| // Gatherer. The zero value is not usable. Create instances with NewRegistry or | ||||
| // NewPedanticRegistry. | ||||
| 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 | ||||
| 	uncheckedCollectors   []Collector | ||||
| 	pedanticChecksEnabled bool | ||||
| } | ||||
|  | ||||
| // Register implements Registerer. | ||||
| func (r *Registry) Register(c Collector) error { | ||||
| 	var ( | ||||
| 		descChan           = make(chan *Desc, capDescChan) | ||||
| 		newDescIDs         = map[uint64]struct{}{} | ||||
| 		newDimHashesByName = map[string]uint64{} | ||||
| 		collectorID        uint64 // Just a sum of all desc IDs. | ||||
| 		duplicateDescErr   error | ||||
| 	) | ||||
| 	go func() { | ||||
| 		c.Describe(descChan) | ||||
| 		close(descChan) | ||||
| 	}() | ||||
| 	r.mtx.Lock() | ||||
| 	defer func() { | ||||
| 		// Drain channel in case of premature return to not leak a goroutine. | ||||
| 		for range descChan { | ||||
| 		} | ||||
| 		r.mtx.Unlock() | ||||
| 	}() | ||||
| 	// Conduct various tests... | ||||
| 	for desc := range descChan { | ||||
|  | ||||
| 		// Is the descriptor valid at all? | ||||
| 		if desc.err != nil { | ||||
| 			return 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 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 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 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	// A Collector yielding no Desc at all is considered unchecked. | ||||
| 	if len(newDescIDs) == 0 { | ||||
| 		r.uncheckedCollectors = append(r.uncheckedCollectors, c) | ||||
| 		return nil | ||||
| 	} | ||||
| 	if existing, exists := r.collectorsByID[collectorID]; exists { | ||||
| 		return AlreadyRegisteredError{ | ||||
| 			ExistingCollector: existing, | ||||
| 			NewCollector:      c, | ||||
| 		} | ||||
| 	} | ||||
| 	// If the collectorID is new, but at least one of the descs existed | ||||
| 	// before, we are in trouble. | ||||
| 	if duplicateDescErr != nil { | ||||
| 		return 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 nil | ||||
| } | ||||
|  | ||||
| // Unregister implements Registerer. | ||||
| func (r *Registry) Unregister(c Collector) bool { | ||||
| 	var ( | ||||
| 		descChan    = make(chan *Desc, capDescChan) | ||||
| 		descIDs     = map[uint64]struct{}{} | ||||
| 		collectorID uint64 // Just a sum of the desc IDs. | ||||
| 	) | ||||
| 	go func() { | ||||
| 		c.Describe(descChan) | ||||
| 		close(descChan) | ||||
| 	}() | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| // MustRegister implements Registerer. | ||||
| func (r *Registry) MustRegister(cs ...Collector) { | ||||
| 	for _, c := range cs { | ||||
| 		if err := r.Register(c); err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Gather implements Gatherer. | ||||
| func (r *Registry) Gather() ([]*dto.MetricFamily, error) { | ||||
| 	var ( | ||||
| 		checkedMetricChan   = make(chan Metric, capMetricChan) | ||||
| 		uncheckedMetricChan = make(chan Metric, capMetricChan) | ||||
| 		metricHashes        = map[uint64]struct{}{} | ||||
| 		wg                  sync.WaitGroup | ||||
| 		errs                MultiError          // The collected errors to return in the end. | ||||
| 		registeredDescIDs   map[uint64]struct{} // Only used for pedantic checks | ||||
| 	) | ||||
|  | ||||
| 	r.mtx.RLock() | ||||
| 	goroutineBudget := len(r.collectorsByID) + len(r.uncheckedCollectors) | ||||
| 	metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName)) | ||||
| 	checkedCollectors := make(chan Collector, len(r.collectorsByID)) | ||||
| 	uncheckedCollectors := make(chan Collector, len(r.uncheckedCollectors)) | ||||
| 	for _, collector := range r.collectorsByID { | ||||
| 		checkedCollectors <- collector | ||||
| 	} | ||||
| 	for _, collector := range r.uncheckedCollectors { | ||||
| 		uncheckedCollectors <- collector | ||||
| 	} | ||||
| 	// In case pedantic checks are enabled, we have to copy the map before | ||||
| 	// giving up the RLock. | ||||
| 	if r.pedanticChecksEnabled { | ||||
| 		registeredDescIDs = make(map[uint64]struct{}, len(r.descIDs)) | ||||
| 		for id := range r.descIDs { | ||||
| 			registeredDescIDs[id] = struct{}{} | ||||
| 		} | ||||
| 	} | ||||
| 	r.mtx.RUnlock() | ||||
|  | ||||
| 	wg.Add(goroutineBudget) | ||||
|  | ||||
| 	collectWorker := func() { | ||||
| 		for { | ||||
| 			select { | ||||
| 			case collector := <-checkedCollectors: | ||||
| 				collector.Collect(checkedMetricChan) | ||||
| 			case collector := <-uncheckedCollectors: | ||||
| 				collector.Collect(uncheckedMetricChan) | ||||
| 			default: | ||||
| 				return | ||||
| 			} | ||||
| 			wg.Done() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Start the first worker now to make sure at least one is running. | ||||
| 	go collectWorker() | ||||
| 	goroutineBudget-- | ||||
|  | ||||
| 	// Close checkedMetricChan and uncheckedMetricChan once all collectors | ||||
| 	// are collected. | ||||
| 	go func() { | ||||
| 		wg.Wait() | ||||
| 		close(checkedMetricChan) | ||||
| 		close(uncheckedMetricChan) | ||||
| 	}() | ||||
|  | ||||
| 	// Drain checkedMetricChan and uncheckedMetricChan in case of premature return. | ||||
| 	defer func() { | ||||
| 		if checkedMetricChan != nil { | ||||
| 			for range checkedMetricChan { | ||||
| 			} | ||||
| 		} | ||||
| 		if uncheckedMetricChan != nil { | ||||
| 			for range uncheckedMetricChan { | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	// Copy the channel references so we can nil them out later to remove | ||||
| 	// them from the select statements below. | ||||
| 	cmc := checkedMetricChan | ||||
| 	umc := uncheckedMetricChan | ||||
|  | ||||
| 	for { | ||||
| 		select { | ||||
| 		case metric, ok := <-cmc: | ||||
| 			if !ok { | ||||
| 				cmc = nil | ||||
| 				break | ||||
| 			} | ||||
| 			errs.Append(processMetric( | ||||
| 				metric, metricFamiliesByName, | ||||
| 				metricHashes, | ||||
| 				registeredDescIDs, | ||||
| 			)) | ||||
| 		case metric, ok := <-umc: | ||||
| 			if !ok { | ||||
| 				umc = nil | ||||
| 				break | ||||
| 			} | ||||
| 			errs.Append(processMetric( | ||||
| 				metric, metricFamiliesByName, | ||||
| 				metricHashes, | ||||
| 				nil, | ||||
| 			)) | ||||
| 		default: | ||||
| 			if goroutineBudget <= 0 || len(checkedCollectors)+len(uncheckedCollectors) == 0 { | ||||
| 				// All collectors are already being worked on or | ||||
| 				// we have already as many goroutines started as | ||||
| 				// there are collectors. Do the same as above, | ||||
| 				// just without the default. | ||||
| 				select { | ||||
| 				case metric, ok := <-cmc: | ||||
| 					if !ok { | ||||
| 						cmc = nil | ||||
| 						break | ||||
| 					} | ||||
| 					errs.Append(processMetric( | ||||
| 						metric, metricFamiliesByName, | ||||
| 						metricHashes, | ||||
| 						registeredDescIDs, | ||||
| 					)) | ||||
| 				case metric, ok := <-umc: | ||||
| 					if !ok { | ||||
| 						umc = nil | ||||
| 						break | ||||
| 					} | ||||
| 					errs.Append(processMetric( | ||||
| 						metric, metricFamiliesByName, | ||||
| 						metricHashes, | ||||
| 						nil, | ||||
| 					)) | ||||
| 				} | ||||
| 				break | ||||
| 			} | ||||
| 			// Start more workers. | ||||
| 			go collectWorker() | ||||
| 			goroutineBudget-- | ||||
| 			runtime.Gosched() | ||||
| 		} | ||||
| 		// Once both checkedMetricChan and uncheckdMetricChan are closed | ||||
| 		// and drained, the contraption above will nil out cmc and umc, | ||||
| 		// and then we can leave the collect loop here. | ||||
| 		if cmc == nil && umc == nil { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() | ||||
| } | ||||
|  | ||||
| // WriteToTextfile calls Gather on the provided Gatherer, encodes the result in the | ||||
| // Prometheus text format, and writes it to a temporary file. Upon success, the | ||||
| // temporary file is renamed to the provided filename. | ||||
| // | ||||
| // This is intended for use with the textfile collector of the node exporter. | ||||
| // Note that the node exporter expects the filename to be suffixed with ".prom". | ||||
| func WriteToTextfile(filename string, g Gatherer) error { | ||||
| 	tmp, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer os.Remove(tmp.Name()) | ||||
|  | ||||
| 	mfs, err := g.Gather() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, mf := range mfs { | ||||
| 		if _, err := expfmt.MetricFamilyToText(tmp, mf); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if err := tmp.Close(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if err := os.Chmod(tmp.Name(), 0644); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return os.Rename(tmp.Name(), filename) | ||||
| } | ||||
|  | ||||
| // processMetric is an internal helper method only used by the Gather method. | ||||
| func processMetric( | ||||
| 	metric Metric, | ||||
| 	metricFamiliesByName map[string]*dto.MetricFamily, | ||||
| 	metricHashes map[uint64]struct{}, | ||||
| 	registeredDescIDs map[uint64]struct{}, | ||||
| ) error { | ||||
| 	desc := metric.Desc() | ||||
| 	// Wrapped metrics collected by an unchecked Collector can have an | ||||
| 	// invalid Desc. | ||||
| 	if desc.err != nil { | ||||
| 		return desc.err | ||||
| 	} | ||||
| 	dtoMetric := &dto.Metric{} | ||||
| 	if err := metric.Write(dtoMetric); err != nil { | ||||
| 		return fmt.Errorf("error collecting metric %v: %s", desc, err) | ||||
| 	} | ||||
| 	metricFamily, ok := metricFamiliesByName[desc.fqName] | ||||
| 	if ok { // Existing name. | ||||
| 		if metricFamily.GetHelp() != desc.help { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %s %s has help %q but should have %q", | ||||
| 				desc.fqName, dtoMetric, desc.help, metricFamily.GetHelp(), | ||||
| 			) | ||||
| 		} | ||||
| 		// TODO(beorn7): Simplify switch once Desc has type. | ||||
| 		switch metricFamily.GetType() { | ||||
| 		case dto.MetricType_COUNTER: | ||||
| 			if dtoMetric.Counter == nil { | ||||
| 				return fmt.Errorf( | ||||
| 					"collected metric %s %s should be a Counter", | ||||
| 					desc.fqName, dtoMetric, | ||||
| 				) | ||||
| 			} | ||||
| 		case dto.MetricType_GAUGE: | ||||
| 			if dtoMetric.Gauge == nil { | ||||
| 				return fmt.Errorf( | ||||
| 					"collected metric %s %s should be a Gauge", | ||||
| 					desc.fqName, dtoMetric, | ||||
| 				) | ||||
| 			} | ||||
| 		case dto.MetricType_SUMMARY: | ||||
| 			if dtoMetric.Summary == nil { | ||||
| 				return fmt.Errorf( | ||||
| 					"collected metric %s %s should be a Summary", | ||||
| 					desc.fqName, dtoMetric, | ||||
| 				) | ||||
| 			} | ||||
| 		case dto.MetricType_UNTYPED: | ||||
| 			if dtoMetric.Untyped == nil { | ||||
| 				return fmt.Errorf( | ||||
| 					"collected metric %s %s should be Untyped", | ||||
| 					desc.fqName, dtoMetric, | ||||
| 				) | ||||
| 			} | ||||
| 		case dto.MetricType_HISTOGRAM: | ||||
| 			if dtoMetric.Histogram == nil { | ||||
| 				return fmt.Errorf( | ||||
| 					"collected metric %s %s should be a Histogram", | ||||
| 					desc.fqName, dtoMetric, | ||||
| 				) | ||||
| 			} | ||||
| 		default: | ||||
| 			panic("encountered MetricFamily with invalid type") | ||||
| 		} | ||||
| 	} else { // New name. | ||||
| 		metricFamily = &dto.MetricFamily{} | ||||
| 		metricFamily.Name = proto.String(desc.fqName) | ||||
| 		metricFamily.Help = proto.String(desc.help) | ||||
| 		// TODO(beorn7): Simplify switch once Desc has type. | ||||
| 		switch { | ||||
| 		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 err := checkSuffixCollisions(metricFamily, metricFamiliesByName); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		metricFamiliesByName[desc.fqName] = metricFamily | ||||
| 	} | ||||
| 	if err := checkMetricConsistency(metricFamily, dtoMetric, metricHashes); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if registeredDescIDs != nil { | ||||
| 		// Is the desc registered at all? | ||||
| 		if _, exist := registeredDescIDs[desc.id]; !exist { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %s %s with unregistered descriptor %s", | ||||
| 				metricFamily.GetName(), dtoMetric, desc, | ||||
| 			) | ||||
| 		} | ||||
| 		if err := checkDescConsistency(metricFamily, dtoMetric, desc); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	metricFamily.Metric = append(metricFamily.Metric, dtoMetric) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Gatherers is a slice of Gatherer instances that implements the Gatherer | ||||
| // interface itself. Its Gather method calls Gather on all Gatherers in the | ||||
| // slice in order and returns the merged results. Errors returned from the | ||||
| // Gather calles are all returned in a flattened MultiError. Duplicate and | ||||
| // inconsistent Metrics are skipped (first occurrence in slice order wins) and | ||||
| // reported in the returned error. | ||||
| // | ||||
| // Gatherers can be used to merge the Gather results from multiple | ||||
| // Registries. It also provides a way to directly inject existing MetricFamily | ||||
| // protobufs into the gathering by creating a custom Gatherer with a Gather | ||||
| // method that simply returns the existing MetricFamily protobufs. Note that no | ||||
| // registration is involved (in contrast to Collector registration), so | ||||
| // obviously registration-time checks cannot happen. Any inconsistencies between | ||||
| // the gathered MetricFamilies are reported as errors by the Gather method, and | ||||
| // inconsistent Metrics are dropped. Invalid parts of the MetricFamilies | ||||
| // (e.g. syntactically invalid metric or label names) will go undetected. | ||||
| type Gatherers []Gatherer | ||||
|  | ||||
| // Gather implements Gatherer. | ||||
| func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) { | ||||
| 	var ( | ||||
| 		metricFamiliesByName = map[string]*dto.MetricFamily{} | ||||
| 		metricHashes         = map[uint64]struct{}{} | ||||
| 		errs                 MultiError // The collected errors to return in the end. | ||||
| 	) | ||||
|  | ||||
| 	for i, g := range gs { | ||||
| 		mfs, err := g.Gather() | ||||
| 		if err != nil { | ||||
| 			if multiErr, ok := err.(MultiError); ok { | ||||
| 				for _, err := range multiErr { | ||||
| 					errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err)) | ||||
| 				} | ||||
| 			} else { | ||||
| 				errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err)) | ||||
| 			} | ||||
| 		} | ||||
| 		for _, mf := range mfs { | ||||
| 			existingMF, exists := metricFamiliesByName[mf.GetName()] | ||||
| 			if exists { | ||||
| 				if existingMF.GetHelp() != mf.GetHelp() { | ||||
| 					errs = append(errs, fmt.Errorf( | ||||
| 						"gathered metric family %s has help %q but should have %q", | ||||
| 						mf.GetName(), mf.GetHelp(), existingMF.GetHelp(), | ||||
| 					)) | ||||
| 					continue | ||||
| 				} | ||||
| 				if existingMF.GetType() != mf.GetType() { | ||||
| 					errs = append(errs, fmt.Errorf( | ||||
| 						"gathered metric family %s has type %s but should have %s", | ||||
| 						mf.GetName(), mf.GetType(), existingMF.GetType(), | ||||
| 					)) | ||||
| 					continue | ||||
| 				} | ||||
| 			} else { | ||||
| 				existingMF = &dto.MetricFamily{} | ||||
| 				existingMF.Name = mf.Name | ||||
| 				existingMF.Help = mf.Help | ||||
| 				existingMF.Type = mf.Type | ||||
| 				if err := checkSuffixCollisions(existingMF, metricFamiliesByName); err != nil { | ||||
| 					errs = append(errs, err) | ||||
| 					continue | ||||
| 				} | ||||
| 				metricFamiliesByName[mf.GetName()] = existingMF | ||||
| 			} | ||||
| 			for _, m := range mf.Metric { | ||||
| 				if err := checkMetricConsistency(existingMF, m, metricHashes); err != nil { | ||||
| 					errs = append(errs, err) | ||||
| 					continue | ||||
| 				} | ||||
| 				existingMF.Metric = append(existingMF.Metric, m) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() | ||||
| } | ||||
|  | ||||
| // checkSuffixCollisions checks for collisions with the “magic” suffixes the | ||||
| // Prometheus text format and the internal metric representation of the | ||||
| // Prometheus server add while flattening Summaries and Histograms. | ||||
| func checkSuffixCollisions(mf *dto.MetricFamily, mfs map[string]*dto.MetricFamily) error { | ||||
| 	var ( | ||||
| 		newName              = mf.GetName() | ||||
| 		newType              = mf.GetType() | ||||
| 		newNameWithoutSuffix = "" | ||||
| 	) | ||||
| 	switch { | ||||
| 	case strings.HasSuffix(newName, "_count"): | ||||
| 		newNameWithoutSuffix = newName[:len(newName)-6] | ||||
| 	case strings.HasSuffix(newName, "_sum"): | ||||
| 		newNameWithoutSuffix = newName[:len(newName)-4] | ||||
| 	case strings.HasSuffix(newName, "_bucket"): | ||||
| 		newNameWithoutSuffix = newName[:len(newName)-7] | ||||
| 	} | ||||
| 	if newNameWithoutSuffix != "" { | ||||
| 		if existingMF, ok := mfs[newNameWithoutSuffix]; ok { | ||||
| 			switch existingMF.GetType() { | ||||
| 			case dto.MetricType_SUMMARY: | ||||
| 				if !strings.HasSuffix(newName, "_bucket") { | ||||
| 					return fmt.Errorf( | ||||
| 						"collected metric named %q collides with previously collected summary named %q", | ||||
| 						newName, newNameWithoutSuffix, | ||||
| 					) | ||||
| 				} | ||||
| 			case dto.MetricType_HISTOGRAM: | ||||
| 				return fmt.Errorf( | ||||
| 					"collected metric named %q collides with previously collected histogram named %q", | ||||
| 					newName, newNameWithoutSuffix, | ||||
| 				) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if newType == dto.MetricType_SUMMARY || newType == dto.MetricType_HISTOGRAM { | ||||
| 		if _, ok := mfs[newName+"_count"]; ok { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected histogram or summary named %q collides with previously collected metric named %q", | ||||
| 				newName, newName+"_count", | ||||
| 			) | ||||
| 		} | ||||
| 		if _, ok := mfs[newName+"_sum"]; ok { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected histogram or summary named %q collides with previously collected metric named %q", | ||||
| 				newName, newName+"_sum", | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
| 	if newType == dto.MetricType_HISTOGRAM { | ||||
| 		if _, ok := mfs[newName+"_bucket"]; ok { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected histogram named %q collides with previously collected metric named %q", | ||||
| 				newName, newName+"_bucket", | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // checkMetricConsistency checks if the provided Metric is consistent with the | ||||
| // provided MetricFamily. It also hashes the Metric labels and the MetricFamily | ||||
| // name. If the resulting hash is already in the provided metricHashes, an error | ||||
| // is returned. If not, it is added to metricHashes. | ||||
| func checkMetricConsistency( | ||||
| 	metricFamily *dto.MetricFamily, | ||||
| 	dtoMetric *dto.Metric, | ||||
| 	metricHashes map[uint64]struct{}, | ||||
| ) error { | ||||
| 	name := metricFamily.GetName() | ||||
|  | ||||
| 	// 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 %q { %s} is not a %s", | ||||
| 			name, dtoMetric, metricFamily.GetType(), | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	previousLabelName := "" | ||||
| 	for _, labelPair := range dtoMetric.GetLabel() { | ||||
| 		labelName := labelPair.GetName() | ||||
| 		if labelName == previousLabelName { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %q { %s} has two or more labels with the same name: %s", | ||||
| 				name, dtoMetric, labelName, | ||||
| 			) | ||||
| 		} | ||||
| 		if !checkLabelName(labelName) { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %q { %s} has a label with an invalid name: %s", | ||||
| 				name, dtoMetric, labelName, | ||||
| 			) | ||||
| 		} | ||||
| 		if dtoMetric.Summary != nil && labelName == quantileLabel { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %q { %s} must not have an explicit %q label", | ||||
| 				name, dtoMetric, quantileLabel, | ||||
| 			) | ||||
| 		} | ||||
| 		if !utf8.ValidString(labelPair.GetValue()) { | ||||
| 			return fmt.Errorf( | ||||
| 				"collected metric %q { %s} has a label named %q whose value is not utf8: %#v", | ||||
| 				name, dtoMetric, labelName, labelPair.GetValue()) | ||||
| 		} | ||||
| 		previousLabelName = labelName | ||||
| 	} | ||||
|  | ||||
| 	// Is the metric unique (i.e. no other metric with the same name and the same labels)? | ||||
| 	h := hashNew() | ||||
| 	h = hashAdd(h, name) | ||||
| 	h = hashAddByte(h, separatorByte) | ||||
| 	// Make sure label pairs are sorted. We depend on it for the consistency | ||||
| 	// check. | ||||
| 	sort.Sort(labelPairSorter(dtoMetric.Label)) | ||||
| 	for _, lp := range dtoMetric.Label { | ||||
| 		h = hashAdd(h, lp.GetName()) | ||||
| 		h = hashAddByte(h, separatorByte) | ||||
| 		h = hashAdd(h, lp.GetValue()) | ||||
| 		h = hashAddByte(h, separatorByte) | ||||
| 	} | ||||
| 	if _, exists := metricHashes[h]; exists { | ||||
| 		return fmt.Errorf( | ||||
| 			"collected metric %q { %s} was collected before with the same name and label values", | ||||
| 			name, dtoMetric, | ||||
| 		) | ||||
| 	} | ||||
| 	metricHashes[h] = struct{}{} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func checkDescConsistency( | ||||
| 	metricFamily *dto.MetricFamily, | ||||
| 	dtoMetric *dto.Metric, | ||||
| 	desc *Desc, | ||||
| ) error { | ||||
| 	// Desc help consistency with metric family help. | ||||
| 	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, | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										626
									
								
								vendor/github.com/prometheus/client_golang/prometheus/summary.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										626
									
								
								vendor/github.com/prometheus/client_golang/prometheus/summary.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,626 @@ | ||||
| // 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" | ||||
| 	"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. However, the default behavior will change in the | ||||
| // upcoming v0.10 of the library. There will be no rank estimations at all by | ||||
| // default. For a sane transition, it is recommended to set the desired rank | ||||
| // estimations explicitly. | ||||
| // | ||||
| // 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) | ||||
| } | ||||
|  | ||||
| // DefObjectives are the default Summary quantile values. | ||||
| // | ||||
| // Deprecated: DefObjectives will not be used as the default objectives in | ||||
| // v0.10 of the library. The default Summary will have no quantiles then. | ||||
| var ( | ||||
| 	DefObjectives = map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001} | ||||
|  | ||||
| 	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 to a non-empty string. While all other fields are | ||||
| // optional and can safely be left at their zero value, it is recommended to set | ||||
| // a help string and to explicitly set the Objectives field to the desired value | ||||
| // as the default value will change in the upcoming v0.10 of the library. | ||||
| 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. | ||||
| 	// | ||||
| 	// 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. | ||||
| 	// | ||||
| 	// Due to the way a Summary is represented in the Prometheus text format | ||||
| 	// and how it is handled by the Prometheus server internally, “quantile” | ||||
| 	// is an illegal label name. Construction of a Summary or SummaryVec | ||||
| 	// will panic if this label name is used in ConstLabels. | ||||
| 	// | ||||
| 	// ConstLabels are only used rarely. In particular, do not use them to | ||||
| 	// attach the same labels to all your metrics. Those use cases are | ||||
| 	// better covered by target labels set by the scraping Prometheus | ||||
| 	// server, or by one specific metric (e.g. a build_info or a | ||||
| 	// machine_role metric). See also | ||||
| 	// https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels,-not-static-scraped-labels | ||||
| 	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. It is used if Objectives is left at | ||||
| 	// its zero value (i.e. nil). To create a Summary without Objectives, | ||||
| 	// set it to an empty map (i.e. map[float64]float64{}). | ||||
| 	// | ||||
| 	// Deprecated: Note that the current value of DefObjectives is | ||||
| 	// deprecated. It will be replaced by an empty map in v0.10 of the | ||||
| 	// library. Please explicitly set Objectives to the desired value. | ||||
| 	Objectives map[float64]float64 | ||||
|  | ||||
| 	// MaxAge defines the duration for which an observation stays relevant | ||||
| 	// 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 | ||||
| } | ||||
|  | ||||
| // 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(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) | ||||
| 	} | ||||
|  | ||||
| 	for _, n := range desc.variableLabels { | ||||
| 		if n == quantileLabel { | ||||
| 			panic(errQuantileLabelNotAllowed) | ||||
| 		} | ||||
| 	} | ||||
| 	for _, lp := range desc.constLabelPairs { | ||||
| 		if lp.GetName() == quantileLabel { | ||||
| 			panic(errQuantileLabelNotAllowed) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if opts.Objectives == nil { | ||||
| 		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. | ||||
| // | ||||
| // Due to the way a Summary is represented in the Prometheus text format and how | ||||
| // it is handled by the Prometheus server internally, “quantile” is an illegal | ||||
| // label name. NewSummaryVec will panic if this label name is used. | ||||
| func NewSummaryVec(opts SummaryOpts, labelNames []string) *SummaryVec { | ||||
| 	for _, ln := range labelNames { | ||||
| 		if ln == quantileLabel { | ||||
| 			panic(errQuantileLabelNotAllowed) | ||||
| 		} | ||||
| 	} | ||||
| 	desc := NewDesc( | ||||
| 		BuildFQName(opts.Namespace, opts.Subsystem, opts.Name), | ||||
| 		opts.Help, | ||||
| 		labelNames, | ||||
| 		opts.ConstLabels, | ||||
| 	) | ||||
| 	return &SummaryVec{ | ||||
| 		metricVec: newMetricVec(desc, func(lvs ...string) Metric { | ||||
| 			return newSummary(desc, opts, lvs...) | ||||
| 		}), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetMetricWithLabelValues returns the Summary 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 Summary is created. | ||||
| // | ||||
| // It is possible to call this method without using the returned Summary to only | ||||
| // create the new Summary but leave it at its starting value, a Summary without | ||||
| // any observations. | ||||
| // | ||||
| // Keeping the Summary 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 Summary from the SummaryVec. In that case, | ||||
| // the Summary will still exist, but it will not be exported anymore, even if a | ||||
| // Summary 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 (minus any curried labels). | ||||
| // | ||||
| // 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 (v *SummaryVec) GetMetricWithLabelValues(lvs ...string) (Observer, error) { | ||||
| 	metric, err := v.metricVec.getMetricWithLabelValues(lvs...) | ||||
| 	if metric != nil { | ||||
| 		return metric.(Observer), err | ||||
| 	} | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| // GetMetricWith returns the Summary 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 Summary is created. Implications of | ||||
| // creating a Summary without using it and keeping the Summary 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 (minus any curried labels). | ||||
| // | ||||
| // This method is used for the same purpose as | ||||
| // GetMetricWithLabelValues(...string). See there for pros and cons of the two | ||||
| // methods. | ||||
| func (v *SummaryVec) GetMetricWith(labels Labels) (Observer, error) { | ||||
| 	metric, err := v.metricVec.getMetricWith(labels) | ||||
| 	if metric != nil { | ||||
| 		return metric.(Observer), err | ||||
| 	} | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| // WithLabelValues works as GetMetricWithLabelValues, but panics where | ||||
| // GetMetricWithLabelValues would have returned an error. Not returning an | ||||
| // error allows shortcuts like | ||||
| //     myVec.WithLabelValues("404", "GET").Observe(42.21) | ||||
| func (v *SummaryVec) WithLabelValues(lvs ...string) Observer { | ||||
| 	s, err := v.GetMetricWithLabelValues(lvs...) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // With works as GetMetricWith, but panics where GetMetricWithLabels would have | ||||
| // returned an error. Not returning an error allows shortcuts like | ||||
| //     myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Observe(42.21) | ||||
| func (v *SummaryVec) With(labels Labels) Observer { | ||||
| 	s, err := v.GetMetricWith(labels) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| // CurryWith returns a vector curried with the provided labels, i.e. the | ||||
| // returned vector has those labels pre-set for all labeled operations performed | ||||
| // on it. The cardinality of the curried vector is reduced accordingly. The | ||||
| // order of the remaining labels stays the same (just with the curried labels | ||||
| // taken out of the sequence – which is relevant for the | ||||
| // (GetMetric)WithLabelValues methods). It is possible to curry a curried | ||||
| // vector, but only with labels not yet used for currying before. | ||||
| // | ||||
| // The metrics contained in the SummaryVec are shared between the curried and | ||||
| // uncurried vectors. They are just accessed differently. Curried and uncurried | ||||
| // vectors behave identically in terms of collection. Only one must be | ||||
| // registered with a given registry (usually the uncurried version). The Reset | ||||
| // method deletes all metrics, even if called on a curried vector. | ||||
| func (v *SummaryVec) CurryWith(labels Labels) (ObserverVec, error) { | ||||
| 	vec, err := v.curryWith(labels) | ||||
| 	if vec != nil { | ||||
| 		return &SummaryVec{vec}, err | ||||
| 	} | ||||
| 	return nil, err | ||||
| } | ||||
|  | ||||
| // MustCurryWith works as CurryWith but panics where CurryWith would have | ||||
| // returned an error. | ||||
| func (v *SummaryVec) MustCurryWith(labels Labels) ObserverVec { | ||||
| 	vec, err := v.CurryWith(labels) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return vec | ||||
| } | ||||
|  | ||||
| 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 or if Desc is invalid. | ||||
| func NewConstSummary( | ||||
| 	desc *Desc, | ||||
| 	count uint64, | ||||
| 	sum float64, | ||||
| 	quantiles map[float64]float64, | ||||
| 	labelValues ...string, | ||||
| ) (Metric, error) { | ||||
| 	if desc.err != nil { | ||||
| 		return nil, desc.err | ||||
| 	} | ||||
| 	if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	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 | ||||
| } | ||||
							
								
								
									
										51
									
								
								vendor/github.com/prometheus/client_golang/prometheus/timer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								vendor/github.com/prometheus/client_golang/prometheus/timer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| // Copyright 2016 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package prometheus | ||||
|  | ||||
| import "time" | ||||
|  | ||||
| // Timer is a helper type to time functions. Use NewTimer to create new | ||||
| // instances. | ||||
| type Timer struct { | ||||
| 	begin    time.Time | ||||
| 	observer Observer | ||||
| } | ||||
|  | ||||
| // NewTimer creates a new Timer. The provided Observer is used to observe a | ||||
| // duration in seconds. Timer is usually used to time a function call in the | ||||
| // following way: | ||||
| //    func TimeMe() { | ||||
| //        timer := NewTimer(myHistogram) | ||||
| //        defer timer.ObserveDuration() | ||||
| //        // Do actual work. | ||||
| //    } | ||||
| func NewTimer(o Observer) *Timer { | ||||
| 	return &Timer{ | ||||
| 		begin:    time.Now(), | ||||
| 		observer: o, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ObserveDuration records the duration passed since the Timer was created with | ||||
| // NewTimer. It calls the Observe method of the Observer provided during | ||||
| // construction with the duration in seconds as an argument. ObserveDuration is | ||||
| // usually called with a defer statement. | ||||
| // | ||||
| // Note that this method is only guaranteed to never observe negative durations | ||||
| // if used with Go1.9+. | ||||
| func (t *Timer) ObserveDuration() { | ||||
| 	if t.observer != nil { | ||||
| 		t.observer.Observe(time.Since(t.begin).Seconds()) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										42
									
								
								vendor/github.com/prometheus/client_golang/prometheus/untyped.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/prometheus/client_golang/prometheus/untyped.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| // 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 | ||||
|  | ||||
| // UntypedOpts is an alias for Opts. See there for doc comments. | ||||
| type UntypedOpts Opts | ||||
|  | ||||
| // UntypedFunc works like GaugeFunc but the collected metric is of type | ||||
| // "Untyped". UntypedFunc is useful to mirror an external metric of unknown | ||||
| // type. | ||||
| // | ||||
| // 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) | ||||
| } | ||||
							
								
								
									
										162
									
								
								vendor/github.com/prometheus/client_golang/prometheus/value.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								vendor/github.com/prometheus/client_golang/prometheus/value.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| // 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" | ||||
| 	"sort" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| // 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 | ||||
| ) | ||||
|  | ||||
| // 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 or if Desc is | ||||
| // invalid. | ||||
| func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) { | ||||
| 	if desc.err != nil { | ||||
| 		return nil, desc.err | ||||
| 	} | ||||
| 	if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	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]), | ||||
| 		}) | ||||
| 	} | ||||
| 	labelPairs = append(labelPairs, desc.constLabelPairs...) | ||||
| 	sort.Sort(labelPairSorter(labelPairs)) | ||||
| 	return labelPairs | ||||
| } | ||||
							
								
								
									
										472
									
								
								vendor/github.com/prometheus/client_golang/prometheus/vec.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										472
									
								
								vendor/github.com/prometheus/client_golang/prometheus/vec.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,472 @@ | ||||
| // 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" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/prometheus/common/model" | ||||
| ) | ||||
|  | ||||
| // metricVec is a Collector to bundle metrics of the same name that differ in | ||||
| // their label values. metricVec is not used directly (and therefore | ||||
| // unexported). It is used as a building block for implementations of vectors of | ||||
| // a given metric type, like GaugeVec, CounterVec, SummaryVec, and HistogramVec. | ||||
| // It also handles label currying. It uses basicMetricVec internally. | ||||
| type metricVec struct { | ||||
| 	*metricMap | ||||
|  | ||||
| 	curry []curriedLabelValue | ||||
|  | ||||
| 	// hashAdd and hashAddByte can be replaced for testing collision handling. | ||||
| 	hashAdd     func(h uint64, s string) uint64 | ||||
| 	hashAddByte func(h uint64, b byte) uint64 | ||||
| } | ||||
|  | ||||
| // newMetricVec returns an initialized metricVec. | ||||
| func newMetricVec(desc *Desc, newMetric func(lvs ...string) Metric) *metricVec { | ||||
| 	return &metricVec{ | ||||
| 		metricMap: &metricMap{ | ||||
| 			metrics:   map[uint64][]metricWithLabelValues{}, | ||||
| 			desc:      desc, | ||||
| 			newMetric: newMetric, | ||||
| 		}, | ||||
| 		hashAdd:     hashAdd, | ||||
| 		hashAddByte: hashAddByte, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 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 { | ||||
| 	h, err := m.hashLabelValues(lvs) | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	return m.metricMap.deleteByHashWithLabelValues(h, lvs, m.curry) | ||||
| } | ||||
|  | ||||
| // 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 Desc. 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 { | ||||
| 	h, err := m.hashLabels(labels) | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	return m.metricMap.deleteByHashWithLabels(h, labels, m.curry) | ||||
| } | ||||
|  | ||||
| func (m *metricVec) curryWith(labels Labels) (*metricVec, error) { | ||||
| 	var ( | ||||
| 		newCurry []curriedLabelValue | ||||
| 		oldCurry = m.curry | ||||
| 		iCurry   int | ||||
| 	) | ||||
| 	for i, label := range m.desc.variableLabels { | ||||
| 		val, ok := labels[label] | ||||
| 		if iCurry < len(oldCurry) && oldCurry[iCurry].index == i { | ||||
| 			if ok { | ||||
| 				return nil, fmt.Errorf("label name %q is already curried", label) | ||||
| 			} | ||||
| 			newCurry = append(newCurry, oldCurry[iCurry]) | ||||
| 			iCurry++ | ||||
| 		} else { | ||||
| 			if !ok { | ||||
| 				continue // Label stays uncurried. | ||||
| 			} | ||||
| 			newCurry = append(newCurry, curriedLabelValue{i, val}) | ||||
| 		} | ||||
| 	} | ||||
| 	if l := len(oldCurry) + len(labels) - len(newCurry); l > 0 { | ||||
| 		return nil, fmt.Errorf("%d unknown label(s) found during currying", l) | ||||
| 	} | ||||
|  | ||||
| 	return &metricVec{ | ||||
| 		metricMap:   m.metricMap, | ||||
| 		curry:       newCurry, | ||||
| 		hashAdd:     m.hashAdd, | ||||
| 		hashAddByte: m.hashAddByte, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func (m *metricVec) getMetricWithLabelValues(lvs ...string) (Metric, error) { | ||||
| 	h, err := m.hashLabelValues(lvs) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return m.metricMap.getOrCreateMetricWithLabelValues(h, lvs, m.curry), nil | ||||
| } | ||||
|  | ||||
| func (m *metricVec) getMetricWith(labels Labels) (Metric, error) { | ||||
| 	h, err := m.hashLabels(labels) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return m.metricMap.getOrCreateMetricWithLabels(h, labels, m.curry), nil | ||||
| } | ||||
|  | ||||
| func (m *metricVec) hashLabelValues(vals []string) (uint64, error) { | ||||
| 	if err := validateLabelValues(vals, len(m.desc.variableLabels)-len(m.curry)); err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		h             = hashNew() | ||||
| 		curry         = m.curry | ||||
| 		iVals, iCurry int | ||||
| 	) | ||||
| 	for i := 0; i < len(m.desc.variableLabels); i++ { | ||||
| 		if iCurry < len(curry) && curry[iCurry].index == i { | ||||
| 			h = m.hashAdd(h, curry[iCurry].value) | ||||
| 			iCurry++ | ||||
| 		} else { | ||||
| 			h = m.hashAdd(h, vals[iVals]) | ||||
| 			iVals++ | ||||
| 		} | ||||
| 		h = m.hashAddByte(h, model.SeparatorByte) | ||||
| 	} | ||||
| 	return h, nil | ||||
| } | ||||
|  | ||||
| func (m *metricVec) hashLabels(labels Labels) (uint64, error) { | ||||
| 	if err := validateValuesInLabels(labels, len(m.desc.variableLabels)-len(m.curry)); err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		h      = hashNew() | ||||
| 		curry  = m.curry | ||||
| 		iCurry int | ||||
| 	) | ||||
| 	for i, label := range m.desc.variableLabels { | ||||
| 		val, ok := labels[label] | ||||
| 		if iCurry < len(curry) && curry[iCurry].index == i { | ||||
| 			if ok { | ||||
| 				return 0, fmt.Errorf("label name %q is already curried", label) | ||||
| 			} | ||||
| 			h = m.hashAdd(h, curry[iCurry].value) | ||||
| 			iCurry++ | ||||
| 		} else { | ||||
| 			if !ok { | ||||
| 				return 0, fmt.Errorf("label name %q missing in label map", label) | ||||
| 			} | ||||
| 			h = m.hashAdd(h, val) | ||||
| 		} | ||||
| 		h = m.hashAddByte(h, model.SeparatorByte) | ||||
| 	} | ||||
| 	return h, nil | ||||
| } | ||||
|  | ||||
| // metricWithLabelValues provides the metric and its label values for | ||||
| // disambiguation on hash collision. | ||||
| type metricWithLabelValues struct { | ||||
| 	values []string | ||||
| 	metric Metric | ||||
| } | ||||
|  | ||||
| // curriedLabelValue sets the curried value for a label at the given index. | ||||
| type curriedLabelValue struct { | ||||
| 	index int | ||||
| 	value string | ||||
| } | ||||
|  | ||||
| // metricMap is a helper for metricVec and shared between differently curried | ||||
| // metricVecs. | ||||
| type metricMap struct { | ||||
| 	mtx       sync.RWMutex // Protects metrics. | ||||
| 	metrics   map[uint64][]metricWithLabelValues | ||||
| 	desc      *Desc | ||||
| 	newMetric func(labelValues ...string) Metric | ||||
| } | ||||
|  | ||||
| // Describe implements Collector. It will send exactly one Desc to the provided | ||||
| // channel. | ||||
| func (m *metricMap) Describe(ch chan<- *Desc) { | ||||
| 	ch <- m.desc | ||||
| } | ||||
|  | ||||
| // Collect implements Collector. | ||||
| func (m *metricMap) Collect(ch chan<- Metric) { | ||||
| 	m.mtx.RLock() | ||||
| 	defer m.mtx.RUnlock() | ||||
|  | ||||
| 	for _, metrics := range m.metrics { | ||||
| 		for _, metric := range metrics { | ||||
| 			ch <- metric.metric | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Reset deletes all metrics in this vector. | ||||
| func (m *metricMap) Reset() { | ||||
| 	m.mtx.Lock() | ||||
| 	defer m.mtx.Unlock() | ||||
|  | ||||
| 	for h := range m.metrics { | ||||
| 		delete(m.metrics, h) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // deleteByHashWithLabelValues removes the metric from the hash bucket h. If | ||||
| // there are multiple matches in the bucket, use lvs to select a metric and | ||||
| // remove only that metric. | ||||
| func (m *metricMap) deleteByHashWithLabelValues( | ||||
| 	h uint64, lvs []string, curry []curriedLabelValue, | ||||
| ) bool { | ||||
| 	m.mtx.Lock() | ||||
| 	defer m.mtx.Unlock() | ||||
|  | ||||
| 	metrics, ok := m.metrics[h] | ||||
| 	if !ok { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	i := findMetricWithLabelValues(metrics, lvs, curry) | ||||
| 	if i >= len(metrics) { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	if len(metrics) > 1 { | ||||
| 		m.metrics[h] = append(metrics[:i], metrics[i+1:]...) | ||||
| 	} else { | ||||
| 		delete(m.metrics, h) | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // deleteByHashWithLabels removes the metric from the hash bucket h. If there | ||||
| // are multiple matches in the bucket, use lvs to select a metric and remove | ||||
| // only that metric. | ||||
| func (m *metricMap) deleteByHashWithLabels( | ||||
| 	h uint64, labels Labels, curry []curriedLabelValue, | ||||
| ) bool { | ||||
| 	m.mtx.Lock() | ||||
| 	defer m.mtx.Unlock() | ||||
|  | ||||
| 	metrics, ok := m.metrics[h] | ||||
| 	if !ok { | ||||
| 		return false | ||||
| 	} | ||||
| 	i := findMetricWithLabels(m.desc, metrics, labels, curry) | ||||
| 	if i >= len(metrics) { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	if len(metrics) > 1 { | ||||
| 		m.metrics[h] = append(metrics[:i], metrics[i+1:]...) | ||||
| 	} else { | ||||
| 		delete(m.metrics, h) | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // getOrCreateMetricWithLabelValues retrieves the metric by hash and label value | ||||
| // or creates it and returns the new one. | ||||
| // | ||||
| // This function holds the mutex. | ||||
| func (m *metricMap) getOrCreateMetricWithLabelValues( | ||||
| 	hash uint64, lvs []string, curry []curriedLabelValue, | ||||
| ) Metric { | ||||
| 	m.mtx.RLock() | ||||
| 	metric, ok := m.getMetricWithHashAndLabelValues(hash, lvs, curry) | ||||
| 	m.mtx.RUnlock() | ||||
| 	if ok { | ||||
| 		return metric | ||||
| 	} | ||||
|  | ||||
| 	m.mtx.Lock() | ||||
| 	defer m.mtx.Unlock() | ||||
| 	metric, ok = m.getMetricWithHashAndLabelValues(hash, lvs, curry) | ||||
| 	if !ok { | ||||
| 		inlinedLVs := inlineLabelValues(lvs, curry) | ||||
| 		metric = m.newMetric(inlinedLVs...) | ||||
| 		m.metrics[hash] = append(m.metrics[hash], metricWithLabelValues{values: inlinedLVs, metric: metric}) | ||||
| 	} | ||||
| 	return metric | ||||
| } | ||||
|  | ||||
| // getOrCreateMetricWithLabelValues retrieves the metric by hash and label value | ||||
| // or creates it and returns the new one. | ||||
| // | ||||
| // This function holds the mutex. | ||||
| func (m *metricMap) getOrCreateMetricWithLabels( | ||||
| 	hash uint64, labels Labels, curry []curriedLabelValue, | ||||
| ) Metric { | ||||
| 	m.mtx.RLock() | ||||
| 	metric, ok := m.getMetricWithHashAndLabels(hash, labels, curry) | ||||
| 	m.mtx.RUnlock() | ||||
| 	if ok { | ||||
| 		return metric | ||||
| 	} | ||||
|  | ||||
| 	m.mtx.Lock() | ||||
| 	defer m.mtx.Unlock() | ||||
| 	metric, ok = m.getMetricWithHashAndLabels(hash, labels, curry) | ||||
| 	if !ok { | ||||
| 		lvs := extractLabelValues(m.desc, labels, curry) | ||||
| 		metric = m.newMetric(lvs...) | ||||
| 		m.metrics[hash] = append(m.metrics[hash], metricWithLabelValues{values: lvs, metric: metric}) | ||||
| 	} | ||||
| 	return metric | ||||
| } | ||||
|  | ||||
| // getMetricWithHashAndLabelValues gets a metric while handling possible | ||||
| // collisions in the hash space. Must be called while holding the read mutex. | ||||
| func (m *metricMap) getMetricWithHashAndLabelValues( | ||||
| 	h uint64, lvs []string, curry []curriedLabelValue, | ||||
| ) (Metric, bool) { | ||||
| 	metrics, ok := m.metrics[h] | ||||
| 	if ok { | ||||
| 		if i := findMetricWithLabelValues(metrics, lvs, curry); i < len(metrics) { | ||||
| 			return metrics[i].metric, true | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, false | ||||
| } | ||||
|  | ||||
| // getMetricWithHashAndLabels gets a metric while handling possible collisions in | ||||
| // the hash space. Must be called while holding read mutex. | ||||
| func (m *metricMap) getMetricWithHashAndLabels( | ||||
| 	h uint64, labels Labels, curry []curriedLabelValue, | ||||
| ) (Metric, bool) { | ||||
| 	metrics, ok := m.metrics[h] | ||||
| 	if ok { | ||||
| 		if i := findMetricWithLabels(m.desc, metrics, labels, curry); i < len(metrics) { | ||||
| 			return metrics[i].metric, true | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, false | ||||
| } | ||||
|  | ||||
| // findMetricWithLabelValues returns the index of the matching metric or | ||||
| // len(metrics) if not found. | ||||
| func findMetricWithLabelValues( | ||||
| 	metrics []metricWithLabelValues, lvs []string, curry []curriedLabelValue, | ||||
| ) int { | ||||
| 	for i, metric := range metrics { | ||||
| 		if matchLabelValues(metric.values, lvs, curry) { | ||||
| 			return i | ||||
| 		} | ||||
| 	} | ||||
| 	return len(metrics) | ||||
| } | ||||
|  | ||||
| // findMetricWithLabels returns the index of the matching metric or len(metrics) | ||||
| // if not found. | ||||
| func findMetricWithLabels( | ||||
| 	desc *Desc, metrics []metricWithLabelValues, labels Labels, curry []curriedLabelValue, | ||||
| ) int { | ||||
| 	for i, metric := range metrics { | ||||
| 		if matchLabels(desc, metric.values, labels, curry) { | ||||
| 			return i | ||||
| 		} | ||||
| 	} | ||||
| 	return len(metrics) | ||||
| } | ||||
|  | ||||
| func matchLabelValues(values []string, lvs []string, curry []curriedLabelValue) bool { | ||||
| 	if len(values) != len(lvs)+len(curry) { | ||||
| 		return false | ||||
| 	} | ||||
| 	var iLVs, iCurry int | ||||
| 	for i, v := range values { | ||||
| 		if iCurry < len(curry) && curry[iCurry].index == i { | ||||
| 			if v != curry[iCurry].value { | ||||
| 				return false | ||||
| 			} | ||||
| 			iCurry++ | ||||
| 			continue | ||||
| 		} | ||||
| 		if v != lvs[iLVs] { | ||||
| 			return false | ||||
| 		} | ||||
| 		iLVs++ | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func matchLabels(desc *Desc, values []string, labels Labels, curry []curriedLabelValue) bool { | ||||
| 	if len(values) != len(labels)+len(curry) { | ||||
| 		return false | ||||
| 	} | ||||
| 	iCurry := 0 | ||||
| 	for i, k := range desc.variableLabels { | ||||
| 		if iCurry < len(curry) && curry[iCurry].index == i { | ||||
| 			if values[i] != curry[iCurry].value { | ||||
| 				return false | ||||
| 			} | ||||
| 			iCurry++ | ||||
| 			continue | ||||
| 		} | ||||
| 		if values[i] != labels[k] { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func extractLabelValues(desc *Desc, labels Labels, curry []curriedLabelValue) []string { | ||||
| 	labelValues := make([]string, len(labels)+len(curry)) | ||||
| 	iCurry := 0 | ||||
| 	for i, k := range desc.variableLabels { | ||||
| 		if iCurry < len(curry) && curry[iCurry].index == i { | ||||
| 			labelValues[i] = curry[iCurry].value | ||||
| 			iCurry++ | ||||
| 			continue | ||||
| 		} | ||||
| 		labelValues[i] = labels[k] | ||||
| 	} | ||||
| 	return labelValues | ||||
| } | ||||
|  | ||||
| func inlineLabelValues(lvs []string, curry []curriedLabelValue) []string { | ||||
| 	labelValues := make([]string, len(lvs)+len(curry)) | ||||
| 	var iCurry, iLVs int | ||||
| 	for i := range labelValues { | ||||
| 		if iCurry < len(curry) && curry[iCurry].index == i { | ||||
| 			labelValues[i] = curry[iCurry].value | ||||
| 			iCurry++ | ||||
| 			continue | ||||
| 		} | ||||
| 		labelValues[i] = lvs[iLVs] | ||||
| 		iLVs++ | ||||
| 	} | ||||
| 	return labelValues | ||||
| } | ||||
							
								
								
									
										179
									
								
								vendor/github.com/prometheus/client_golang/prometheus/wrap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								vendor/github.com/prometheus/client_golang/prometheus/wrap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,179 @@ | ||||
| // Copyright 2018 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" | ||||
| 	"sort" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| // WrapRegistererWith returns a Registerer wrapping the provided | ||||
| // Registerer. Collectors registered with the returned Registerer will be | ||||
| // registered with the wrapped Registerer in a modified way. The modified | ||||
| // Collector adds the provided Labels to all Metrics it collects (as | ||||
| // ConstLabels). The Metrics collected by the unmodified Collector must not | ||||
| // duplicate any of those labels. | ||||
| // | ||||
| // WrapRegistererWith provides a way to add fixed labels to a subset of | ||||
| // Collectors. It should not be used to add fixed labels to all metrics exposed. | ||||
| // | ||||
| // The Collector example demonstrates a use of WrapRegistererWith. | ||||
| func WrapRegistererWith(labels Labels, reg Registerer) Registerer { | ||||
| 	return &wrappingRegisterer{ | ||||
| 		wrappedRegisterer: reg, | ||||
| 		labels:            labels, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WrapRegistererWithPrefix returns a Registerer wrapping the provided | ||||
| // Registerer. Collectors registered with the returned Registerer will be | ||||
| // registered with the wrapped Registerer in a modified way. The modified | ||||
| // Collector adds the provided prefix to the name of all Metrics it collects. | ||||
| // | ||||
| // WrapRegistererWithPrefix is useful to have one place to prefix all metrics of | ||||
| // a sub-system. To make this work, register metrics of the sub-system with the | ||||
| // wrapping Registerer returned by WrapRegistererWithPrefix. It is rarely useful | ||||
| // to use the same prefix for all metrics exposed. In particular, do not prefix | ||||
| // metric names that are standardized across applications, as that would break | ||||
| // horizontal monitoring, for example the metrics provided by the Go collector | ||||
| // (see NewGoCollector) and the process collector (see NewProcessCollector). (In | ||||
| // fact, those metrics are already prefixed with “go_” or “process_”, | ||||
| // respectively.) | ||||
| func WrapRegistererWithPrefix(prefix string, reg Registerer) Registerer { | ||||
| 	return &wrappingRegisterer{ | ||||
| 		wrappedRegisterer: reg, | ||||
| 		prefix:            prefix, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type wrappingRegisterer struct { | ||||
| 	wrappedRegisterer Registerer | ||||
| 	prefix            string | ||||
| 	labels            Labels | ||||
| } | ||||
|  | ||||
| func (r *wrappingRegisterer) Register(c Collector) error { | ||||
| 	return r.wrappedRegisterer.Register(&wrappingCollector{ | ||||
| 		wrappedCollector: c, | ||||
| 		prefix:           r.prefix, | ||||
| 		labels:           r.labels, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (r *wrappingRegisterer) MustRegister(cs ...Collector) { | ||||
| 	for _, c := range cs { | ||||
| 		if err := r.Register(c); err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r *wrappingRegisterer) Unregister(c Collector) bool { | ||||
| 	return r.wrappedRegisterer.Unregister(&wrappingCollector{ | ||||
| 		wrappedCollector: c, | ||||
| 		prefix:           r.prefix, | ||||
| 		labels:           r.labels, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| type wrappingCollector struct { | ||||
| 	wrappedCollector Collector | ||||
| 	prefix           string | ||||
| 	labels           Labels | ||||
| } | ||||
|  | ||||
| func (c *wrappingCollector) Collect(ch chan<- Metric) { | ||||
| 	wrappedCh := make(chan Metric) | ||||
| 	go func() { | ||||
| 		c.wrappedCollector.Collect(wrappedCh) | ||||
| 		close(wrappedCh) | ||||
| 	}() | ||||
| 	for m := range wrappedCh { | ||||
| 		ch <- &wrappingMetric{ | ||||
| 			wrappedMetric: m, | ||||
| 			prefix:        c.prefix, | ||||
| 			labels:        c.labels, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *wrappingCollector) Describe(ch chan<- *Desc) { | ||||
| 	wrappedCh := make(chan *Desc) | ||||
| 	go func() { | ||||
| 		c.wrappedCollector.Describe(wrappedCh) | ||||
| 		close(wrappedCh) | ||||
| 	}() | ||||
| 	for desc := range wrappedCh { | ||||
| 		ch <- wrapDesc(desc, c.prefix, c.labels) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type wrappingMetric struct { | ||||
| 	wrappedMetric Metric | ||||
| 	prefix        string | ||||
| 	labels        Labels | ||||
| } | ||||
|  | ||||
| func (m *wrappingMetric) Desc() *Desc { | ||||
| 	return wrapDesc(m.wrappedMetric.Desc(), m.prefix, m.labels) | ||||
| } | ||||
|  | ||||
| func (m *wrappingMetric) Write(out *dto.Metric) error { | ||||
| 	if err := m.wrappedMetric.Write(out); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if len(m.labels) == 0 { | ||||
| 		// No wrapping labels. | ||||
| 		return nil | ||||
| 	} | ||||
| 	for ln, lv := range m.labels { | ||||
| 		out.Label = append(out.Label, &dto.LabelPair{ | ||||
| 			Name:  proto.String(ln), | ||||
| 			Value: proto.String(lv), | ||||
| 		}) | ||||
| 	} | ||||
| 	sort.Sort(labelPairSorter(out.Label)) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc { | ||||
| 	constLabels := Labels{} | ||||
| 	for _, lp := range desc.constLabelPairs { | ||||
| 		constLabels[*lp.Name] = *lp.Value | ||||
| 	} | ||||
| 	for ln, lv := range labels { | ||||
| 		if _, alreadyUsed := constLabels[ln]; alreadyUsed { | ||||
| 			return &Desc{ | ||||
| 				fqName:          desc.fqName, | ||||
| 				help:            desc.help, | ||||
| 				variableLabels:  desc.variableLabels, | ||||
| 				constLabelPairs: desc.constLabelPairs, | ||||
| 				err:             fmt.Errorf("attempted wrapping with already existing label name %q", ln), | ||||
| 			} | ||||
| 		} | ||||
| 		constLabels[ln] = lv | ||||
| 	} | ||||
| 	// NewDesc will do remaining validations. | ||||
| 	newDesc := NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels) | ||||
| 	// Propagate errors if there was any. This will override any errer | ||||
| 	// created by NewDesc above, i.e. earlier errors get precedence. | ||||
| 	if desc.err != nil { | ||||
| 		newDesc.err = desc.err | ||||
| 	} | ||||
| 	return newDesc | ||||
| } | ||||
							
								
								
									
										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. | ||||
							
								
								
									
										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/). | ||||
							
								
								
									
										629
									
								
								vendor/github.com/prometheus/client_model/go/metrics.pb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										629
									
								
								vendor/github.com/prometheus/client_model/go/metrics.pb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,629 @@ | ||||
| // Code generated by protoc-gen-go. DO NOT EDIT. | ||||
| // source: metrics.proto | ||||
|  | ||||
| package io_prometheus_client // import "github.com/prometheus/client_model/go" | ||||
|  | ||||
| import proto "github.com/golang/protobuf/proto" | ||||
| import fmt "fmt" | ||||
| import math "math" | ||||
|  | ||||
| // Reference imports to suppress errors if they are not otherwise used. | ||||
| var _ = proto.Marshal | ||||
| var _ = fmt.Errorf | ||||
| var _ = math.Inf | ||||
|  | ||||
| // This is a compile-time assertion to ensure that this generated file | ||||
| // is compatible with the proto package it is being compiled against. | ||||
| // A compilation error at this line likely means your copy of the | ||||
| // proto package needs to be updated. | ||||
| const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package | ||||
|  | ||||
| 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 | ||||
| } | ||||
| func (MetricType) EnumDescriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{0} | ||||
| } | ||||
|  | ||||
| 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_NoUnkeyedLiteral struct{} `json:"-"` | ||||
| 	XXX_unrecognized     []byte   `json:"-"` | ||||
| 	XXX_sizecache        int32    `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *LabelPair) Reset()         { *m = LabelPair{} } | ||||
| func (m *LabelPair) String() string { return proto.CompactTextString(m) } | ||||
| func (*LabelPair) ProtoMessage()    {} | ||||
| func (*LabelPair) Descriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{0} | ||||
| } | ||||
| func (m *LabelPair) XXX_Unmarshal(b []byte) error { | ||||
| 	return xxx_messageInfo_LabelPair.Unmarshal(m, b) | ||||
| } | ||||
| func (m *LabelPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||
| 	return xxx_messageInfo_LabelPair.Marshal(b, m, deterministic) | ||||
| } | ||||
| func (dst *LabelPair) XXX_Merge(src proto.Message) { | ||||
| 	xxx_messageInfo_LabelPair.Merge(dst, src) | ||||
| } | ||||
| func (m *LabelPair) XXX_Size() int { | ||||
| 	return xxx_messageInfo_LabelPair.Size(m) | ||||
| } | ||||
| func (m *LabelPair) XXX_DiscardUnknown() { | ||||
| 	xxx_messageInfo_LabelPair.DiscardUnknown(m) | ||||
| } | ||||
|  | ||||
| var xxx_messageInfo_LabelPair proto.InternalMessageInfo | ||||
|  | ||||
| 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_NoUnkeyedLiteral struct{} `json:"-"` | ||||
| 	XXX_unrecognized     []byte   `json:"-"` | ||||
| 	XXX_sizecache        int32    `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *Gauge) Reset()         { *m = Gauge{} } | ||||
| func (m *Gauge) String() string { return proto.CompactTextString(m) } | ||||
| func (*Gauge) ProtoMessage()    {} | ||||
| func (*Gauge) Descriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{1} | ||||
| } | ||||
| func (m *Gauge) XXX_Unmarshal(b []byte) error { | ||||
| 	return xxx_messageInfo_Gauge.Unmarshal(m, b) | ||||
| } | ||||
| func (m *Gauge) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||
| 	return xxx_messageInfo_Gauge.Marshal(b, m, deterministic) | ||||
| } | ||||
| func (dst *Gauge) XXX_Merge(src proto.Message) { | ||||
| 	xxx_messageInfo_Gauge.Merge(dst, src) | ||||
| } | ||||
| func (m *Gauge) XXX_Size() int { | ||||
| 	return xxx_messageInfo_Gauge.Size(m) | ||||
| } | ||||
| func (m *Gauge) XXX_DiscardUnknown() { | ||||
| 	xxx_messageInfo_Gauge.DiscardUnknown(m) | ||||
| } | ||||
|  | ||||
| var xxx_messageInfo_Gauge proto.InternalMessageInfo | ||||
|  | ||||
| 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_NoUnkeyedLiteral struct{} `json:"-"` | ||||
| 	XXX_unrecognized     []byte   `json:"-"` | ||||
| 	XXX_sizecache        int32    `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *Counter) Reset()         { *m = Counter{} } | ||||
| func (m *Counter) String() string { return proto.CompactTextString(m) } | ||||
| func (*Counter) ProtoMessage()    {} | ||||
| func (*Counter) Descriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{2} | ||||
| } | ||||
| func (m *Counter) XXX_Unmarshal(b []byte) error { | ||||
| 	return xxx_messageInfo_Counter.Unmarshal(m, b) | ||||
| } | ||||
| func (m *Counter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||
| 	return xxx_messageInfo_Counter.Marshal(b, m, deterministic) | ||||
| } | ||||
| func (dst *Counter) XXX_Merge(src proto.Message) { | ||||
| 	xxx_messageInfo_Counter.Merge(dst, src) | ||||
| } | ||||
| func (m *Counter) XXX_Size() int { | ||||
| 	return xxx_messageInfo_Counter.Size(m) | ||||
| } | ||||
| func (m *Counter) XXX_DiscardUnknown() { | ||||
| 	xxx_messageInfo_Counter.DiscardUnknown(m) | ||||
| } | ||||
|  | ||||
| var xxx_messageInfo_Counter proto.InternalMessageInfo | ||||
|  | ||||
| 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_NoUnkeyedLiteral struct{} `json:"-"` | ||||
| 	XXX_unrecognized     []byte   `json:"-"` | ||||
| 	XXX_sizecache        int32    `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *Quantile) Reset()         { *m = Quantile{} } | ||||
| func (m *Quantile) String() string { return proto.CompactTextString(m) } | ||||
| func (*Quantile) ProtoMessage()    {} | ||||
| func (*Quantile) Descriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{3} | ||||
| } | ||||
| func (m *Quantile) XXX_Unmarshal(b []byte) error { | ||||
| 	return xxx_messageInfo_Quantile.Unmarshal(m, b) | ||||
| } | ||||
| func (m *Quantile) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||
| 	return xxx_messageInfo_Quantile.Marshal(b, m, deterministic) | ||||
| } | ||||
| func (dst *Quantile) XXX_Merge(src proto.Message) { | ||||
| 	xxx_messageInfo_Quantile.Merge(dst, src) | ||||
| } | ||||
| func (m *Quantile) XXX_Size() int { | ||||
| 	return xxx_messageInfo_Quantile.Size(m) | ||||
| } | ||||
| func (m *Quantile) XXX_DiscardUnknown() { | ||||
| 	xxx_messageInfo_Quantile.DiscardUnknown(m) | ||||
| } | ||||
|  | ||||
| var xxx_messageInfo_Quantile proto.InternalMessageInfo | ||||
|  | ||||
| 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=sampleCount" json:"sample_count,omitempty"` | ||||
| 	SampleSum            *float64    `protobuf:"fixed64,2,opt,name=sample_sum,json=sampleSum" json:"sample_sum,omitempty"` | ||||
| 	Quantile             []*Quantile `protobuf:"bytes,3,rep,name=quantile" json:"quantile,omitempty"` | ||||
| 	XXX_NoUnkeyedLiteral struct{}    `json:"-"` | ||||
| 	XXX_unrecognized     []byte      `json:"-"` | ||||
| 	XXX_sizecache        int32       `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *Summary) Reset()         { *m = Summary{} } | ||||
| func (m *Summary) String() string { return proto.CompactTextString(m) } | ||||
| func (*Summary) ProtoMessage()    {} | ||||
| func (*Summary) Descriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{4} | ||||
| } | ||||
| func (m *Summary) XXX_Unmarshal(b []byte) error { | ||||
| 	return xxx_messageInfo_Summary.Unmarshal(m, b) | ||||
| } | ||||
| func (m *Summary) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||
| 	return xxx_messageInfo_Summary.Marshal(b, m, deterministic) | ||||
| } | ||||
| func (dst *Summary) XXX_Merge(src proto.Message) { | ||||
| 	xxx_messageInfo_Summary.Merge(dst, src) | ||||
| } | ||||
| func (m *Summary) XXX_Size() int { | ||||
| 	return xxx_messageInfo_Summary.Size(m) | ||||
| } | ||||
| func (m *Summary) XXX_DiscardUnknown() { | ||||
| 	xxx_messageInfo_Summary.DiscardUnknown(m) | ||||
| } | ||||
|  | ||||
| var xxx_messageInfo_Summary proto.InternalMessageInfo | ||||
|  | ||||
| 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_NoUnkeyedLiteral struct{} `json:"-"` | ||||
| 	XXX_unrecognized     []byte   `json:"-"` | ||||
| 	XXX_sizecache        int32    `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *Untyped) Reset()         { *m = Untyped{} } | ||||
| func (m *Untyped) String() string { return proto.CompactTextString(m) } | ||||
| func (*Untyped) ProtoMessage()    {} | ||||
| func (*Untyped) Descriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{5} | ||||
| } | ||||
| func (m *Untyped) XXX_Unmarshal(b []byte) error { | ||||
| 	return xxx_messageInfo_Untyped.Unmarshal(m, b) | ||||
| } | ||||
| func (m *Untyped) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||
| 	return xxx_messageInfo_Untyped.Marshal(b, m, deterministic) | ||||
| } | ||||
| func (dst *Untyped) XXX_Merge(src proto.Message) { | ||||
| 	xxx_messageInfo_Untyped.Merge(dst, src) | ||||
| } | ||||
| func (m *Untyped) XXX_Size() int { | ||||
| 	return xxx_messageInfo_Untyped.Size(m) | ||||
| } | ||||
| func (m *Untyped) XXX_DiscardUnknown() { | ||||
| 	xxx_messageInfo_Untyped.DiscardUnknown(m) | ||||
| } | ||||
|  | ||||
| var xxx_messageInfo_Untyped proto.InternalMessageInfo | ||||
|  | ||||
| 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=sampleCount" json:"sample_count,omitempty"` | ||||
| 	SampleSum            *float64  `protobuf:"fixed64,2,opt,name=sample_sum,json=sampleSum" json:"sample_sum,omitempty"` | ||||
| 	Bucket               []*Bucket `protobuf:"bytes,3,rep,name=bucket" json:"bucket,omitempty"` | ||||
| 	XXX_NoUnkeyedLiteral struct{}  `json:"-"` | ||||
| 	XXX_unrecognized     []byte    `json:"-"` | ||||
| 	XXX_sizecache        int32     `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *Histogram) Reset()         { *m = Histogram{} } | ||||
| func (m *Histogram) String() string { return proto.CompactTextString(m) } | ||||
| func (*Histogram) ProtoMessage()    {} | ||||
| func (*Histogram) Descriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{6} | ||||
| } | ||||
| func (m *Histogram) XXX_Unmarshal(b []byte) error { | ||||
| 	return xxx_messageInfo_Histogram.Unmarshal(m, b) | ||||
| } | ||||
| func (m *Histogram) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||
| 	return xxx_messageInfo_Histogram.Marshal(b, m, deterministic) | ||||
| } | ||||
| func (dst *Histogram) XXX_Merge(src proto.Message) { | ||||
| 	xxx_messageInfo_Histogram.Merge(dst, src) | ||||
| } | ||||
| func (m *Histogram) XXX_Size() int { | ||||
| 	return xxx_messageInfo_Histogram.Size(m) | ||||
| } | ||||
| func (m *Histogram) XXX_DiscardUnknown() { | ||||
| 	xxx_messageInfo_Histogram.DiscardUnknown(m) | ||||
| } | ||||
|  | ||||
| var xxx_messageInfo_Histogram proto.InternalMessageInfo | ||||
|  | ||||
| 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=cumulativeCount" json:"cumulative_count,omitempty"` | ||||
| 	UpperBound           *float64 `protobuf:"fixed64,2,opt,name=upper_bound,json=upperBound" json:"upper_bound,omitempty"` | ||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||
| 	XXX_unrecognized     []byte   `json:"-"` | ||||
| 	XXX_sizecache        int32    `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *Bucket) Reset()         { *m = Bucket{} } | ||||
| func (m *Bucket) String() string { return proto.CompactTextString(m) } | ||||
| func (*Bucket) ProtoMessage()    {} | ||||
| func (*Bucket) Descriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{7} | ||||
| } | ||||
| func (m *Bucket) XXX_Unmarshal(b []byte) error { | ||||
| 	return xxx_messageInfo_Bucket.Unmarshal(m, b) | ||||
| } | ||||
| func (m *Bucket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||
| 	return xxx_messageInfo_Bucket.Marshal(b, m, deterministic) | ||||
| } | ||||
| func (dst *Bucket) XXX_Merge(src proto.Message) { | ||||
| 	xxx_messageInfo_Bucket.Merge(dst, src) | ||||
| } | ||||
| func (m *Bucket) XXX_Size() int { | ||||
| 	return xxx_messageInfo_Bucket.Size(m) | ||||
| } | ||||
| func (m *Bucket) XXX_DiscardUnknown() { | ||||
| 	xxx_messageInfo_Bucket.DiscardUnknown(m) | ||||
| } | ||||
|  | ||||
| var xxx_messageInfo_Bucket proto.InternalMessageInfo | ||||
|  | ||||
| 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=timestampMs" json:"timestamp_ms,omitempty"` | ||||
| 	XXX_NoUnkeyedLiteral struct{}     `json:"-"` | ||||
| 	XXX_unrecognized     []byte       `json:"-"` | ||||
| 	XXX_sizecache        int32        `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *Metric) Reset()         { *m = Metric{} } | ||||
| func (m *Metric) String() string { return proto.CompactTextString(m) } | ||||
| func (*Metric) ProtoMessage()    {} | ||||
| func (*Metric) Descriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{8} | ||||
| } | ||||
| func (m *Metric) XXX_Unmarshal(b []byte) error { | ||||
| 	return xxx_messageInfo_Metric.Unmarshal(m, b) | ||||
| } | ||||
| func (m *Metric) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||
| 	return xxx_messageInfo_Metric.Marshal(b, m, deterministic) | ||||
| } | ||||
| func (dst *Metric) XXX_Merge(src proto.Message) { | ||||
| 	xxx_messageInfo_Metric.Merge(dst, src) | ||||
| } | ||||
| func (m *Metric) XXX_Size() int { | ||||
| 	return xxx_messageInfo_Metric.Size(m) | ||||
| } | ||||
| func (m *Metric) XXX_DiscardUnknown() { | ||||
| 	xxx_messageInfo_Metric.DiscardUnknown(m) | ||||
| } | ||||
|  | ||||
| var xxx_messageInfo_Metric proto.InternalMessageInfo | ||||
|  | ||||
| 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_NoUnkeyedLiteral struct{}    `json:"-"` | ||||
| 	XXX_unrecognized     []byte      `json:"-"` | ||||
| 	XXX_sizecache        int32       `json:"-"` | ||||
| } | ||||
|  | ||||
| func (m *MetricFamily) Reset()         { *m = MetricFamily{} } | ||||
| func (m *MetricFamily) String() string { return proto.CompactTextString(m) } | ||||
| func (*MetricFamily) ProtoMessage()    {} | ||||
| func (*MetricFamily) Descriptor() ([]byte, []int) { | ||||
| 	return fileDescriptor_metrics_c97c9a2b9560cb8f, []int{9} | ||||
| } | ||||
| func (m *MetricFamily) XXX_Unmarshal(b []byte) error { | ||||
| 	return xxx_messageInfo_MetricFamily.Unmarshal(m, b) | ||||
| } | ||||
| func (m *MetricFamily) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||
| 	return xxx_messageInfo_MetricFamily.Marshal(b, m, deterministic) | ||||
| } | ||||
| func (dst *MetricFamily) XXX_Merge(src proto.Message) { | ||||
| 	xxx_messageInfo_MetricFamily.Merge(dst, src) | ||||
| } | ||||
| func (m *MetricFamily) XXX_Size() int { | ||||
| 	return xxx_messageInfo_MetricFamily.Size(m) | ||||
| } | ||||
| func (m *MetricFamily) XXX_DiscardUnknown() { | ||||
| 	xxx_messageInfo_MetricFamily.DiscardUnknown(m) | ||||
| } | ||||
|  | ||||
| var xxx_messageInfo_MetricFamily proto.InternalMessageInfo | ||||
|  | ||||
| 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.RegisterType((*LabelPair)(nil), "io.prometheus.client.LabelPair") | ||||
| 	proto.RegisterType((*Gauge)(nil), "io.prometheus.client.Gauge") | ||||
| 	proto.RegisterType((*Counter)(nil), "io.prometheus.client.Counter") | ||||
| 	proto.RegisterType((*Quantile)(nil), "io.prometheus.client.Quantile") | ||||
| 	proto.RegisterType((*Summary)(nil), "io.prometheus.client.Summary") | ||||
| 	proto.RegisterType((*Untyped)(nil), "io.prometheus.client.Untyped") | ||||
| 	proto.RegisterType((*Histogram)(nil), "io.prometheus.client.Histogram") | ||||
| 	proto.RegisterType((*Bucket)(nil), "io.prometheus.client.Bucket") | ||||
| 	proto.RegisterType((*Metric)(nil), "io.prometheus.client.Metric") | ||||
| 	proto.RegisterType((*MetricFamily)(nil), "io.prometheus.client.MetricFamily") | ||||
| 	proto.RegisterEnum("io.prometheus.client.MetricType", MetricType_name, MetricType_value) | ||||
| } | ||||
|  | ||||
| func init() { proto.RegisterFile("metrics.proto", fileDescriptor_metrics_c97c9a2b9560cb8f) } | ||||
|  | ||||
| var fileDescriptor_metrics_c97c9a2b9560cb8f = []byte{ | ||||
| 	// 591 bytes of a gzipped FileDescriptorProto | ||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x4f, 0x4f, 0xdb, 0x4e, | ||||
| 	0x14, 0xfc, 0x99, 0xd8, 0x09, 0x7e, 0x86, 0x5f, 0xad, 0x15, 0x07, 0xab, 0x2d, 0x25, 0xcd, 0x89, | ||||
| 	0xf6, 0x10, 0x54, 0x04, 0xaa, 0x44, 0xdb, 0x03, 0x50, 0x1a, 0x2a, 0xd5, 0x40, 0x37, 0xc9, 0x81, | ||||
| 	0x5e, 0xac, 0x8d, 0x59, 0x25, 0x56, 0xbd, 0xb6, 0x6b, 0xef, 0x22, 0xe5, 0xdc, 0x43, 0xbf, 0x47, | ||||
| 	0xbf, 0x68, 0xab, 0xfd, 0xe3, 0x18, 0x24, 0xc3, 0xa9, 0xb7, 0xb7, 0xf3, 0x66, 0xde, 0x8e, 0x77, | ||||
| 	0xc7, 0x0b, 0x9b, 0x8c, 0xf2, 0x32, 0x89, 0xab, 0x61, 0x51, 0xe6, 0x3c, 0x47, 0x5b, 0x49, 0x2e, | ||||
| 	0x2b, 0x46, 0xf9, 0x82, 0x8a, 0x6a, 0x18, 0xa7, 0x09, 0xcd, 0xf8, 0xe0, 0x10, 0xdc, 0x2f, 0x64, | ||||
| 	0x46, 0xd3, 0x2b, 0x92, 0x94, 0x08, 0x81, 0x9d, 0x11, 0x46, 0x03, 0xab, 0x6f, 0xed, 0xba, 0x58, | ||||
| 	0xd5, 0x68, 0x0b, 0x9c, 0x5b, 0x92, 0x0a, 0x1a, 0xac, 0x29, 0x50, 0x2f, 0x06, 0xdb, 0xe0, 0x8c, | ||||
| 	0x88, 0x98, 0xdf, 0x69, 0x4b, 0x8d, 0x55, 0xb7, 0x77, 0xa0, 0x77, 0x9a, 0x8b, 0x8c, 0xd3, 0xf2, | ||||
| 	0x01, 0xc2, 0x7b, 0x58, 0xff, 0x2a, 0x48, 0xc6, 0x93, 0x94, 0xa2, 0xa7, 0xb0, 0xfe, 0xc3, 0xd4, | ||||
| 	0x86, 0xb4, 0x5a, 0xdf, 0xdf, 0x7d, 0xa5, 0xfe, 0x65, 0x41, 0x6f, 0x2c, 0x18, 0x23, 0xe5, 0x12, | ||||
| 	0xbd, 0x84, 0x8d, 0x8a, 0xb0, 0x22, 0xa5, 0x51, 0x2c, 0x77, 0x54, 0x13, 0x6c, 0xec, 0x69, 0x4c, | ||||
| 	0x99, 0x40, 0xdb, 0x00, 0x86, 0x52, 0x09, 0x66, 0x26, 0xb9, 0x1a, 0x19, 0x0b, 0x86, 0x8e, 0xee, | ||||
| 	0xec, 0xdf, 0xe9, 0x77, 0x76, 0xbd, 0xfd, 0x17, 0xc3, 0xb6, 0xb3, 0x1a, 0xd6, 0x8e, 0x1b, 0x7f, | ||||
| 	0xf2, 0x43, 0xa7, 0x19, 0x5f, 0x16, 0xf4, 0xe6, 0x81, 0x0f, 0xfd, 0x69, 0x81, 0x7b, 0x9e, 0x54, | ||||
| 	0x3c, 0x9f, 0x97, 0x84, 0xfd, 0x03, 0xb3, 0x07, 0xd0, 0x9d, 0x89, 0xf8, 0x3b, 0xe5, 0xc6, 0xea, | ||||
| 	0xf3, 0x76, 0xab, 0x27, 0x8a, 0x83, 0x0d, 0x77, 0x30, 0x81, 0xae, 0x46, 0xd0, 0x2b, 0xf0, 0x63, | ||||
| 	0xc1, 0x44, 0x4a, 0x78, 0x72, 0x7b, 0xdf, 0xc5, 0x93, 0x06, 0xd7, 0x4e, 0x76, 0xc0, 0x13, 0x45, | ||||
| 	0x41, 0xcb, 0x68, 0x96, 0x8b, 0xec, 0xc6, 0x58, 0x01, 0x05, 0x9d, 0x48, 0x64, 0xf0, 0x67, 0x0d, | ||||
| 	0xba, 0xa1, 0xca, 0x18, 0x3a, 0x04, 0x27, 0x95, 0x31, 0x0a, 0x2c, 0xe5, 0x6a, 0xa7, 0xdd, 0xd5, | ||||
| 	0x2a, 0x69, 0x58, 0xb3, 0xd1, 0x1b, 0x70, 0xe6, 0x32, 0x46, 0x6a, 0xb8, 0xb7, 0xff, 0xac, 0x5d, | ||||
| 	0xa6, 0x92, 0x86, 0x35, 0x13, 0xbd, 0x85, 0x5e, 0xac, 0xa3, 0x15, 0x74, 0x94, 0x68, 0xbb, 0x5d, | ||||
| 	0x64, 0xf2, 0x87, 0x6b, 0xb6, 0x14, 0x56, 0x3a, 0x33, 0x81, 0xfd, 0x98, 0xd0, 0x04, 0x0b, 0xd7, | ||||
| 	0x6c, 0x29, 0x14, 0xfa, 0x8e, 0x03, 0xe7, 0x31, 0xa1, 0x09, 0x02, 0xae, 0xd9, 0xe8, 0x03, 0xb8, | ||||
| 	0x8b, 0xfa, 0xea, 0x83, 0x9e, 0x92, 0x3e, 0x70, 0x30, 0xab, 0x84, 0xe0, 0x46, 0x21, 0xc3, 0xc2, | ||||
| 	0x13, 0x46, 0x2b, 0x4e, 0x58, 0x11, 0xb1, 0x2a, 0xe8, 0xf6, 0xad, 0xdd, 0x0e, 0xf6, 0x56, 0x58, | ||||
| 	0x58, 0x0d, 0x7e, 0x5b, 0xb0, 0xa1, 0x6f, 0xe0, 0x13, 0x61, 0x49, 0xba, 0x6c, 0xfd, 0x83, 0x11, | ||||
| 	0xd8, 0x0b, 0x9a, 0x16, 0xe6, 0x07, 0x56, 0x35, 0x3a, 0x00, 0x5b, 0x7a, 0x54, 0x47, 0xf8, 0xff, | ||||
| 	0x7e, 0xbf, 0xdd, 0x95, 0x9e, 0x3c, 0x59, 0x16, 0x14, 0x2b, 0xb6, 0x0c, 0x9f, 0x7e, 0x53, 0x02, | ||||
| 	0xfb, 0xb1, 0xf0, 0x69, 0x1d, 0x36, 0xdc, 0xd7, 0x21, 0x40, 0x33, 0x09, 0x79, 0xd0, 0x3b, 0xbd, | ||||
| 	0x9c, 0x5e, 0x4c, 0xce, 0xb0, 0xff, 0x1f, 0x72, 0xc1, 0x19, 0x1d, 0x4f, 0x47, 0x67, 0xbe, 0x25, | ||||
| 	0xf1, 0xf1, 0x34, 0x0c, 0x8f, 0xf1, 0xb5, 0xbf, 0x26, 0x17, 0xd3, 0x8b, 0xc9, 0xf5, 0xd5, 0xd9, | ||||
| 	0x47, 0xbf, 0x83, 0x36, 0xc1, 0x3d, 0xff, 0x3c, 0x9e, 0x5c, 0x8e, 0xf0, 0x71, 0xe8, 0xdb, 0x27, | ||||
| 	0x18, 0x5a, 0x5f, 0xb2, 0x6f, 0x47, 0xf3, 0x84, 0x2f, 0xc4, 0x6c, 0x18, 0xe7, 0x6c, 0xaf, 0xe9, | ||||
| 	0xee, 0xe9, 0x6e, 0xc4, 0xf2, 0x1b, 0x9a, 0xee, 0xcd, 0xf3, 0x77, 0x49, 0x1e, 0x35, 0xdd, 0x48, | ||||
| 	0x77, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x45, 0x21, 0x7f, 0x64, 0x2b, 0x05, 0x00, 0x00, | ||||
| } | ||||
							
								
								
									
										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/). | ||||
							
								
								
									
										429
									
								
								vendor/github.com/prometheus/common/expfmt/decode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										429
									
								
								vendor/github.com/prometheus/common/expfmt/decode.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,429 @@ | ||||
| // 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 | ||||
| } | ||||
|  | ||||
| // DecodeOptions contains options used by the Decoder and in sample extraction. | ||||
| 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" | ||||
|  | ||||
| 	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 | ||||
| 	} | ||||
|  | ||||
| 	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} | ||||
| 	} | ||||
| 	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) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if !model.IsValidMetricName(model.LabelValue(v.GetName())) { | ||||
| 		return fmt.Errorf("invalid metric name %q", v.GetName()) | ||||
| 	} | ||||
| 	for _, m := range v.GetMetric() { | ||||
| 		if m == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		for _, l := range m.GetLabel() { | ||||
| 			if l == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			if !model.LabelValue(l.GetValue()).IsValid() { | ||||
| 				return fmt.Errorf("invalid label value %q", l.GetValue()) | ||||
| 			} | ||||
| 			if !model.LabelName(l.GetName()).IsValid() { | ||||
| 				return fmt.Errorf("invalid label name %q", l.GetName()) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // textDecoder implements the Decoder interface for the text protocol. | ||||
| 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 | ||||
| } | ||||
|  | ||||
| // SampleDecoder wraps a Decoder to extract samples from the metric families | ||||
| // decoded by the wrapped Decoder. | ||||
| type SampleDecoder struct { | ||||
| 	Dec  Decoder | ||||
| 	Opts *DecodeOptions | ||||
|  | ||||
| 	f dto.MetricFamily | ||||
| } | ||||
|  | ||||
| // Decode calls the Decode method of the wrapped Decoder and then extracts the | ||||
| // samples from the decoded MetricFamily into the provided model.Vector. | ||||
| func (sd *SampleDecoder) Decode(s *model.Vector) error { | ||||
| 	err := sd.Dec.Decode(&sd.f) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*s, err = extractSamples(&sd.f, sd.Opts) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // ExtractSamples builds a slice of samples from the provided metric | ||||
| // families. If an error occurrs during sample extraction, it continues to | ||||
| // extract from the remaining metric families. The returned error is the last | ||||
| // error that has occurred. | ||||
| func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) (model.Vector, error) { | ||||
| 	var ( | ||||
| 		all     model.Vector | ||||
| 		lastErr error | ||||
| 	) | ||||
| 	for _, f := range fams { | ||||
| 		some, err := extractSamples(f, o) | ||||
| 		if err != nil { | ||||
| 			lastErr = err | ||||
| 			continue | ||||
| 		} | ||||
| 		all = append(all, some...) | ||||
| 	} | ||||
| 	return all, lastErr | ||||
| } | ||||
|  | ||||
| func extractSamples(f *dto.MetricFamily, o *DecodeOptions) (model.Vector, error) { | ||||
| 	switch f.GetType() { | ||||
| 	case dto.MetricType_COUNTER: | ||||
| 		return extractCounter(o, f), nil | ||||
| 	case dto.MetricType_GAUGE: | ||||
| 		return extractGauge(o, f), nil | ||||
| 	case dto.MetricType_SUMMARY: | ||||
| 		return extractSummary(o, f), nil | ||||
| 	case dto.MetricType_UNTYPED: | ||||
| 		return extractUntyped(o, f), nil | ||||
| 	case dto.MetricType_HISTOGRAM: | ||||
| 		return extractHistogram(o, f), nil | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("expfmt.extractSamples: unknown metric family type %v", f.GetType()) | ||||
| } | ||||
|  | ||||
| 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 | ||||
| } | ||||
							
								
								
									
										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" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"github.com/matttproud/golang_protobuf_extensions/pbutil" | ||||
| 	"github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg" | ||||
|  | ||||
| 	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") | ||||
| } | ||||
							
								
								
									
										38
									
								
								vendor/github.com/prometheus/common/expfmt/expfmt.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/prometheus/common/expfmt/expfmt.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| // 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 contains tools for reading and writing Prometheus metrics. | ||||
| package expfmt | ||||
|  | ||||
| // Format specifies the HTTP content type of the different wire protocols. | ||||
| type Format string | ||||
|  | ||||
| // Constants to assemble the Content-Type values for the different wire protocols. | ||||
| 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 + `; charset=utf-8` | ||||
| 	FmtProtoDelim   Format = ProtoFmt + ` encoding=delimited` | ||||
| 	FmtProtoText    Format = ProtoFmt + ` encoding=text` | ||||
| 	FmtProtoCompact Format = ProtoFmt + ` encoding=compact-text` | ||||
| ) | ||||
|  | ||||
| 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/common/expfmt | ||||
| //     go-fuzz -bin expfmt-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 | ||||
| } | ||||
							
								
								
									
										468
									
								
								vendor/github.com/prometheus/common/expfmt/text_create.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										468
									
								
								vendor/github.com/prometheus/common/expfmt/text_create.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,468 @@ | ||||
| // 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 expfmt | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/prometheus/common/model" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| // enhancedWriter has all the enhanced write functions needed here. bytes.Buffer | ||||
| // implements it. | ||||
| type enhancedWriter interface { | ||||
| 	io.Writer | ||||
| 	WriteRune(r rune) (n int, err error) | ||||
| 	WriteString(s string) (n int, err error) | ||||
| 	WriteByte(c byte) error | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	initialBufSize    = 512 | ||||
| 	initialNumBufSize = 24 | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	bufPool = sync.Pool{ | ||||
| 		New: func() interface{} { | ||||
| 			return bytes.NewBuffer(make([]byte, 0, initialBufSize)) | ||||
| 		}, | ||||
| 	} | ||||
| 	numBufPool = sync.Pool{ | ||||
| 		New: func() interface{} { | ||||
| 			b := make([]byte, 0, initialNumBufSize) | ||||
| 			return &b | ||||
| 		}, | ||||
| 	} | ||||
| ) | ||||
|  | ||||
| // MetricFamilyToText converts a MetricFamily proto message into text format and | ||||
| // writes the resulting lines to 'out'. It returns the number of bytes written | ||||
| // and any error encountered. The output will have the same order as the input, | ||||
| // no further sorting is performed. Furthermore, this function assumes the input | ||||
| // is already sanitized and does not perform any sanity checks. If the input | ||||
| // contains duplicate metrics or invalid metric or label names, the conversion | ||||
| // will result in invalid text format output. | ||||
| // | ||||
| // This method fulfills the type 'prometheus.encoder'. | ||||
| func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err error) { | ||||
| 	// Fail-fast checks. | ||||
| 	if len(in.Metric) == 0 { | ||||
| 		return 0, fmt.Errorf("MetricFamily has no metrics: %s", in) | ||||
| 	} | ||||
| 	name := in.GetName() | ||||
| 	if name == "" { | ||||
| 		return 0, fmt.Errorf("MetricFamily has no name: %s", in) | ||||
| 	} | ||||
|  | ||||
| 	// Try the interface upgrade. If it doesn't work, we'll use a | ||||
| 	// bytes.Buffer from the sync.Pool and write out its content to out in a | ||||
| 	// single go in the end. | ||||
| 	w, ok := out.(enhancedWriter) | ||||
| 	if !ok { | ||||
| 		b := bufPool.Get().(*bytes.Buffer) | ||||
| 		b.Reset() | ||||
| 		w = b | ||||
| 		defer func() { | ||||
| 			bWritten, bErr := out.Write(b.Bytes()) | ||||
| 			written = bWritten | ||||
| 			if err == nil { | ||||
| 				err = bErr | ||||
| 			} | ||||
| 			bufPool.Put(b) | ||||
| 		}() | ||||
| 	} | ||||
|  | ||||
| 	var n int | ||||
|  | ||||
| 	// Comments, first HELP, then TYPE. | ||||
| 	if in.Help != nil { | ||||
| 		n, err = w.WriteString("# HELP ") | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		n, err = w.WriteString(name) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		err = w.WriteByte(' ') | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		n, err = writeEscapedString(w, *in.Help, false) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		err = w.WriteByte('\n') | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	n, err = w.WriteString("# TYPE ") | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	n, err = w.WriteString(name) | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	metricType := in.GetType() | ||||
| 	switch metricType { | ||||
| 	case dto.MetricType_COUNTER: | ||||
| 		n, err = w.WriteString(" counter\n") | ||||
| 	case dto.MetricType_GAUGE: | ||||
| 		n, err = w.WriteString(" gauge\n") | ||||
| 	case dto.MetricType_SUMMARY: | ||||
| 		n, err = w.WriteString(" summary\n") | ||||
| 	case dto.MetricType_UNTYPED: | ||||
| 		n, err = w.WriteString(" untyped\n") | ||||
| 	case dto.MetricType_HISTOGRAM: | ||||
| 		n, err = w.WriteString(" histogram\n") | ||||
| 	default: | ||||
| 		return written, fmt.Errorf("unknown metric type %s", metricType.String()) | ||||
| 	} | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Finally the samples, one line for each. | ||||
| 	for _, metric := range in.Metric { | ||||
| 		switch metricType { | ||||
| 		case dto.MetricType_COUNTER: | ||||
| 			if metric.Counter == nil { | ||||
| 				return written, fmt.Errorf( | ||||
| 					"expected counter in metric %s %s", name, metric, | ||||
| 				) | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				w, name, "", metric, "", 0, | ||||
| 				metric.Counter.GetValue(), | ||||
| 			) | ||||
| 		case dto.MetricType_GAUGE: | ||||
| 			if metric.Gauge == nil { | ||||
| 				return written, fmt.Errorf( | ||||
| 					"expected gauge in metric %s %s", name, metric, | ||||
| 				) | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				w, name, "", metric, "", 0, | ||||
| 				metric.Gauge.GetValue(), | ||||
| 			) | ||||
| 		case dto.MetricType_UNTYPED: | ||||
| 			if metric.Untyped == nil { | ||||
| 				return written, fmt.Errorf( | ||||
| 					"expected untyped in metric %s %s", name, metric, | ||||
| 				) | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				w, name, "", metric, "", 0, | ||||
| 				metric.Untyped.GetValue(), | ||||
| 			) | ||||
| 		case dto.MetricType_SUMMARY: | ||||
| 			if metric.Summary == nil { | ||||
| 				return written, fmt.Errorf( | ||||
| 					"expected summary in metric %s %s", name, metric, | ||||
| 				) | ||||
| 			} | ||||
| 			for _, q := range metric.Summary.Quantile { | ||||
| 				n, err = writeSample( | ||||
| 					w, name, "", metric, | ||||
| 					model.QuantileLabel, q.GetQuantile(), | ||||
| 					q.GetValue(), | ||||
| 				) | ||||
| 				written += n | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				w, name, "_sum", metric, "", 0, | ||||
| 				metric.Summary.GetSampleSum(), | ||||
| 			) | ||||
| 			written += n | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				w, name, "_count", metric, "", 0, | ||||
| 				float64(metric.Summary.GetSampleCount()), | ||||
| 			) | ||||
| 		case dto.MetricType_HISTOGRAM: | ||||
| 			if metric.Histogram == nil { | ||||
| 				return written, fmt.Errorf( | ||||
| 					"expected histogram in metric %s %s", name, metric, | ||||
| 				) | ||||
| 			} | ||||
| 			infSeen := false | ||||
| 			for _, b := range metric.Histogram.Bucket { | ||||
| 				n, err = writeSample( | ||||
| 					w, name, "_bucket", metric, | ||||
| 					model.BucketLabel, b.GetUpperBound(), | ||||
| 					float64(b.GetCumulativeCount()), | ||||
| 				) | ||||
| 				written += n | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if math.IsInf(b.GetUpperBound(), +1) { | ||||
| 					infSeen = true | ||||
| 				} | ||||
| 			} | ||||
| 			if !infSeen { | ||||
| 				n, err = writeSample( | ||||
| 					w, name, "_bucket", metric, | ||||
| 					model.BucketLabel, math.Inf(+1), | ||||
| 					float64(metric.Histogram.GetSampleCount()), | ||||
| 				) | ||||
| 				written += n | ||||
| 				if err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				w, name, "_sum", metric, "", 0, | ||||
| 				metric.Histogram.GetSampleSum(), | ||||
| 			) | ||||
| 			written += n | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 			n, err = writeSample( | ||||
| 				w, name, "_count", metric, "", 0, | ||||
| 				float64(metric.Histogram.GetSampleCount()), | ||||
| 			) | ||||
| 		default: | ||||
| 			return written, fmt.Errorf( | ||||
| 				"unexpected type in metric %s %s", name, metric, | ||||
| 			) | ||||
| 		} | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // writeSample writes a single sample in text format to w, given the metric | ||||
| // name, the metric proto message itself, optionally an additional label name | ||||
| // with a float64 value (use empty string as label name if not required), and | ||||
| // the value. The function returns the number of bytes written and any error | ||||
| // encountered. | ||||
| func writeSample( | ||||
| 	w enhancedWriter, | ||||
| 	name, suffix string, | ||||
| 	metric *dto.Metric, | ||||
| 	additionalLabelName string, additionalLabelValue float64, | ||||
| 	value float64, | ||||
| ) (int, error) { | ||||
| 	var written int | ||||
| 	n, err := w.WriteString(name) | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	if suffix != "" { | ||||
| 		n, err = w.WriteString(suffix) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 	} | ||||
| 	n, err = writeLabelPairs( | ||||
| 		w, metric.Label, additionalLabelName, additionalLabelValue, | ||||
| 	) | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	err = w.WriteByte(' ') | ||||
| 	written++ | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	n, err = writeFloat(w, value) | ||||
| 	written += n | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	if metric.TimestampMs != nil { | ||||
| 		err = w.WriteByte(' ') | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err = writeInt(w, *metric.TimestampMs) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 	} | ||||
| 	err = w.WriteByte('\n') | ||||
| 	written++ | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	return written, nil | ||||
| } | ||||
|  | ||||
| // writeLabelPairs converts a slice of LabelPair proto messages plus the | ||||
| // explicitly given additional label pair into text formatted as required by the | ||||
| // text format and writes it to 'w'. An empty slice in combination with an empty | ||||
| // string 'additionalLabelName' results in nothing being written. Otherwise, the | ||||
| // label pairs are written, escaped as required by the text format, and enclosed | ||||
| // in '{...}'. The function returns the number of bytes written and any error | ||||
| // encountered. | ||||
| func writeLabelPairs( | ||||
| 	w enhancedWriter, | ||||
| 	in []*dto.LabelPair, | ||||
| 	additionalLabelName string, additionalLabelValue float64, | ||||
| ) (int, error) { | ||||
| 	if len(in) == 0 && additionalLabelName == "" { | ||||
| 		return 0, nil | ||||
| 	} | ||||
| 	var ( | ||||
| 		written   int | ||||
| 		separator byte = '{' | ||||
| 	) | ||||
| 	for _, lp := range in { | ||||
| 		err := w.WriteByte(separator) | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err := w.WriteString(lp.GetName()) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err = w.WriteString(`="`) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err = writeEscapedString(w, lp.GetValue(), true) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		err = w.WriteByte('"') | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		separator = ',' | ||||
| 	} | ||||
| 	if additionalLabelName != "" { | ||||
| 		err := w.WriteByte(separator) | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err := w.WriteString(additionalLabelName) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err = w.WriteString(`="`) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		n, err = writeFloat(w, additionalLabelValue) | ||||
| 		written += n | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 		err = w.WriteByte('"') | ||||
| 		written++ | ||||
| 		if err != nil { | ||||
| 			return written, err | ||||
| 		} | ||||
| 	} | ||||
| 	err := w.WriteByte('}') | ||||
| 	written++ | ||||
| 	if err != nil { | ||||
| 		return written, err | ||||
| 	} | ||||
| 	return written, nil | ||||
| } | ||||
|  | ||||
| // writeEscapedString replaces '\' by '\\', new line character by '\n', and - if | ||||
| // includeDoubleQuote is true - '"' by '\"'. | ||||
| var ( | ||||
| 	escaper       = strings.NewReplacer("\\", `\\`, "\n", `\n`) | ||||
| 	quotedEscaper = strings.NewReplacer("\\", `\\`, "\n", `\n`, "\"", `\"`) | ||||
| ) | ||||
|  | ||||
| func writeEscapedString(w enhancedWriter, v string, includeDoubleQuote bool) (int, error) { | ||||
| 	if includeDoubleQuote { | ||||
| 		return quotedEscaper.WriteString(w, v) | ||||
| 	} else { | ||||
| 		return escaper.WriteString(w, v) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // writeFloat is equivalent to fmt.Fprint with a float64 argument but hardcodes | ||||
| // a few common cases for increased efficiency. For non-hardcoded cases, it uses | ||||
| // strconv.AppendFloat to avoid allocations, similar to writeInt. | ||||
| func writeFloat(w enhancedWriter, f float64) (int, error) { | ||||
| 	switch { | ||||
| 	case f == 1: | ||||
| 		return 1, w.WriteByte('1') | ||||
| 	case f == 0: | ||||
| 		return 1, w.WriteByte('0') | ||||
| 	case f == -1: | ||||
| 		return w.WriteString("-1") | ||||
| 	case math.IsNaN(f): | ||||
| 		return w.WriteString("NaN") | ||||
| 	case math.IsInf(f, +1): | ||||
| 		return w.WriteString("+Inf") | ||||
| 	case math.IsInf(f, -1): | ||||
| 		return w.WriteString("-Inf") | ||||
| 	default: | ||||
| 		bp := numBufPool.Get().(*[]byte) | ||||
| 		*bp = strconv.AppendFloat((*bp)[:0], f, 'g', -1, 64) | ||||
| 		written, err := w.Write(*bp) | ||||
| 		numBufPool.Put(bp) | ||||
| 		return written, err | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // writeInt is equivalent to fmt.Fprint with an int64 argument but uses | ||||
| // strconv.AppendInt with a byte slice taken from a sync.Pool to avoid | ||||
| // allocations. | ||||
| func writeInt(w enhancedWriter, i int64) (int, error) { | ||||
| 	bp := numBufPool.Get().(*[]byte) | ||||
| 	*bp = strconv.AppendInt((*bp)[:0], i, 10) | ||||
| 	written, err := w.Write(*bp) | ||||
| 	numBufPool.Put(bp) | ||||
| 	return written, err | ||||
| } | ||||
							
								
								
									
										757
									
								
								vendor/github.com/prometheus/common/expfmt/text_parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										757
									
								
								vendor/github.com/prometheus/common/expfmt/text_parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,757 @@ | ||||
| // 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 expfmt | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"github.com/prometheus/common/model" | ||||
| ) | ||||
|  | ||||
| // A stateFn is a function that represents a state in a state machine. By | ||||
| // executing it, the state is progressed to the next state. The stateFn returns | ||||
| // another stateFn, which represents the new state. The end state is represented | ||||
| // by nil. | ||||
| type stateFn func() stateFn | ||||
|  | ||||
| // ParseError signals errors while parsing the simple and flat text-based | ||||
| // exchange format. | ||||
| type ParseError struct { | ||||
| 	Line int | ||||
| 	Msg  string | ||||
| } | ||||
|  | ||||
| // Error implements the error interface. | ||||
| func (e ParseError) Error() string { | ||||
| 	return fmt.Sprintf("text format parsing error in line %d: %s", e.Line, e.Msg) | ||||
| } | ||||
|  | ||||
| // TextParser is used to parse the simple and flat text-based exchange format. Its | ||||
| // zero value is ready to use. | ||||
| type TextParser struct { | ||||
| 	metricFamiliesByName map[string]*dto.MetricFamily | ||||
| 	buf                  *bufio.Reader // Where the parsed input is read through. | ||||
| 	err                  error         // Most recent error. | ||||
| 	lineCount            int           // Tracks the line count for error messages. | ||||
| 	currentByte          byte          // The most recent byte read. | ||||
| 	currentToken         bytes.Buffer  // Re-used each time a token has to be gathered from multiple bytes. | ||||
| 	currentMF            *dto.MetricFamily | ||||
| 	currentMetric        *dto.Metric | ||||
| 	currentLabelPair     *dto.LabelPair | ||||
|  | ||||
| 	// The remaining member variables are only used for summaries/histograms. | ||||
| 	currentLabels map[string]string // All labels including '__name__' but excluding 'quantile'/'le' | ||||
| 	// Summary specific. | ||||
| 	summaries       map[uint64]*dto.Metric // Key is created with LabelsToSignature. | ||||
| 	currentQuantile float64 | ||||
| 	// Histogram specific. | ||||
| 	histograms    map[uint64]*dto.Metric // Key is created with LabelsToSignature. | ||||
| 	currentBucket float64 | ||||
| 	// These tell us if the currently processed line ends on '_count' or | ||||
| 	// '_sum' respectively and belong to a summary/histogram, representing the sample | ||||
| 	// count and sum of that summary/histogram. | ||||
| 	currentIsSummaryCount, currentIsSummarySum     bool | ||||
| 	currentIsHistogramCount, currentIsHistogramSum bool | ||||
| } | ||||
|  | ||||
| // TextToMetricFamilies reads 'in' as the simple and flat text-based exchange | ||||
| // format and creates MetricFamily proto messages. It returns the MetricFamily | ||||
| // proto messages in a map where the metric names are the keys, along with any | ||||
| // error encountered. | ||||
| // | ||||
| // If the input contains duplicate metrics (i.e. lines with the same metric name | ||||
| // and exactly the same label set), the resulting MetricFamily will contain | ||||
| // duplicate Metric proto messages. Similar is true for duplicate label | ||||
| // names. Checks for duplicates have to be performed separately, if required. | ||||
| // Also note that neither the metrics within each MetricFamily are sorted nor | ||||
| // the label pairs within each Metric. Sorting is not required for the most | ||||
| // frequent use of this method, which is sample ingestion in the Prometheus | ||||
| // server. However, for presentation purposes, you might want to sort the | ||||
| // metrics, and in some cases, you must sort the labels, e.g. for consumption by | ||||
| // the metric family injection hook of the Prometheus registry. | ||||
| // | ||||
| // Summaries and histograms are rather special beasts. You would probably not | ||||
| // use them in the simple text format anyway. This method can deal with | ||||
| // summaries and histograms if they are presented in exactly the way the | ||||
| // text.Create function creates them. | ||||
| // | ||||
| // This method must not be called concurrently. If you want to parse different | ||||
| // input concurrently, instantiate a separate Parser for each goroutine. | ||||
| func (p *TextParser) TextToMetricFamilies(in io.Reader) (map[string]*dto.MetricFamily, error) { | ||||
| 	p.reset(in) | ||||
| 	for nextState := p.startOfLine; nextState != nil; nextState = nextState() { | ||||
| 		// Magic happens here... | ||||
| 	} | ||||
| 	// Get rid of empty metric families. | ||||
| 	for k, mf := range p.metricFamiliesByName { | ||||
| 		if len(mf.GetMetric()) == 0 { | ||||
| 			delete(p.metricFamiliesByName, k) | ||||
| 		} | ||||
| 	} | ||||
| 	// If p.err is io.EOF now, we have run into a premature end of the input | ||||
| 	// stream. Turn this error into something nicer and more | ||||
| 	// meaningful. (io.EOF is often used as a signal for the legitimate end | ||||
| 	// of an input stream.) | ||||
| 	if p.err == io.EOF { | ||||
| 		p.parseError("unexpected end of input stream") | ||||
| 	} | ||||
| 	return p.metricFamiliesByName, p.err | ||||
| } | ||||
|  | ||||
| func (p *TextParser) reset(in io.Reader) { | ||||
| 	p.metricFamiliesByName = map[string]*dto.MetricFamily{} | ||||
| 	if p.buf == nil { | ||||
| 		p.buf = bufio.NewReader(in) | ||||
| 	} else { | ||||
| 		p.buf.Reset(in) | ||||
| 	} | ||||
| 	p.err = nil | ||||
| 	p.lineCount = 0 | ||||
| 	if p.summaries == nil || len(p.summaries) > 0 { | ||||
| 		p.summaries = map[uint64]*dto.Metric{} | ||||
| 	} | ||||
| 	if p.histograms == nil || len(p.histograms) > 0 { | ||||
| 		p.histograms = map[uint64]*dto.Metric{} | ||||
| 	} | ||||
| 	p.currentQuantile = math.NaN() | ||||
| 	p.currentBucket = math.NaN() | ||||
| } | ||||
|  | ||||
| // startOfLine represents the state where the next byte read from p.buf is the | ||||
| // start of a line (or whitespace leading up to it). | ||||
| func (p *TextParser) startOfLine() stateFn { | ||||
| 	p.lineCount++ | ||||
| 	if p.skipBlankTab(); p.err != nil { | ||||
| 		// End of input reached. This is the only case where | ||||
| 		// that is not an error but a signal that we are done. | ||||
| 		p.err = nil | ||||
| 		return nil | ||||
| 	} | ||||
| 	switch p.currentByte { | ||||
| 	case '#': | ||||
| 		return p.startComment | ||||
| 	case '\n': | ||||
| 		return p.startOfLine // Empty line, start the next one. | ||||
| 	} | ||||
| 	return p.readingMetricName | ||||
| } | ||||
|  | ||||
| // startComment represents the state where the next byte read from p.buf is the | ||||
| // start of a comment (or whitespace leading up to it). | ||||
| func (p *TextParser) startComment() stateFn { | ||||
| 	if p.skipBlankTab(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	if p.currentByte == '\n' { | ||||
| 		return p.startOfLine | ||||
| 	} | ||||
| 	if p.readTokenUntilWhitespace(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	// If we have hit the end of line already, there is nothing left | ||||
| 	// to do. This is not considered a syntax error. | ||||
| 	if p.currentByte == '\n' { | ||||
| 		return p.startOfLine | ||||
| 	} | ||||
| 	keyword := p.currentToken.String() | ||||
| 	if keyword != "HELP" && keyword != "TYPE" { | ||||
| 		// Generic comment, ignore by fast forwarding to end of line. | ||||
| 		for p.currentByte != '\n' { | ||||
| 			if p.currentByte, p.err = p.buf.ReadByte(); p.err != nil { | ||||
| 				return nil // Unexpected end of input. | ||||
| 			} | ||||
| 		} | ||||
| 		return p.startOfLine | ||||
| 	} | ||||
| 	// There is something. Next has to be a metric name. | ||||
| 	if p.skipBlankTab(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	if p.readTokenAsMetricName(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	if p.currentByte == '\n' { | ||||
| 		// At the end of the line already. | ||||
| 		// Again, this is not considered a syntax error. | ||||
| 		return p.startOfLine | ||||
| 	} | ||||
| 	if !isBlankOrTab(p.currentByte) { | ||||
| 		p.parseError("invalid metric name in comment") | ||||
| 		return nil | ||||
| 	} | ||||
| 	p.setOrCreateCurrentMF() | ||||
| 	if p.skipBlankTab(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	if p.currentByte == '\n' { | ||||
| 		// At the end of the line already. | ||||
| 		// Again, this is not considered a syntax error. | ||||
| 		return p.startOfLine | ||||
| 	} | ||||
| 	switch keyword { | ||||
| 	case "HELP": | ||||
| 		return p.readingHelp | ||||
| 	case "TYPE": | ||||
| 		return p.readingType | ||||
| 	} | ||||
| 	panic(fmt.Sprintf("code error: unexpected keyword %q", keyword)) | ||||
| } | ||||
|  | ||||
| // readingMetricName represents the state where the last byte read (now in | ||||
| // p.currentByte) is the first byte of a metric name. | ||||
| func (p *TextParser) readingMetricName() stateFn { | ||||
| 	if p.readTokenAsMetricName(); p.err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if p.currentToken.Len() == 0 { | ||||
| 		p.parseError("invalid metric name") | ||||
| 		return nil | ||||
| 	} | ||||
| 	p.setOrCreateCurrentMF() | ||||
| 	// Now is the time to fix the type if it hasn't happened yet. | ||||
| 	if p.currentMF.Type == nil { | ||||
| 		p.currentMF.Type = dto.MetricType_UNTYPED.Enum() | ||||
| 	} | ||||
| 	p.currentMetric = &dto.Metric{} | ||||
| 	// Do not append the newly created currentMetric to | ||||
| 	// currentMF.Metric right now. First wait if this is a summary, | ||||
| 	// and the metric exists already, which we can only know after | ||||
| 	// having read all the labels. | ||||
| 	if p.skipBlankTabIfCurrentBlankTab(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	return p.readingLabels | ||||
| } | ||||
|  | ||||
| // readingLabels represents the state where the last byte read (now in | ||||
| // p.currentByte) is either the first byte of the label set (i.e. a '{'), or the | ||||
| // first byte of the value (otherwise). | ||||
| func (p *TextParser) readingLabels() stateFn { | ||||
| 	// Summaries/histograms are special. We have to reset the | ||||
| 	// currentLabels map, currentQuantile and currentBucket before starting to | ||||
| 	// read labels. | ||||
| 	if p.currentMF.GetType() == dto.MetricType_SUMMARY || p.currentMF.GetType() == dto.MetricType_HISTOGRAM { | ||||
| 		p.currentLabels = map[string]string{} | ||||
| 		p.currentLabels[string(model.MetricNameLabel)] = p.currentMF.GetName() | ||||
| 		p.currentQuantile = math.NaN() | ||||
| 		p.currentBucket = math.NaN() | ||||
| 	} | ||||
| 	if p.currentByte != '{' { | ||||
| 		return p.readingValue | ||||
| 	} | ||||
| 	return p.startLabelName | ||||
| } | ||||
|  | ||||
| // startLabelName represents the state where the next byte read from p.buf is | ||||
| // the start of a label name (or whitespace leading up to it). | ||||
| func (p *TextParser) startLabelName() stateFn { | ||||
| 	if p.skipBlankTab(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	if p.currentByte == '}' { | ||||
| 		if p.skipBlankTab(); p.err != nil { | ||||
| 			return nil // Unexpected end of input. | ||||
| 		} | ||||
| 		return p.readingValue | ||||
| 	} | ||||
| 	if p.readTokenAsLabelName(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	if p.currentToken.Len() == 0 { | ||||
| 		p.parseError(fmt.Sprintf("invalid label name for metric %q", p.currentMF.GetName())) | ||||
| 		return nil | ||||
| 	} | ||||
| 	p.currentLabelPair = &dto.LabelPair{Name: proto.String(p.currentToken.String())} | ||||
| 	if p.currentLabelPair.GetName() == string(model.MetricNameLabel) { | ||||
| 		p.parseError(fmt.Sprintf("label name %q is reserved", model.MetricNameLabel)) | ||||
| 		return nil | ||||
| 	} | ||||
| 	// Special summary/histogram treatment. Don't add 'quantile' and 'le' | ||||
| 	// labels to 'real' labels. | ||||
| 	if !(p.currentMF.GetType() == dto.MetricType_SUMMARY && p.currentLabelPair.GetName() == model.QuantileLabel) && | ||||
| 		!(p.currentMF.GetType() == dto.MetricType_HISTOGRAM && p.currentLabelPair.GetName() == model.BucketLabel) { | ||||
| 		p.currentMetric.Label = append(p.currentMetric.Label, p.currentLabelPair) | ||||
| 	} | ||||
| 	if p.skipBlankTabIfCurrentBlankTab(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	if p.currentByte != '=' { | ||||
| 		p.parseError(fmt.Sprintf("expected '=' after label name, found %q", p.currentByte)) | ||||
| 		return nil | ||||
| 	} | ||||
| 	return p.startLabelValue | ||||
| } | ||||
|  | ||||
| // startLabelValue represents the state where the next byte read from p.buf is | ||||
| // the start of a (quoted) label value (or whitespace leading up to it). | ||||
| func (p *TextParser) startLabelValue() stateFn { | ||||
| 	if p.skipBlankTab(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	if p.currentByte != '"' { | ||||
| 		p.parseError(fmt.Sprintf("expected '\"' at start of label value, found %q", p.currentByte)) | ||||
| 		return nil | ||||
| 	} | ||||
| 	if p.readTokenAsLabelValue(); p.err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if !model.LabelValue(p.currentToken.String()).IsValid() { | ||||
| 		p.parseError(fmt.Sprintf("invalid label value %q", p.currentToken.String())) | ||||
| 		return nil | ||||
| 	} | ||||
| 	p.currentLabelPair.Value = proto.String(p.currentToken.String()) | ||||
| 	// Special treatment of summaries: | ||||
| 	// - Quantile labels are special, will result in dto.Quantile later. | ||||
| 	// - Other labels have to be added to currentLabels for signature calculation. | ||||
| 	if p.currentMF.GetType() == dto.MetricType_SUMMARY { | ||||
| 		if p.currentLabelPair.GetName() == model.QuantileLabel { | ||||
| 			if p.currentQuantile, p.err = strconv.ParseFloat(p.currentLabelPair.GetValue(), 64); p.err != nil { | ||||
| 				// Create a more helpful error message. | ||||
| 				p.parseError(fmt.Sprintf("expected float as value for 'quantile' label, got %q", p.currentLabelPair.GetValue())) | ||||
| 				return nil | ||||
| 			} | ||||
| 		} else { | ||||
| 			p.currentLabels[p.currentLabelPair.GetName()] = p.currentLabelPair.GetValue() | ||||
| 		} | ||||
| 	} | ||||
| 	// Similar special treatment of histograms. | ||||
| 	if p.currentMF.GetType() == dto.MetricType_HISTOGRAM { | ||||
| 		if p.currentLabelPair.GetName() == model.BucketLabel { | ||||
| 			if p.currentBucket, p.err = strconv.ParseFloat(p.currentLabelPair.GetValue(), 64); p.err != nil { | ||||
| 				// Create a more helpful error message. | ||||
| 				p.parseError(fmt.Sprintf("expected float as value for 'le' label, got %q", p.currentLabelPair.GetValue())) | ||||
| 				return nil | ||||
| 			} | ||||
| 		} else { | ||||
| 			p.currentLabels[p.currentLabelPair.GetName()] = p.currentLabelPair.GetValue() | ||||
| 		} | ||||
| 	} | ||||
| 	if p.skipBlankTab(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	switch p.currentByte { | ||||
| 	case ',': | ||||
| 		return p.startLabelName | ||||
|  | ||||
| 	case '}': | ||||
| 		if p.skipBlankTab(); p.err != nil { | ||||
| 			return nil // Unexpected end of input. | ||||
| 		} | ||||
| 		return p.readingValue | ||||
| 	default: | ||||
| 		p.parseError(fmt.Sprintf("unexpected end of label value %q", p.currentLabelPair.GetValue())) | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readingValue represents the state where the last byte read (now in | ||||
| // p.currentByte) is the first byte of the sample value (i.e. a float). | ||||
| func (p *TextParser) readingValue() stateFn { | ||||
| 	// When we are here, we have read all the labels, so for the | ||||
| 	// special case of a summary/histogram, we can finally find out | ||||
| 	// if the metric already exists. | ||||
| 	if p.currentMF.GetType() == dto.MetricType_SUMMARY { | ||||
| 		signature := model.LabelsToSignature(p.currentLabels) | ||||
| 		if summary := p.summaries[signature]; summary != nil { | ||||
| 			p.currentMetric = summary | ||||
| 		} else { | ||||
| 			p.summaries[signature] = p.currentMetric | ||||
| 			p.currentMF.Metric = append(p.currentMF.Metric, p.currentMetric) | ||||
| 		} | ||||
| 	} else if p.currentMF.GetType() == dto.MetricType_HISTOGRAM { | ||||
| 		signature := model.LabelsToSignature(p.currentLabels) | ||||
| 		if histogram := p.histograms[signature]; histogram != nil { | ||||
| 			p.currentMetric = histogram | ||||
| 		} else { | ||||
| 			p.histograms[signature] = p.currentMetric | ||||
| 			p.currentMF.Metric = append(p.currentMF.Metric, p.currentMetric) | ||||
| 		} | ||||
| 	} else { | ||||
| 		p.currentMF.Metric = append(p.currentMF.Metric, p.currentMetric) | ||||
| 	} | ||||
| 	if p.readTokenUntilWhitespace(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	value, err := strconv.ParseFloat(p.currentToken.String(), 64) | ||||
| 	if err != nil { | ||||
| 		// Create a more helpful error message. | ||||
| 		p.parseError(fmt.Sprintf("expected float as value, got %q", p.currentToken.String())) | ||||
| 		return nil | ||||
| 	} | ||||
| 	switch p.currentMF.GetType() { | ||||
| 	case dto.MetricType_COUNTER: | ||||
| 		p.currentMetric.Counter = &dto.Counter{Value: proto.Float64(value)} | ||||
| 	case dto.MetricType_GAUGE: | ||||
| 		p.currentMetric.Gauge = &dto.Gauge{Value: proto.Float64(value)} | ||||
| 	case dto.MetricType_UNTYPED: | ||||
| 		p.currentMetric.Untyped = &dto.Untyped{Value: proto.Float64(value)} | ||||
| 	case dto.MetricType_SUMMARY: | ||||
| 		// *sigh* | ||||
| 		if p.currentMetric.Summary == nil { | ||||
| 			p.currentMetric.Summary = &dto.Summary{} | ||||
| 		} | ||||
| 		switch { | ||||
| 		case p.currentIsSummaryCount: | ||||
| 			p.currentMetric.Summary.SampleCount = proto.Uint64(uint64(value)) | ||||
| 		case p.currentIsSummarySum: | ||||
| 			p.currentMetric.Summary.SampleSum = proto.Float64(value) | ||||
| 		case !math.IsNaN(p.currentQuantile): | ||||
| 			p.currentMetric.Summary.Quantile = append( | ||||
| 				p.currentMetric.Summary.Quantile, | ||||
| 				&dto.Quantile{ | ||||
| 					Quantile: proto.Float64(p.currentQuantile), | ||||
| 					Value:    proto.Float64(value), | ||||
| 				}, | ||||
| 			) | ||||
| 		} | ||||
| 	case dto.MetricType_HISTOGRAM: | ||||
| 		// *sigh* | ||||
| 		if p.currentMetric.Histogram == nil { | ||||
| 			p.currentMetric.Histogram = &dto.Histogram{} | ||||
| 		} | ||||
| 		switch { | ||||
| 		case p.currentIsHistogramCount: | ||||
| 			p.currentMetric.Histogram.SampleCount = proto.Uint64(uint64(value)) | ||||
| 		case p.currentIsHistogramSum: | ||||
| 			p.currentMetric.Histogram.SampleSum = proto.Float64(value) | ||||
| 		case !math.IsNaN(p.currentBucket): | ||||
| 			p.currentMetric.Histogram.Bucket = append( | ||||
| 				p.currentMetric.Histogram.Bucket, | ||||
| 				&dto.Bucket{ | ||||
| 					UpperBound:      proto.Float64(p.currentBucket), | ||||
| 					CumulativeCount: proto.Uint64(uint64(value)), | ||||
| 				}, | ||||
| 			) | ||||
| 		} | ||||
| 	default: | ||||
| 		p.err = fmt.Errorf("unexpected type for metric name %q", p.currentMF.GetName()) | ||||
| 	} | ||||
| 	if p.currentByte == '\n' { | ||||
| 		return p.startOfLine | ||||
| 	} | ||||
| 	return p.startTimestamp | ||||
| } | ||||
|  | ||||
| // startTimestamp represents the state where the next byte read from p.buf is | ||||
| // the start of the timestamp (or whitespace leading up to it). | ||||
| func (p *TextParser) startTimestamp() stateFn { | ||||
| 	if p.skipBlankTab(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	if p.readTokenUntilWhitespace(); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	timestamp, err := strconv.ParseInt(p.currentToken.String(), 10, 64) | ||||
| 	if err != nil { | ||||
| 		// Create a more helpful error message. | ||||
| 		p.parseError(fmt.Sprintf("expected integer as timestamp, got %q", p.currentToken.String())) | ||||
| 		return nil | ||||
| 	} | ||||
| 	p.currentMetric.TimestampMs = proto.Int64(timestamp) | ||||
| 	if p.readTokenUntilNewline(false); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	if p.currentToken.Len() > 0 { | ||||
| 		p.parseError(fmt.Sprintf("spurious string after timestamp: %q", p.currentToken.String())) | ||||
| 		return nil | ||||
| 	} | ||||
| 	return p.startOfLine | ||||
| } | ||||
|  | ||||
| // readingHelp represents the state where the last byte read (now in | ||||
| // p.currentByte) is the first byte of the docstring after 'HELP'. | ||||
| func (p *TextParser) readingHelp() stateFn { | ||||
| 	if p.currentMF.Help != nil { | ||||
| 		p.parseError(fmt.Sprintf("second HELP line for metric name %q", p.currentMF.GetName())) | ||||
| 		return nil | ||||
| 	} | ||||
| 	// Rest of line is the docstring. | ||||
| 	if p.readTokenUntilNewline(true); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	p.currentMF.Help = proto.String(p.currentToken.String()) | ||||
| 	return p.startOfLine | ||||
| } | ||||
|  | ||||
| // readingType represents the state where the last byte read (now in | ||||
| // p.currentByte) is the first byte of the type hint after 'HELP'. | ||||
| func (p *TextParser) readingType() stateFn { | ||||
| 	if p.currentMF.Type != nil { | ||||
| 		p.parseError(fmt.Sprintf("second TYPE line for metric name %q, or TYPE reported after samples", p.currentMF.GetName())) | ||||
| 		return nil | ||||
| 	} | ||||
| 	// Rest of line is the type. | ||||
| 	if p.readTokenUntilNewline(false); p.err != nil { | ||||
| 		return nil // Unexpected end of input. | ||||
| 	} | ||||
| 	metricType, ok := dto.MetricType_value[strings.ToUpper(p.currentToken.String())] | ||||
| 	if !ok { | ||||
| 		p.parseError(fmt.Sprintf("unknown metric type %q", p.currentToken.String())) | ||||
| 		return nil | ||||
| 	} | ||||
| 	p.currentMF.Type = dto.MetricType(metricType).Enum() | ||||
| 	return p.startOfLine | ||||
| } | ||||
|  | ||||
| // parseError sets p.err to a ParseError at the current line with the given | ||||
| // message. | ||||
| func (p *TextParser) parseError(msg string) { | ||||
| 	p.err = ParseError{ | ||||
| 		Line: p.lineCount, | ||||
| 		Msg:  msg, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // skipBlankTab reads (and discards) bytes from p.buf until it encounters a byte | ||||
| // that is neither ' ' nor '\t'. That byte is left in p.currentByte. | ||||
| func (p *TextParser) skipBlankTab() { | ||||
| 	for { | ||||
| 		if p.currentByte, p.err = p.buf.ReadByte(); p.err != nil || !isBlankOrTab(p.currentByte) { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // skipBlankTabIfCurrentBlankTab works exactly as skipBlankTab but doesn't do | ||||
| // anything if p.currentByte is neither ' ' nor '\t'. | ||||
| func (p *TextParser) skipBlankTabIfCurrentBlankTab() { | ||||
| 	if isBlankOrTab(p.currentByte) { | ||||
| 		p.skipBlankTab() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readTokenUntilWhitespace copies bytes from p.buf into p.currentToken.  The | ||||
| // first byte considered is the byte already read (now in p.currentByte).  The | ||||
| // first whitespace byte encountered is still copied into p.currentByte, but not | ||||
| // into p.currentToken. | ||||
| func (p *TextParser) readTokenUntilWhitespace() { | ||||
| 	p.currentToken.Reset() | ||||
| 	for p.err == nil && !isBlankOrTab(p.currentByte) && p.currentByte != '\n' { | ||||
| 		p.currentToken.WriteByte(p.currentByte) | ||||
| 		p.currentByte, p.err = p.buf.ReadByte() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readTokenUntilNewline copies bytes from p.buf into p.currentToken.  The first | ||||
| // byte considered is the byte already read (now in p.currentByte).  The first | ||||
| // newline byte encountered is still copied into p.currentByte, but not into | ||||
| // p.currentToken. If recognizeEscapeSequence is true, two escape sequences are | ||||
| // recognized: '\\' translates into '\', and '\n' into a line-feed character. | ||||
| // All other escape sequences are invalid and cause an error. | ||||
| func (p *TextParser) readTokenUntilNewline(recognizeEscapeSequence bool) { | ||||
| 	p.currentToken.Reset() | ||||
| 	escaped := false | ||||
| 	for p.err == nil { | ||||
| 		if recognizeEscapeSequence && escaped { | ||||
| 			switch p.currentByte { | ||||
| 			case '\\': | ||||
| 				p.currentToken.WriteByte(p.currentByte) | ||||
| 			case 'n': | ||||
| 				p.currentToken.WriteByte('\n') | ||||
| 			default: | ||||
| 				p.parseError(fmt.Sprintf("invalid escape sequence '\\%c'", p.currentByte)) | ||||
| 				return | ||||
| 			} | ||||
| 			escaped = false | ||||
| 		} else { | ||||
| 			switch p.currentByte { | ||||
| 			case '\n': | ||||
| 				return | ||||
| 			case '\\': | ||||
| 				escaped = true | ||||
| 			default: | ||||
| 				p.currentToken.WriteByte(p.currentByte) | ||||
| 			} | ||||
| 		} | ||||
| 		p.currentByte, p.err = p.buf.ReadByte() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readTokenAsMetricName copies a metric name from p.buf into p.currentToken. | ||||
| // The first byte considered is the byte already read (now in p.currentByte). | ||||
| // The first byte not part of a metric name is still copied into p.currentByte, | ||||
| // but not into p.currentToken. | ||||
| func (p *TextParser) readTokenAsMetricName() { | ||||
| 	p.currentToken.Reset() | ||||
| 	if !isValidMetricNameStart(p.currentByte) { | ||||
| 		return | ||||
| 	} | ||||
| 	for { | ||||
| 		p.currentToken.WriteByte(p.currentByte) | ||||
| 		p.currentByte, p.err = p.buf.ReadByte() | ||||
| 		if p.err != nil || !isValidMetricNameContinuation(p.currentByte) { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readTokenAsLabelName copies a label name from p.buf into p.currentToken. | ||||
| // The first byte considered is the byte already read (now in p.currentByte). | ||||
| // The first byte not part of a label name is still copied into p.currentByte, | ||||
| // but not into p.currentToken. | ||||
| func (p *TextParser) readTokenAsLabelName() { | ||||
| 	p.currentToken.Reset() | ||||
| 	if !isValidLabelNameStart(p.currentByte) { | ||||
| 		return | ||||
| 	} | ||||
| 	for { | ||||
| 		p.currentToken.WriteByte(p.currentByte) | ||||
| 		p.currentByte, p.err = p.buf.ReadByte() | ||||
| 		if p.err != nil || !isValidLabelNameContinuation(p.currentByte) { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // readTokenAsLabelValue copies a label value from p.buf into p.currentToken. | ||||
| // In contrast to the other 'readTokenAs...' functions, which start with the | ||||
| // last read byte in p.currentByte, this method ignores p.currentByte and starts | ||||
| // with reading a new byte from p.buf. The first byte not part of a label value | ||||
| // is still copied into p.currentByte, but not into p.currentToken. | ||||
| func (p *TextParser) readTokenAsLabelValue() { | ||||
| 	p.currentToken.Reset() | ||||
| 	escaped := false | ||||
| 	for { | ||||
| 		if p.currentByte, p.err = p.buf.ReadByte(); p.err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if escaped { | ||||
| 			switch p.currentByte { | ||||
| 			case '"', '\\': | ||||
| 				p.currentToken.WriteByte(p.currentByte) | ||||
| 			case 'n': | ||||
| 				p.currentToken.WriteByte('\n') | ||||
| 			default: | ||||
| 				p.parseError(fmt.Sprintf("invalid escape sequence '\\%c'", p.currentByte)) | ||||
| 				return | ||||
| 			} | ||||
| 			escaped = false | ||||
| 			continue | ||||
| 		} | ||||
| 		switch p.currentByte { | ||||
| 		case '"': | ||||
| 			return | ||||
| 		case '\n': | ||||
| 			p.parseError(fmt.Sprintf("label value %q contains unescaped new-line", p.currentToken.String())) | ||||
| 			return | ||||
| 		case '\\': | ||||
| 			escaped = true | ||||
| 		default: | ||||
| 			p.currentToken.WriteByte(p.currentByte) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (p *TextParser) setOrCreateCurrentMF() { | ||||
| 	p.currentIsSummaryCount = false | ||||
| 	p.currentIsSummarySum = false | ||||
| 	p.currentIsHistogramCount = false | ||||
| 	p.currentIsHistogramSum = false | ||||
| 	name := p.currentToken.String() | ||||
| 	if p.currentMF = p.metricFamiliesByName[name]; p.currentMF != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	// Try out if this is a _sum or _count for a summary/histogram. | ||||
| 	summaryName := summaryMetricName(name) | ||||
| 	if p.currentMF = p.metricFamiliesByName[summaryName]; p.currentMF != nil { | ||||
| 		if p.currentMF.GetType() == dto.MetricType_SUMMARY { | ||||
| 			if isCount(name) { | ||||
| 				p.currentIsSummaryCount = true | ||||
| 			} | ||||
| 			if isSum(name) { | ||||
| 				p.currentIsSummarySum = true | ||||
| 			} | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	histogramName := histogramMetricName(name) | ||||
| 	if p.currentMF = p.metricFamiliesByName[histogramName]; p.currentMF != nil { | ||||
| 		if p.currentMF.GetType() == dto.MetricType_HISTOGRAM { | ||||
| 			if isCount(name) { | ||||
| 				p.currentIsHistogramCount = true | ||||
| 			} | ||||
| 			if isSum(name) { | ||||
| 				p.currentIsHistogramSum = true | ||||
| 			} | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	p.currentMF = &dto.MetricFamily{Name: proto.String(name)} | ||||
| 	p.metricFamiliesByName[name] = p.currentMF | ||||
| } | ||||
|  | ||||
| func isValidLabelNameStart(b byte) bool { | ||||
| 	return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' | ||||
| } | ||||
|  | ||||
| func isValidLabelNameContinuation(b byte) bool { | ||||
| 	return isValidLabelNameStart(b) || (b >= '0' && b <= '9') | ||||
| } | ||||
|  | ||||
| func isValidMetricNameStart(b byte) bool { | ||||
| 	return isValidLabelNameStart(b) || b == ':' | ||||
| } | ||||
|  | ||||
| func isValidMetricNameContinuation(b byte) bool { | ||||
| 	return isValidLabelNameContinuation(b) || b == ':' | ||||
| } | ||||
|  | ||||
| func isBlankOrTab(b byte) bool { | ||||
| 	return b == ' ' || b == '\t' | ||||
| } | ||||
|  | ||||
| func isCount(name string) bool { | ||||
| 	return len(name) > 6 && name[len(name)-6:] == "_count" | ||||
| } | ||||
|  | ||||
| func isSum(name string) bool { | ||||
| 	return len(name) > 4 && name[len(name)-4:] == "_sum" | ||||
| } | ||||
|  | ||||
| func isBucket(name string) bool { | ||||
| 	return len(name) > 7 && name[len(name)-7:] == "_bucket" | ||||
| } | ||||
|  | ||||
| func summaryMetricName(name string) string { | ||||
| 	switch { | ||||
| 	case isCount(name): | ||||
| 		return name[:len(name)-6] | ||||
| 	case isSum(name): | ||||
| 		return name[:len(name)-4] | ||||
| 	default: | ||||
| 		return name | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func histogramMetricName(name string) string { | ||||
| 	switch { | ||||
| 	case isCount(name): | ||||
| 		return name[:len(name)-6] | ||||
| 	case isSum(name): | ||||
| 		return name[:len(name)-4] | ||||
| 	case isBucket(name): | ||||
| 		return name[:len(name)-7] | ||||
| 	default: | ||||
| 		return name | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										67
									
								
								vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| PACKAGE | ||||
|  | ||||
| package goautoneg | ||||
| import "bitbucket.org/ww/goautoneg" | ||||
|  | ||||
| HTTP Content-Type Autonegotiation. | ||||
|  | ||||
| The functions in this package implement the behaviour specified in | ||||
| http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html | ||||
|  | ||||
| Copyright (c) 2011, Open Knowledge Foundation Ltd. | ||||
| All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|  | ||||
|     Redistributions of source code must retain the above copyright | ||||
|     notice, this list of conditions and the following disclaimer. | ||||
|  | ||||
|     Redistributions in binary form must reproduce the above copyright | ||||
|     notice, this list of conditions and the following disclaimer in | ||||
|     the documentation and/or other materials provided with the | ||||
|     distribution. | ||||
|  | ||||
|     Neither the name of the Open Knowledge Foundation Ltd. nor the | ||||
|     names of its contributors may be used to endorse or promote | ||||
|     products derived from this software without specific prior written | ||||
|     permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
|  | ||||
| FUNCTIONS | ||||
|  | ||||
| func Negotiate(header string, alternatives []string) (content_type string) | ||||
| Negotiate the most appropriate content_type given the accept header | ||||
| and a list of alternatives. | ||||
|  | ||||
| func ParseAccept(header string) (accept []Accept) | ||||
| Parse an Accept Header string returning a sorted list | ||||
| of clauses | ||||
|  | ||||
|  | ||||
| TYPES | ||||
|  | ||||
| type Accept struct { | ||||
|     Type, SubType string | ||||
|     Q             float32 | ||||
|     Params        map[string]string | ||||
| } | ||||
| Structure to represent a clause in an HTTP Accept Header | ||||
|  | ||||
|  | ||||
| SUBDIRECTORIES | ||||
|  | ||||
| 	.hg | ||||
							
								
								
									
										162
									
								
								vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| /* | ||||
| HTTP Content-Type Autonegotiation. | ||||
|  | ||||
| The functions in this package implement the behaviour specified in | ||||
| http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html | ||||
|  | ||||
| Copyright (c) 2011, Open Knowledge Foundation Ltd. | ||||
| All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|  | ||||
|     Redistributions of source code must retain the above copyright | ||||
|     notice, this list of conditions and the following disclaimer. | ||||
|  | ||||
|     Redistributions in binary form must reproduce the above copyright | ||||
|     notice, this list of conditions and the following disclaimer in | ||||
|     the documentation and/or other materials provided with the | ||||
|     distribution. | ||||
|  | ||||
|     Neither the name of the Open Knowledge Foundation Ltd. nor the | ||||
|     names of its contributors may be used to endorse or promote | ||||
|     products derived from this software without specific prior written | ||||
|     permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | ||||
|  | ||||
| */ | ||||
| package goautoneg | ||||
|  | ||||
| import ( | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // Structure to represent a clause in an HTTP Accept Header | ||||
| type Accept struct { | ||||
| 	Type, SubType string | ||||
| 	Q             float64 | ||||
| 	Params        map[string]string | ||||
| } | ||||
|  | ||||
| // For internal use, so that we can use the sort interface | ||||
| type accept_slice []Accept | ||||
|  | ||||
| func (accept accept_slice) Len() int { | ||||
| 	slice := []Accept(accept) | ||||
| 	return len(slice) | ||||
| } | ||||
|  | ||||
| func (accept accept_slice) Less(i, j int) bool { | ||||
| 	slice := []Accept(accept) | ||||
| 	ai, aj := slice[i], slice[j] | ||||
| 	if ai.Q > aj.Q { | ||||
| 		return true | ||||
| 	} | ||||
| 	if ai.Type != "*" && aj.Type == "*" { | ||||
| 		return true | ||||
| 	} | ||||
| 	if ai.SubType != "*" && aj.SubType == "*" { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (accept accept_slice) Swap(i, j int) { | ||||
| 	slice := []Accept(accept) | ||||
| 	slice[i], slice[j] = slice[j], slice[i] | ||||
| } | ||||
|  | ||||
| // Parse an Accept Header string returning a sorted list | ||||
| // of clauses | ||||
| func ParseAccept(header string) (accept []Accept) { | ||||
| 	parts := strings.Split(header, ",") | ||||
| 	accept = make([]Accept, 0, len(parts)) | ||||
| 	for _, part := range parts { | ||||
| 		part := strings.Trim(part, " ") | ||||
|  | ||||
| 		a := Accept{} | ||||
| 		a.Params = make(map[string]string) | ||||
| 		a.Q = 1.0 | ||||
|  | ||||
| 		mrp := strings.Split(part, ";") | ||||
|  | ||||
| 		media_range := mrp[0] | ||||
| 		sp := strings.Split(media_range, "/") | ||||
| 		a.Type = strings.Trim(sp[0], " ") | ||||
|  | ||||
| 		switch { | ||||
| 		case len(sp) == 1 && a.Type == "*": | ||||
| 			a.SubType = "*" | ||||
| 		case len(sp) == 2: | ||||
| 			a.SubType = strings.Trim(sp[1], " ") | ||||
| 		default: | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if len(mrp) == 1 { | ||||
| 			accept = append(accept, a) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		for _, param := range mrp[1:] { | ||||
| 			sp := strings.SplitN(param, "=", 2) | ||||
| 			if len(sp) != 2 { | ||||
| 				continue | ||||
| 			} | ||||
| 			token := strings.Trim(sp[0], " ") | ||||
| 			if token == "q" { | ||||
| 				a.Q, _ = strconv.ParseFloat(sp[1], 32) | ||||
| 			} else { | ||||
| 				a.Params[token] = strings.Trim(sp[1], " ") | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		accept = append(accept, a) | ||||
| 	} | ||||
|  | ||||
| 	slice := accept_slice(accept) | ||||
| 	sort.Sort(slice) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Negotiate the most appropriate content_type given the accept header | ||||
| // and a list of alternatives. | ||||
| func Negotiate(header string, alternatives []string) (content_type string) { | ||||
| 	asp := make([][]string, 0, len(alternatives)) | ||||
| 	for _, ctype := range alternatives { | ||||
| 		asp = append(asp, strings.SplitN(ctype, "/", 2)) | ||||
| 	} | ||||
| 	for _, clause := range ParseAccept(header) { | ||||
| 		for i, ctsp := range asp { | ||||
| 			if clause.Type == ctsp[0] && clause.SubType == ctsp[1] { | ||||
| 				content_type = alternatives[i] | ||||
| 				return | ||||
| 			} | ||||
| 			if clause.Type == ctsp[0] && clause.SubType == "*" { | ||||
| 				content_type = alternatives[i] | ||||
| 				return | ||||
| 			} | ||||
| 			if clause.Type == "*" && clause.SubType == "*" { | ||||
| 				content_type = alternatives[i] | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										136
									
								
								vendor/github.com/prometheus/common/model/alert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								vendor/github.com/prometheus/common/model/alert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type AlertStatus string | ||||
|  | ||||
| const ( | ||||
| 	AlertFiring   AlertStatus = "firing" | ||||
| 	AlertResolved AlertStatus = "resolved" | ||||
| ) | ||||
|  | ||||
| // Alert is a generic representation of an alert in the Prometheus eco-system. | ||||
| type Alert struct { | ||||
| 	// Label value pairs for purpose of aggregation, matching, and disposition | ||||
| 	// dispatching. This must minimally include an "alertname" label. | ||||
| 	Labels LabelSet `json:"labels"` | ||||
|  | ||||
| 	// Extra key/value information which does not define alert identity. | ||||
| 	Annotations LabelSet `json:"annotations"` | ||||
|  | ||||
| 	// The known time range for this alert. Both ends are optional. | ||||
| 	StartsAt     time.Time `json:"startsAt,omitempty"` | ||||
| 	EndsAt       time.Time `json:"endsAt,omitempty"` | ||||
| 	GeneratorURL string    `json:"generatorURL"` | ||||
| } | ||||
|  | ||||
| // Name returns the name of the alert. It is equivalent to the "alertname" label. | ||||
| func (a *Alert) Name() string { | ||||
| 	return string(a.Labels[AlertNameLabel]) | ||||
| } | ||||
|  | ||||
| // Fingerprint returns a unique hash for the alert. It is equivalent to | ||||
| // the fingerprint of the alert's label set. | ||||
| func (a *Alert) Fingerprint() Fingerprint { | ||||
| 	return a.Labels.Fingerprint() | ||||
| } | ||||
|  | ||||
| func (a *Alert) String() string { | ||||
| 	s := fmt.Sprintf("%s[%s]", a.Name(), a.Fingerprint().String()[:7]) | ||||
| 	if a.Resolved() { | ||||
| 		return s + "[resolved]" | ||||
| 	} | ||||
| 	return s + "[active]" | ||||
| } | ||||
|  | ||||
| // Resolved returns true iff the activity interval ended in the past. | ||||
| func (a *Alert) Resolved() bool { | ||||
| 	return a.ResolvedAt(time.Now()) | ||||
| } | ||||
|  | ||||
| // ResolvedAt returns true off the activity interval ended before | ||||
| // the given timestamp. | ||||
| func (a *Alert) ResolvedAt(ts time.Time) bool { | ||||
| 	if a.EndsAt.IsZero() { | ||||
| 		return false | ||||
| 	} | ||||
| 	return !a.EndsAt.After(ts) | ||||
| } | ||||
|  | ||||
| // Status returns the status of the alert. | ||||
| func (a *Alert) Status() AlertStatus { | ||||
| 	if a.Resolved() { | ||||
| 		return AlertResolved | ||||
| 	} | ||||
| 	return AlertFiring | ||||
| } | ||||
|  | ||||
| // Validate checks whether the alert data is inconsistent. | ||||
| func (a *Alert) Validate() error { | ||||
| 	if a.StartsAt.IsZero() { | ||||
| 		return fmt.Errorf("start time missing") | ||||
| 	} | ||||
| 	if !a.EndsAt.IsZero() && a.EndsAt.Before(a.StartsAt) { | ||||
| 		return fmt.Errorf("start time must be before end time") | ||||
| 	} | ||||
| 	if err := a.Labels.Validate(); err != nil { | ||||
| 		return fmt.Errorf("invalid label set: %s", err) | ||||
| 	} | ||||
| 	if len(a.Labels) == 0 { | ||||
| 		return fmt.Errorf("at least one label pair required") | ||||
| 	} | ||||
| 	if err := a.Annotations.Validate(); err != nil { | ||||
| 		return fmt.Errorf("invalid annotations: %s", err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Alert is a list of alerts that can be sorted in chronological order. | ||||
| type Alerts []*Alert | ||||
|  | ||||
| func (as Alerts) Len() int      { return len(as) } | ||||
| func (as Alerts) Swap(i, j int) { as[i], as[j] = as[j], as[i] } | ||||
|  | ||||
| func (as Alerts) Less(i, j int) bool { | ||||
| 	if as[i].StartsAt.Before(as[j].StartsAt) { | ||||
| 		return true | ||||
| 	} | ||||
| 	if as[i].EndsAt.Before(as[j].EndsAt) { | ||||
| 		return true | ||||
| 	} | ||||
| 	return as[i].Fingerprint() < as[j].Fingerprint() | ||||
| } | ||||
|  | ||||
| // HasFiring returns true iff one of the alerts is not resolved. | ||||
| func (as Alerts) HasFiring() bool { | ||||
| 	for _, a := range as { | ||||
| 		if !a.Resolved() { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Status returns StatusFiring iff at least one of the alerts is firing. | ||||
| func (as Alerts) Status() AlertStatus { | ||||
| 	if as.HasFiring() { | ||||
| 		return AlertFiring | ||||
| 	} | ||||
| 	return AlertResolved | ||||
| } | ||||
							
								
								
									
										105
									
								
								vendor/github.com/prometheus/common/model/fingerprinting.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								vendor/github.com/prometheus/common/model/fingerprinting.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // Fingerprint provides a hash-capable representation of a Metric. | ||||
| // For our purposes, FNV-1A 64-bit is used. | ||||
| type Fingerprint uint64 | ||||
|  | ||||
| // FingerprintFromString transforms a string representation into a Fingerprint. | ||||
| func FingerprintFromString(s string) (Fingerprint, error) { | ||||
| 	num, err := strconv.ParseUint(s, 16, 64) | ||||
| 	return Fingerprint(num), err | ||||
| } | ||||
|  | ||||
| // ParseFingerprint parses the input string into a fingerprint. | ||||
| func ParseFingerprint(s string) (Fingerprint, error) { | ||||
| 	num, err := strconv.ParseUint(s, 16, 64) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return Fingerprint(num), nil | ||||
| } | ||||
|  | ||||
| func (f Fingerprint) String() string { | ||||
| 	return fmt.Sprintf("%016x", uint64(f)) | ||||
| } | ||||
|  | ||||
| // Fingerprints represents a collection of Fingerprint subject to a given | ||||
| // natural sorting scheme. It implements sort.Interface. | ||||
| type Fingerprints []Fingerprint | ||||
|  | ||||
| // Len implements sort.Interface. | ||||
| func (f Fingerprints) Len() int { | ||||
| 	return len(f) | ||||
| } | ||||
|  | ||||
| // Less implements sort.Interface. | ||||
| func (f Fingerprints) Less(i, j int) bool { | ||||
| 	return f[i] < f[j] | ||||
| } | ||||
|  | ||||
| // Swap implements sort.Interface. | ||||
| func (f Fingerprints) Swap(i, j int) { | ||||
| 	f[i], f[j] = f[j], f[i] | ||||
| } | ||||
|  | ||||
| // FingerprintSet is a set of Fingerprints. | ||||
| type FingerprintSet map[Fingerprint]struct{} | ||||
|  | ||||
| // Equal returns true if both sets contain the same elements (and not more). | ||||
| func (s FingerprintSet) Equal(o FingerprintSet) bool { | ||||
| 	if len(s) != len(o) { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	for k := range s { | ||||
| 		if _, ok := o[k]; !ok { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // Intersection returns the elements contained in both sets. | ||||
| func (s FingerprintSet) Intersection(o FingerprintSet) FingerprintSet { | ||||
| 	myLength, otherLength := len(s), len(o) | ||||
| 	if myLength == 0 || otherLength == 0 { | ||||
| 		return FingerprintSet{} | ||||
| 	} | ||||
|  | ||||
| 	subSet := s | ||||
| 	superSet := o | ||||
|  | ||||
| 	if otherLength < myLength { | ||||
| 		subSet = o | ||||
| 		superSet = s | ||||
| 	} | ||||
|  | ||||
| 	out := FingerprintSet{} | ||||
|  | ||||
| 	for k := range subSet { | ||||
| 		if _, ok := superSet[k]; ok { | ||||
| 			out[k] = struct{}{} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return out | ||||
| } | ||||
							
								
								
									
										42
									
								
								vendor/github.com/prometheus/common/model/fnv.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/prometheus/common/model/fnv.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| // 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 model | ||||
|  | ||||
| // Inline and byte-free variant of hash/fnv's fnv64a. | ||||
|  | ||||
| const ( | ||||
| 	offset64 = 14695981039346656037 | ||||
| 	prime64  = 1099511628211 | ||||
| ) | ||||
|  | ||||
| // hashNew initializies a new fnv64a hash value. | ||||
| func hashNew() uint64 { | ||||
| 	return offset64 | ||||
| } | ||||
|  | ||||
| // hashAdd adds a string to a fnv64a hash value, returning the updated hash. | ||||
| func hashAdd(h uint64, s string) uint64 { | ||||
| 	for i := 0; i < len(s); i++ { | ||||
| 		h ^= uint64(s[i]) | ||||
| 		h *= prime64 | ||||
| 	} | ||||
| 	return h | ||||
| } | ||||
|  | ||||
| // hashAddByte adds a byte to a fnv64a hash value, returning the updated hash. | ||||
| func hashAddByte(h uint64, b byte) uint64 { | ||||
| 	h ^= uint64(b) | ||||
| 	h *= prime64 | ||||
| 	return h | ||||
| } | ||||
							
								
								
									
										210
									
								
								vendor/github.com/prometheus/common/model/labels.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								vendor/github.com/prometheus/common/model/labels.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,210 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// AlertNameLabel is the name of the label containing the an alert's name. | ||||
| 	AlertNameLabel = "alertname" | ||||
|  | ||||
| 	// ExportedLabelPrefix is the prefix to prepend to the label names present in | ||||
| 	// exported metrics if a label of the same name is added by the server. | ||||
| 	ExportedLabelPrefix = "exported_" | ||||
|  | ||||
| 	// MetricNameLabel is the label name indicating the metric name of a | ||||
| 	// timeseries. | ||||
| 	MetricNameLabel = "__name__" | ||||
|  | ||||
| 	// SchemeLabel is the name of the label that holds the scheme on which to | ||||
| 	// scrape a target. | ||||
| 	SchemeLabel = "__scheme__" | ||||
|  | ||||
| 	// AddressLabel is the name of the label that holds the address of | ||||
| 	// a scrape target. | ||||
| 	AddressLabel = "__address__" | ||||
|  | ||||
| 	// MetricsPathLabel is the name of the label that holds the path on which to | ||||
| 	// scrape a target. | ||||
| 	MetricsPathLabel = "__metrics_path__" | ||||
|  | ||||
| 	// ReservedLabelPrefix is a prefix which is not legal in user-supplied | ||||
| 	// label names. | ||||
| 	ReservedLabelPrefix = "__" | ||||
|  | ||||
| 	// MetaLabelPrefix is a prefix for labels that provide meta information. | ||||
| 	// Labels with this prefix are used for intermediate label processing and | ||||
| 	// will not be attached to time series. | ||||
| 	MetaLabelPrefix = "__meta_" | ||||
|  | ||||
| 	// TmpLabelPrefix is a prefix for temporary labels as part of relabelling. | ||||
| 	// Labels with this prefix are used for intermediate label processing and | ||||
| 	// will not be attached to time series. This is reserved for use in | ||||
| 	// Prometheus configuration files by users. | ||||
| 	TmpLabelPrefix = "__tmp_" | ||||
|  | ||||
| 	// ParamLabelPrefix is a prefix for labels that provide URL parameters | ||||
| 	// used to scrape a target. | ||||
| 	ParamLabelPrefix = "__param_" | ||||
|  | ||||
| 	// JobLabel is the label name indicating the job from which a timeseries | ||||
| 	// was scraped. | ||||
| 	JobLabel = "job" | ||||
|  | ||||
| 	// InstanceLabel is the label name used for the instance label. | ||||
| 	InstanceLabel = "instance" | ||||
|  | ||||
| 	// BucketLabel is used for the label that defines the upper bound of a | ||||
| 	// bucket of a histogram ("le" -> "less or equal"). | ||||
| 	BucketLabel = "le" | ||||
|  | ||||
| 	// QuantileLabel is used for the label that defines the quantile in a | ||||
| 	// summary. | ||||
| 	QuantileLabel = "quantile" | ||||
| ) | ||||
|  | ||||
| // LabelNameRE is a regular expression matching valid label names. Note that the | ||||
| // IsValid method of LabelName performs the same check but faster than a match | ||||
| // with this regular expression. | ||||
| var LabelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") | ||||
|  | ||||
| // A LabelName is a key for a LabelSet or Metric.  It has a value associated | ||||
| // therewith. | ||||
| type LabelName string | ||||
|  | ||||
| // IsValid is true iff the label name matches the pattern of LabelNameRE. This | ||||
| // method, however, does not use LabelNameRE for the check but a much faster | ||||
| // hardcoded implementation. | ||||
| func (ln LabelName) IsValid() bool { | ||||
| 	if len(ln) == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	for i, b := range ln { | ||||
| 		if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0)) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // UnmarshalYAML implements the yaml.Unmarshaler interface. | ||||
| func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error { | ||||
| 	var s string | ||||
| 	if err := unmarshal(&s); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if !LabelName(s).IsValid() { | ||||
| 		return fmt.Errorf("%q is not a valid label name", s) | ||||
| 	} | ||||
| 	*ln = LabelName(s) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON implements the json.Unmarshaler interface. | ||||
| func (ln *LabelName) UnmarshalJSON(b []byte) error { | ||||
| 	var s string | ||||
| 	if err := json.Unmarshal(b, &s); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if !LabelName(s).IsValid() { | ||||
| 		return fmt.Errorf("%q is not a valid label name", s) | ||||
| 	} | ||||
| 	*ln = LabelName(s) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // LabelNames is a sortable LabelName slice. In implements sort.Interface. | ||||
| type LabelNames []LabelName | ||||
|  | ||||
| func (l LabelNames) Len() int { | ||||
| 	return len(l) | ||||
| } | ||||
|  | ||||
| func (l LabelNames) Less(i, j int) bool { | ||||
| 	return l[i] < l[j] | ||||
| } | ||||
|  | ||||
| func (l LabelNames) Swap(i, j int) { | ||||
| 	l[i], l[j] = l[j], l[i] | ||||
| } | ||||
|  | ||||
| func (l LabelNames) String() string { | ||||
| 	labelStrings := make([]string, 0, len(l)) | ||||
| 	for _, label := range l { | ||||
| 		labelStrings = append(labelStrings, string(label)) | ||||
| 	} | ||||
| 	return strings.Join(labelStrings, ", ") | ||||
| } | ||||
|  | ||||
| // A LabelValue is an associated value for a LabelName. | ||||
| type LabelValue string | ||||
|  | ||||
| // IsValid returns true iff the string is a valid UTF8. | ||||
| func (lv LabelValue) IsValid() bool { | ||||
| 	return utf8.ValidString(string(lv)) | ||||
| } | ||||
|  | ||||
| // LabelValues is a sortable LabelValue slice. It implements sort.Interface. | ||||
| type LabelValues []LabelValue | ||||
|  | ||||
| func (l LabelValues) Len() int { | ||||
| 	return len(l) | ||||
| } | ||||
|  | ||||
| func (l LabelValues) Less(i, j int) bool { | ||||
| 	return string(l[i]) < string(l[j]) | ||||
| } | ||||
|  | ||||
| func (l LabelValues) Swap(i, j int) { | ||||
| 	l[i], l[j] = l[j], l[i] | ||||
| } | ||||
|  | ||||
| // LabelPair pairs a name with a value. | ||||
| type LabelPair struct { | ||||
| 	Name  LabelName | ||||
| 	Value LabelValue | ||||
| } | ||||
|  | ||||
| // LabelPairs is a sortable slice of LabelPair pointers. It implements | ||||
| // sort.Interface. | ||||
| type LabelPairs []*LabelPair | ||||
|  | ||||
| func (l LabelPairs) Len() int { | ||||
| 	return len(l) | ||||
| } | ||||
|  | ||||
| func (l LabelPairs) Less(i, j int) bool { | ||||
| 	switch { | ||||
| 	case l[i].Name > l[j].Name: | ||||
| 		return false | ||||
| 	case l[i].Name < l[j].Name: | ||||
| 		return true | ||||
| 	case l[i].Value > l[j].Value: | ||||
| 		return false | ||||
| 	case l[i].Value < l[j].Value: | ||||
| 		return true | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (l LabelPairs) Swap(i, j int) { | ||||
| 	l[i], l[j] = l[j], l[i] | ||||
| } | ||||
							
								
								
									
										169
									
								
								vendor/github.com/prometheus/common/model/labelset.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								vendor/github.com/prometheus/common/model/labelset.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // A LabelSet is a collection of LabelName and LabelValue pairs.  The LabelSet | ||||
| // may be fully-qualified down to the point where it may resolve to a single | ||||
| // Metric in the data store or not.  All operations that occur within the realm | ||||
| // of a LabelSet can emit a vector of Metric entities to which the LabelSet may | ||||
| // match. | ||||
| type LabelSet map[LabelName]LabelValue | ||||
|  | ||||
| // Validate checks whether all names and values in the label set | ||||
| // are valid. | ||||
| func (ls LabelSet) Validate() error { | ||||
| 	for ln, lv := range ls { | ||||
| 		if !ln.IsValid() { | ||||
| 			return fmt.Errorf("invalid name %q", ln) | ||||
| 		} | ||||
| 		if !lv.IsValid() { | ||||
| 			return fmt.Errorf("invalid value %q", lv) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Equal returns true iff both label sets have exactly the same key/value pairs. | ||||
| func (ls LabelSet) Equal(o LabelSet) bool { | ||||
| 	if len(ls) != len(o) { | ||||
| 		return false | ||||
| 	} | ||||
| 	for ln, lv := range ls { | ||||
| 		olv, ok := o[ln] | ||||
| 		if !ok { | ||||
| 			return false | ||||
| 		} | ||||
| 		if olv != lv { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // Before compares the metrics, using the following criteria: | ||||
| // | ||||
| // If m has fewer labels than o, it is before o. If it has more, it is not. | ||||
| // | ||||
| // If the number of labels is the same, the superset of all label names is | ||||
| // sorted alphanumerically. The first differing label pair found in that order | ||||
| // determines the outcome: If the label does not exist at all in m, then m is | ||||
| // before o, and vice versa. Otherwise the label value is compared | ||||
| // alphanumerically. | ||||
| // | ||||
| // If m and o are equal, the method returns false. | ||||
| func (ls LabelSet) Before(o LabelSet) bool { | ||||
| 	if len(ls) < len(o) { | ||||
| 		return true | ||||
| 	} | ||||
| 	if len(ls) > len(o) { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	lns := make(LabelNames, 0, len(ls)+len(o)) | ||||
| 	for ln := range ls { | ||||
| 		lns = append(lns, ln) | ||||
| 	} | ||||
| 	for ln := range o { | ||||
| 		lns = append(lns, ln) | ||||
| 	} | ||||
| 	// It's probably not worth it to de-dup lns. | ||||
| 	sort.Sort(lns) | ||||
| 	for _, ln := range lns { | ||||
| 		mlv, ok := ls[ln] | ||||
| 		if !ok { | ||||
| 			return true | ||||
| 		} | ||||
| 		olv, ok := o[ln] | ||||
| 		if !ok { | ||||
| 			return false | ||||
| 		} | ||||
| 		if mlv < olv { | ||||
| 			return true | ||||
| 		} | ||||
| 		if mlv > olv { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Clone returns a copy of the label set. | ||||
| func (ls LabelSet) Clone() LabelSet { | ||||
| 	lsn := make(LabelSet, len(ls)) | ||||
| 	for ln, lv := range ls { | ||||
| 		lsn[ln] = lv | ||||
| 	} | ||||
| 	return lsn | ||||
| } | ||||
|  | ||||
| // Merge is a helper function to non-destructively merge two label sets. | ||||
| func (l LabelSet) Merge(other LabelSet) LabelSet { | ||||
| 	result := make(LabelSet, len(l)) | ||||
|  | ||||
| 	for k, v := range l { | ||||
| 		result[k] = v | ||||
| 	} | ||||
|  | ||||
| 	for k, v := range other { | ||||
| 		result[k] = v | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| func (l LabelSet) String() string { | ||||
| 	lstrs := make([]string, 0, len(l)) | ||||
| 	for l, v := range l { | ||||
| 		lstrs = append(lstrs, fmt.Sprintf("%s=%q", l, v)) | ||||
| 	} | ||||
|  | ||||
| 	sort.Strings(lstrs) | ||||
| 	return fmt.Sprintf("{%s}", strings.Join(lstrs, ", ")) | ||||
| } | ||||
|  | ||||
| // Fingerprint returns the LabelSet's fingerprint. | ||||
| func (ls LabelSet) Fingerprint() Fingerprint { | ||||
| 	return labelSetToFingerprint(ls) | ||||
| } | ||||
|  | ||||
| // FastFingerprint returns the LabelSet's Fingerprint calculated by a faster hashing | ||||
| // algorithm, which is, however, more susceptible to hash collisions. | ||||
| func (ls LabelSet) FastFingerprint() Fingerprint { | ||||
| 	return labelSetToFastFingerprint(ls) | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON implements the json.Unmarshaler interface. | ||||
| func (l *LabelSet) UnmarshalJSON(b []byte) error { | ||||
| 	var m map[LabelName]LabelValue | ||||
| 	if err := json.Unmarshal(b, &m); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	// encoding/json only unmarshals maps of the form map[string]T. It treats | ||||
| 	// LabelName as a string and does not call its UnmarshalJSON method. | ||||
| 	// Thus, we have to replicate the behavior here. | ||||
| 	for ln := range m { | ||||
| 		if !ln.IsValid() { | ||||
| 			return fmt.Errorf("%q is not a valid label name", ln) | ||||
| 		} | ||||
| 	} | ||||
| 	*l = LabelSet(m) | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										103
									
								
								vendor/github.com/prometheus/common/model/metric.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vendor/github.com/prometheus/common/model/metric.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	separator = []byte{0} | ||||
| 	// MetricNameRE is a regular expression matching valid metric | ||||
| 	// names. Note that the IsValidMetricName function performs the same | ||||
| 	// check but faster than a match with this regular expression. | ||||
| 	MetricNameRE = regexp.MustCompile(`^[a-zA-Z_:][a-zA-Z0-9_:]*$`) | ||||
| ) | ||||
|  | ||||
| // A Metric is similar to a LabelSet, but the key difference is that a Metric is | ||||
| // a singleton and refers to one and only one stream of samples. | ||||
| type Metric LabelSet | ||||
|  | ||||
| // Equal compares the metrics. | ||||
| func (m Metric) Equal(o Metric) bool { | ||||
| 	return LabelSet(m).Equal(LabelSet(o)) | ||||
| } | ||||
|  | ||||
| // Before compares the metrics' underlying label sets. | ||||
| func (m Metric) Before(o Metric) bool { | ||||
| 	return LabelSet(m).Before(LabelSet(o)) | ||||
| } | ||||
|  | ||||
| // Clone returns a copy of the Metric. | ||||
| func (m Metric) Clone() Metric { | ||||
| 	clone := make(Metric, len(m)) | ||||
| 	for k, v := range m { | ||||
| 		clone[k] = v | ||||
| 	} | ||||
| 	return clone | ||||
| } | ||||
|  | ||||
| func (m Metric) String() string { | ||||
| 	metricName, hasName := m[MetricNameLabel] | ||||
| 	numLabels := len(m) - 1 | ||||
| 	if !hasName { | ||||
| 		numLabels = len(m) | ||||
| 	} | ||||
| 	labelStrings := make([]string, 0, numLabels) | ||||
| 	for label, value := range m { | ||||
| 		if label != MetricNameLabel { | ||||
| 			labelStrings = append(labelStrings, fmt.Sprintf("%s=%q", label, value)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	switch numLabels { | ||||
| 	case 0: | ||||
| 		if hasName { | ||||
| 			return string(metricName) | ||||
| 		} | ||||
| 		return "{}" | ||||
| 	default: | ||||
| 		sort.Strings(labelStrings) | ||||
| 		return fmt.Sprintf("%s{%s}", metricName, strings.Join(labelStrings, ", ")) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Fingerprint returns a Metric's Fingerprint. | ||||
| func (m Metric) Fingerprint() Fingerprint { | ||||
| 	return LabelSet(m).Fingerprint() | ||||
| } | ||||
|  | ||||
| // FastFingerprint returns a Metric's Fingerprint calculated by a faster hashing | ||||
| // algorithm, which is, however, more susceptible to hash collisions. | ||||
| func (m Metric) FastFingerprint() Fingerprint { | ||||
| 	return LabelSet(m).FastFingerprint() | ||||
| } | ||||
|  | ||||
| // IsValidMetricName returns true iff name matches the pattern of MetricNameRE. | ||||
| // This function, however, does not use MetricNameRE for the check but a much | ||||
| // faster hardcoded implementation. | ||||
| func IsValidMetricName(n LabelValue) bool { | ||||
| 	if len(n) == 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	for i, b := range n { | ||||
| 		if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || b == ':' || (b >= '0' && b <= '9' && i > 0)) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/github.com/prometheus/common/model/model.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/prometheus/common/model/model.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| // Copyright 2013 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 model contains common data structures that are shared across | ||||
| // Prometheus components and libraries. | ||||
| package model | ||||
							
								
								
									
										144
									
								
								vendor/github.com/prometheus/common/model/signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								vendor/github.com/prometheus/common/model/signature.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| // 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 model | ||||
|  | ||||
| import ( | ||||
| 	"sort" | ||||
| ) | ||||
|  | ||||
| // SeparatorByte is a byte that cannot occur in valid UTF-8 sequences and is | ||||
| // used to separate label names, label values, and other strings from each other | ||||
| // when calculating their combined hash value (aka signature aka fingerprint). | ||||
| const SeparatorByte byte = 255 | ||||
|  | ||||
| var ( | ||||
| 	// cache the signature of an empty label set. | ||||
| 	emptyLabelSignature = hashNew() | ||||
| ) | ||||
|  | ||||
| // LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a | ||||
| // given label set. (Collisions are possible but unlikely if the number of label | ||||
| // sets the function is applied to is small.) | ||||
| func LabelsToSignature(labels map[string]string) uint64 { | ||||
| 	if len(labels) == 0 { | ||||
| 		return emptyLabelSignature | ||||
| 	} | ||||
|  | ||||
| 	labelNames := make([]string, 0, len(labels)) | ||||
| 	for labelName := range labels { | ||||
| 		labelNames = append(labelNames, labelName) | ||||
| 	} | ||||
| 	sort.Strings(labelNames) | ||||
|  | ||||
| 	sum := hashNew() | ||||
| 	for _, labelName := range labelNames { | ||||
| 		sum = hashAdd(sum, labelName) | ||||
| 		sum = hashAddByte(sum, SeparatorByte) | ||||
| 		sum = hashAdd(sum, labels[labelName]) | ||||
| 		sum = hashAddByte(sum, SeparatorByte) | ||||
| 	} | ||||
| 	return sum | ||||
| } | ||||
|  | ||||
| // labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as | ||||
| // parameter (rather than a label map) and returns a Fingerprint. | ||||
| func labelSetToFingerprint(ls LabelSet) Fingerprint { | ||||
| 	if len(ls) == 0 { | ||||
| 		return Fingerprint(emptyLabelSignature) | ||||
| 	} | ||||
|  | ||||
| 	labelNames := make(LabelNames, 0, len(ls)) | ||||
| 	for labelName := range ls { | ||||
| 		labelNames = append(labelNames, labelName) | ||||
| 	} | ||||
| 	sort.Sort(labelNames) | ||||
|  | ||||
| 	sum := hashNew() | ||||
| 	for _, labelName := range labelNames { | ||||
| 		sum = hashAdd(sum, string(labelName)) | ||||
| 		sum = hashAddByte(sum, SeparatorByte) | ||||
| 		sum = hashAdd(sum, string(ls[labelName])) | ||||
| 		sum = hashAddByte(sum, SeparatorByte) | ||||
| 	} | ||||
| 	return Fingerprint(sum) | ||||
| } | ||||
|  | ||||
| // labelSetToFastFingerprint works similar to labelSetToFingerprint but uses a | ||||
| // faster and less allocation-heavy hash function, which is more susceptible to | ||||
| // create hash collisions. Therefore, collision detection should be applied. | ||||
| func labelSetToFastFingerprint(ls LabelSet) Fingerprint { | ||||
| 	if len(ls) == 0 { | ||||
| 		return Fingerprint(emptyLabelSignature) | ||||
| 	} | ||||
|  | ||||
| 	var result uint64 | ||||
| 	for labelName, labelValue := range ls { | ||||
| 		sum := hashNew() | ||||
| 		sum = hashAdd(sum, string(labelName)) | ||||
| 		sum = hashAddByte(sum, SeparatorByte) | ||||
| 		sum = hashAdd(sum, string(labelValue)) | ||||
| 		result ^= sum | ||||
| 	} | ||||
| 	return Fingerprint(result) | ||||
| } | ||||
|  | ||||
| // SignatureForLabels works like LabelsToSignature but takes a Metric as | ||||
| // parameter (rather than a label map) and only includes the labels with the | ||||
| // specified LabelNames into the signature calculation. The labels passed in | ||||
| // will be sorted by this function. | ||||
| func SignatureForLabels(m Metric, labels ...LabelName) uint64 { | ||||
| 	if len(labels) == 0 { | ||||
| 		return emptyLabelSignature | ||||
| 	} | ||||
|  | ||||
| 	sort.Sort(LabelNames(labels)) | ||||
|  | ||||
| 	sum := hashNew() | ||||
| 	for _, label := range labels { | ||||
| 		sum = hashAdd(sum, string(label)) | ||||
| 		sum = hashAddByte(sum, SeparatorByte) | ||||
| 		sum = hashAdd(sum, string(m[label])) | ||||
| 		sum = hashAddByte(sum, SeparatorByte) | ||||
| 	} | ||||
| 	return sum | ||||
| } | ||||
|  | ||||
| // SignatureWithoutLabels works like LabelsToSignature but takes a Metric as | ||||
| // parameter (rather than a label map) and excludes the labels with any of the | ||||
| // specified LabelNames from the signature calculation. | ||||
| func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 { | ||||
| 	if len(m) == 0 { | ||||
| 		return emptyLabelSignature | ||||
| 	} | ||||
|  | ||||
| 	labelNames := make(LabelNames, 0, len(m)) | ||||
| 	for labelName := range m { | ||||
| 		if _, exclude := labels[labelName]; !exclude { | ||||
| 			labelNames = append(labelNames, labelName) | ||||
| 		} | ||||
| 	} | ||||
| 	if len(labelNames) == 0 { | ||||
| 		return emptyLabelSignature | ||||
| 	} | ||||
| 	sort.Sort(labelNames) | ||||
|  | ||||
| 	sum := hashNew() | ||||
| 	for _, labelName := range labelNames { | ||||
| 		sum = hashAdd(sum, string(labelName)) | ||||
| 		sum = hashAddByte(sum, SeparatorByte) | ||||
| 		sum = hashAdd(sum, string(m[labelName])) | ||||
| 		sum = hashAddByte(sum, SeparatorByte) | ||||
| 	} | ||||
| 	return sum | ||||
| } | ||||
							
								
								
									
										106
									
								
								vendor/github.com/prometheus/common/model/silence.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								vendor/github.com/prometheus/common/model/silence.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| // 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 model | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // Matcher describes a matches the value of a given label. | ||||
| type Matcher struct { | ||||
| 	Name    LabelName `json:"name"` | ||||
| 	Value   string    `json:"value"` | ||||
| 	IsRegex bool      `json:"isRegex"` | ||||
| } | ||||
|  | ||||
| func (m *Matcher) UnmarshalJSON(b []byte) error { | ||||
| 	type plain Matcher | ||||
| 	if err := json.Unmarshal(b, (*plain)(m)); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if len(m.Name) == 0 { | ||||
| 		return fmt.Errorf("label name in matcher must not be empty") | ||||
| 	} | ||||
| 	if m.IsRegex { | ||||
| 		if _, err := regexp.Compile(m.Value); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Validate returns true iff all fields of the matcher have valid values. | ||||
| func (m *Matcher) Validate() error { | ||||
| 	if !m.Name.IsValid() { | ||||
| 		return fmt.Errorf("invalid name %q", m.Name) | ||||
| 	} | ||||
| 	if m.IsRegex { | ||||
| 		if _, err := regexp.Compile(m.Value); err != nil { | ||||
| 			return fmt.Errorf("invalid regular expression %q", m.Value) | ||||
| 		} | ||||
| 	} else if !LabelValue(m.Value).IsValid() || len(m.Value) == 0 { | ||||
| 		return fmt.Errorf("invalid value %q", m.Value) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Silence defines the representation of a silence definition in the Prometheus | ||||
| // eco-system. | ||||
| type Silence struct { | ||||
| 	ID uint64 `json:"id,omitempty"` | ||||
|  | ||||
| 	Matchers []*Matcher `json:"matchers"` | ||||
|  | ||||
| 	StartsAt time.Time `json:"startsAt"` | ||||
| 	EndsAt   time.Time `json:"endsAt"` | ||||
|  | ||||
| 	CreatedAt time.Time `json:"createdAt,omitempty"` | ||||
| 	CreatedBy string    `json:"createdBy"` | ||||
| 	Comment   string    `json:"comment,omitempty"` | ||||
| } | ||||
|  | ||||
| // Validate returns true iff all fields of the silence have valid values. | ||||
| func (s *Silence) Validate() error { | ||||
| 	if len(s.Matchers) == 0 { | ||||
| 		return fmt.Errorf("at least one matcher required") | ||||
| 	} | ||||
| 	for _, m := range s.Matchers { | ||||
| 		if err := m.Validate(); err != nil { | ||||
| 			return fmt.Errorf("invalid matcher: %s", err) | ||||
| 		} | ||||
| 	} | ||||
| 	if s.StartsAt.IsZero() { | ||||
| 		return fmt.Errorf("start time missing") | ||||
| 	} | ||||
| 	if s.EndsAt.IsZero() { | ||||
| 		return fmt.Errorf("end time missing") | ||||
| 	} | ||||
| 	if s.EndsAt.Before(s.StartsAt) { | ||||
| 		return fmt.Errorf("start time must be before end time") | ||||
| 	} | ||||
| 	if s.CreatedBy == "" { | ||||
| 		return fmt.Errorf("creator information missing") | ||||
| 	} | ||||
| 	if s.Comment == "" { | ||||
| 		return fmt.Errorf("comment missing") | ||||
| 	} | ||||
| 	if s.CreatedAt.IsZero() { | ||||
| 		return fmt.Errorf("creation timestamp missing") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										264
									
								
								vendor/github.com/prometheus/common/model/time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								vendor/github.com/prometheus/common/model/time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,264 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// MinimumTick is the minimum supported time resolution. This has to be | ||||
| 	// at least time.Second in order for the code below to work. | ||||
| 	minimumTick = time.Millisecond | ||||
| 	// second is the Time duration equivalent to one second. | ||||
| 	second = int64(time.Second / minimumTick) | ||||
| 	// The number of nanoseconds per minimum tick. | ||||
| 	nanosPerTick = int64(minimumTick / time.Nanosecond) | ||||
|  | ||||
| 	// Earliest is the earliest Time representable. Handy for | ||||
| 	// initializing a high watermark. | ||||
| 	Earliest = Time(math.MinInt64) | ||||
| 	// Latest is the latest Time representable. Handy for initializing | ||||
| 	// a low watermark. | ||||
| 	Latest = Time(math.MaxInt64) | ||||
| ) | ||||
|  | ||||
| // Time is the number of milliseconds since the epoch | ||||
| // (1970-01-01 00:00 UTC) excluding leap seconds. | ||||
| type Time int64 | ||||
|  | ||||
| // Interval describes an interval between two timestamps. | ||||
| type Interval struct { | ||||
| 	Start, End Time | ||||
| } | ||||
|  | ||||
| // Now returns the current time as a Time. | ||||
| func Now() Time { | ||||
| 	return TimeFromUnixNano(time.Now().UnixNano()) | ||||
| } | ||||
|  | ||||
| // TimeFromUnix returns the Time equivalent to the Unix Time t | ||||
| // provided in seconds. | ||||
| func TimeFromUnix(t int64) Time { | ||||
| 	return Time(t * second) | ||||
| } | ||||
|  | ||||
| // TimeFromUnixNano returns the Time equivalent to the Unix Time | ||||
| // t provided in nanoseconds. | ||||
| func TimeFromUnixNano(t int64) Time { | ||||
| 	return Time(t / nanosPerTick) | ||||
| } | ||||
|  | ||||
| // Equal reports whether two Times represent the same instant. | ||||
| func (t Time) Equal(o Time) bool { | ||||
| 	return t == o | ||||
| } | ||||
|  | ||||
| // Before reports whether the Time t is before o. | ||||
| func (t Time) Before(o Time) bool { | ||||
| 	return t < o | ||||
| } | ||||
|  | ||||
| // After reports whether the Time t is after o. | ||||
| func (t Time) After(o Time) bool { | ||||
| 	return t > o | ||||
| } | ||||
|  | ||||
| // Add returns the Time t + d. | ||||
| func (t Time) Add(d time.Duration) Time { | ||||
| 	return t + Time(d/minimumTick) | ||||
| } | ||||
|  | ||||
| // Sub returns the Duration t - o. | ||||
| func (t Time) Sub(o Time) time.Duration { | ||||
| 	return time.Duration(t-o) * minimumTick | ||||
| } | ||||
|  | ||||
| // Time returns the time.Time representation of t. | ||||
| func (t Time) Time() time.Time { | ||||
| 	return time.Unix(int64(t)/second, (int64(t)%second)*nanosPerTick) | ||||
| } | ||||
|  | ||||
| // Unix returns t as a Unix time, the number of seconds elapsed | ||||
| // since January 1, 1970 UTC. | ||||
| func (t Time) Unix() int64 { | ||||
| 	return int64(t) / second | ||||
| } | ||||
|  | ||||
| // UnixNano returns t as a Unix time, the number of nanoseconds elapsed | ||||
| // since January 1, 1970 UTC. | ||||
| func (t Time) UnixNano() int64 { | ||||
| 	return int64(t) * nanosPerTick | ||||
| } | ||||
|  | ||||
| // The number of digits after the dot. | ||||
| var dotPrecision = int(math.Log10(float64(second))) | ||||
|  | ||||
| // String returns a string representation of the Time. | ||||
| func (t Time) String() string { | ||||
| 	return strconv.FormatFloat(float64(t)/float64(second), 'f', -1, 64) | ||||
| } | ||||
|  | ||||
| // MarshalJSON implements the json.Marshaler interface. | ||||
| func (t Time) MarshalJSON() ([]byte, error) { | ||||
| 	return []byte(t.String()), nil | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON implements the json.Unmarshaler interface. | ||||
| func (t *Time) UnmarshalJSON(b []byte) error { | ||||
| 	p := strings.Split(string(b), ".") | ||||
| 	switch len(p) { | ||||
| 	case 1: | ||||
| 		v, err := strconv.ParseInt(string(p[0]), 10, 64) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		*t = Time(v * second) | ||||
|  | ||||
| 	case 2: | ||||
| 		v, err := strconv.ParseInt(string(p[0]), 10, 64) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		v *= second | ||||
|  | ||||
| 		prec := dotPrecision - len(p[1]) | ||||
| 		if prec < 0 { | ||||
| 			p[1] = p[1][:dotPrecision] | ||||
| 		} else if prec > 0 { | ||||
| 			p[1] = p[1] + strings.Repeat("0", prec) | ||||
| 		} | ||||
|  | ||||
| 		va, err := strconv.ParseInt(p[1], 10, 32) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		*t = Time(v + va) | ||||
|  | ||||
| 	default: | ||||
| 		return fmt.Errorf("invalid time %q", string(b)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Duration wraps time.Duration. It is used to parse the custom duration format | ||||
| // from YAML. | ||||
| // This type should not propagate beyond the scope of input/output processing. | ||||
| type Duration time.Duration | ||||
|  | ||||
| // Set implements pflag/flag.Value | ||||
| func (d *Duration) Set(s string) error { | ||||
| 	var err error | ||||
| 	*d, err = ParseDuration(s) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // Type implements pflag.Value | ||||
| func (d *Duration) Type() string { | ||||
| 	return "duration" | ||||
| } | ||||
|  | ||||
| var durationRE = regexp.MustCompile("^([0-9]+)(y|w|d|h|m|s|ms)$") | ||||
|  | ||||
| // ParseDuration parses a string into a time.Duration, assuming that a year | ||||
| // always has 365d, a week always has 7d, and a day always has 24h. | ||||
| func ParseDuration(durationStr string) (Duration, error) { | ||||
| 	matches := durationRE.FindStringSubmatch(durationStr) | ||||
| 	if len(matches) != 3 { | ||||
| 		return 0, fmt.Errorf("not a valid duration string: %q", durationStr) | ||||
| 	} | ||||
| 	var ( | ||||
| 		n, _ = strconv.Atoi(matches[1]) | ||||
| 		dur  = time.Duration(n) * time.Millisecond | ||||
| 	) | ||||
| 	switch unit := matches[2]; unit { | ||||
| 	case "y": | ||||
| 		dur *= 1000 * 60 * 60 * 24 * 365 | ||||
| 	case "w": | ||||
| 		dur *= 1000 * 60 * 60 * 24 * 7 | ||||
| 	case "d": | ||||
| 		dur *= 1000 * 60 * 60 * 24 | ||||
| 	case "h": | ||||
| 		dur *= 1000 * 60 * 60 | ||||
| 	case "m": | ||||
| 		dur *= 1000 * 60 | ||||
| 	case "s": | ||||
| 		dur *= 1000 | ||||
| 	case "ms": | ||||
| 		// Value already correct | ||||
| 	default: | ||||
| 		return 0, fmt.Errorf("invalid time unit in duration string: %q", unit) | ||||
| 	} | ||||
| 	return Duration(dur), nil | ||||
| } | ||||
|  | ||||
| func (d Duration) String() string { | ||||
| 	var ( | ||||
| 		ms   = int64(time.Duration(d) / time.Millisecond) | ||||
| 		unit = "ms" | ||||
| 	) | ||||
| 	if ms == 0 { | ||||
| 		return "0s" | ||||
| 	} | ||||
| 	factors := map[string]int64{ | ||||
| 		"y":  1000 * 60 * 60 * 24 * 365, | ||||
| 		"w":  1000 * 60 * 60 * 24 * 7, | ||||
| 		"d":  1000 * 60 * 60 * 24, | ||||
| 		"h":  1000 * 60 * 60, | ||||
| 		"m":  1000 * 60, | ||||
| 		"s":  1000, | ||||
| 		"ms": 1, | ||||
| 	} | ||||
|  | ||||
| 	switch int64(0) { | ||||
| 	case ms % factors["y"]: | ||||
| 		unit = "y" | ||||
| 	case ms % factors["w"]: | ||||
| 		unit = "w" | ||||
| 	case ms % factors["d"]: | ||||
| 		unit = "d" | ||||
| 	case ms % factors["h"]: | ||||
| 		unit = "h" | ||||
| 	case ms % factors["m"]: | ||||
| 		unit = "m" | ||||
| 	case ms % factors["s"]: | ||||
| 		unit = "s" | ||||
| 	} | ||||
| 	return fmt.Sprintf("%v%v", ms/factors[unit], unit) | ||||
| } | ||||
|  | ||||
| // MarshalYAML implements the yaml.Marshaler interface. | ||||
| func (d Duration) MarshalYAML() (interface{}, error) { | ||||
| 	return d.String(), nil | ||||
| } | ||||
|  | ||||
| // UnmarshalYAML implements the yaml.Unmarshaler interface. | ||||
| func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error { | ||||
| 	var s string | ||||
| 	if err := unmarshal(&s); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	dur, err := ParseDuration(s) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*d = dur | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										416
									
								
								vendor/github.com/prometheus/common/model/value.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										416
									
								
								vendor/github.com/prometheus/common/model/value.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,416 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// ZeroSamplePair is the pseudo zero-value of SamplePair used to signal a | ||||
| 	// non-existing sample pair. It is a SamplePair with timestamp Earliest and | ||||
| 	// value 0.0. Note that the natural zero value of SamplePair has a timestamp | ||||
| 	// of 0, which is possible to appear in a real SamplePair and thus not | ||||
| 	// suitable to signal a non-existing SamplePair. | ||||
| 	ZeroSamplePair = SamplePair{Timestamp: Earliest} | ||||
|  | ||||
| 	// ZeroSample is the pseudo zero-value of Sample used to signal a | ||||
| 	// non-existing sample. It is a Sample with timestamp Earliest, value 0.0, | ||||
| 	// and metric nil. Note that the natural zero value of Sample has a timestamp | ||||
| 	// of 0, which is possible to appear in a real Sample and thus not suitable | ||||
| 	// to signal a non-existing Sample. | ||||
| 	ZeroSample = Sample{Timestamp: Earliest} | ||||
| ) | ||||
|  | ||||
| // A SampleValue is a representation of a value for a given sample at a given | ||||
| // time. | ||||
| type SampleValue float64 | ||||
|  | ||||
| // MarshalJSON implements json.Marshaler. | ||||
| func (v SampleValue) MarshalJSON() ([]byte, error) { | ||||
| 	return json.Marshal(v.String()) | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON implements json.Unmarshaler. | ||||
| func (v *SampleValue) UnmarshalJSON(b []byte) error { | ||||
| 	if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { | ||||
| 		return fmt.Errorf("sample value must be a quoted string") | ||||
| 	} | ||||
| 	f, err := strconv.ParseFloat(string(b[1:len(b)-1]), 64) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*v = SampleValue(f) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Equal returns true if the value of v and o is equal or if both are NaN. Note | ||||
| // that v==o is false if both are NaN. If you want the conventional float | ||||
| // behavior, use == to compare two SampleValues. | ||||
| func (v SampleValue) Equal(o SampleValue) bool { | ||||
| 	if v == o { | ||||
| 		return true | ||||
| 	} | ||||
| 	return math.IsNaN(float64(v)) && math.IsNaN(float64(o)) | ||||
| } | ||||
|  | ||||
| func (v SampleValue) String() string { | ||||
| 	return strconv.FormatFloat(float64(v), 'f', -1, 64) | ||||
| } | ||||
|  | ||||
| // SamplePair pairs a SampleValue with a Timestamp. | ||||
| type SamplePair struct { | ||||
| 	Timestamp Time | ||||
| 	Value     SampleValue | ||||
| } | ||||
|  | ||||
| // MarshalJSON implements json.Marshaler. | ||||
| func (s SamplePair) MarshalJSON() ([]byte, error) { | ||||
| 	t, err := json.Marshal(s.Timestamp) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	v, err := json.Marshal(s.Value) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON implements json.Unmarshaler. | ||||
| func (s *SamplePair) UnmarshalJSON(b []byte) error { | ||||
| 	v := [...]json.Unmarshaler{&s.Timestamp, &s.Value} | ||||
| 	return json.Unmarshal(b, &v) | ||||
| } | ||||
|  | ||||
| // Equal returns true if this SamplePair and o have equal Values and equal | ||||
| // Timestamps. The semantics of Value equality is defined by SampleValue.Equal. | ||||
| func (s *SamplePair) Equal(o *SamplePair) bool { | ||||
| 	return s == o || (s.Value.Equal(o.Value) && s.Timestamp.Equal(o.Timestamp)) | ||||
| } | ||||
|  | ||||
| func (s SamplePair) String() string { | ||||
| 	return fmt.Sprintf("%s @[%s]", s.Value, s.Timestamp) | ||||
| } | ||||
|  | ||||
| // Sample is a sample pair associated with a metric. | ||||
| type Sample struct { | ||||
| 	Metric    Metric      `json:"metric"` | ||||
| 	Value     SampleValue `json:"value"` | ||||
| 	Timestamp Time        `json:"timestamp"` | ||||
| } | ||||
|  | ||||
| // Equal compares first the metrics, then the timestamp, then the value. The | ||||
| // semantics of value equality is defined by SampleValue.Equal. | ||||
| func (s *Sample) Equal(o *Sample) bool { | ||||
| 	if s == o { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	if !s.Metric.Equal(o.Metric) { | ||||
| 		return false | ||||
| 	} | ||||
| 	if !s.Timestamp.Equal(o.Timestamp) { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	return s.Value.Equal(o.Value) | ||||
| } | ||||
|  | ||||
| func (s Sample) String() string { | ||||
| 	return fmt.Sprintf("%s => %s", s.Metric, SamplePair{ | ||||
| 		Timestamp: s.Timestamp, | ||||
| 		Value:     s.Value, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // MarshalJSON implements json.Marshaler. | ||||
| func (s Sample) MarshalJSON() ([]byte, error) { | ||||
| 	v := struct { | ||||
| 		Metric Metric     `json:"metric"` | ||||
| 		Value  SamplePair `json:"value"` | ||||
| 	}{ | ||||
| 		Metric: s.Metric, | ||||
| 		Value: SamplePair{ | ||||
| 			Timestamp: s.Timestamp, | ||||
| 			Value:     s.Value, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	return json.Marshal(&v) | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON implements json.Unmarshaler. | ||||
| func (s *Sample) UnmarshalJSON(b []byte) error { | ||||
| 	v := struct { | ||||
| 		Metric Metric     `json:"metric"` | ||||
| 		Value  SamplePair `json:"value"` | ||||
| 	}{ | ||||
| 		Metric: s.Metric, | ||||
| 		Value: SamplePair{ | ||||
| 			Timestamp: s.Timestamp, | ||||
| 			Value:     s.Value, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	if err := json.Unmarshal(b, &v); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	s.Metric = v.Metric | ||||
| 	s.Timestamp = v.Value.Timestamp | ||||
| 	s.Value = v.Value.Value | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Samples is a sortable Sample slice. It implements sort.Interface. | ||||
| type Samples []*Sample | ||||
|  | ||||
| func (s Samples) Len() int { | ||||
| 	return len(s) | ||||
| } | ||||
|  | ||||
| // Less compares first the metrics, then the timestamp. | ||||
| func (s Samples) Less(i, j int) bool { | ||||
| 	switch { | ||||
| 	case s[i].Metric.Before(s[j].Metric): | ||||
| 		return true | ||||
| 	case s[j].Metric.Before(s[i].Metric): | ||||
| 		return false | ||||
| 	case s[i].Timestamp.Before(s[j].Timestamp): | ||||
| 		return true | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s Samples) Swap(i, j int) { | ||||
| 	s[i], s[j] = s[j], s[i] | ||||
| } | ||||
|  | ||||
| // Equal compares two sets of samples and returns true if they are equal. | ||||
| func (s Samples) Equal(o Samples) bool { | ||||
| 	if len(s) != len(o) { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	for i, sample := range s { | ||||
| 		if !sample.Equal(o[i]) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // SampleStream is a stream of Values belonging to an attached COWMetric. | ||||
| type SampleStream struct { | ||||
| 	Metric Metric       `json:"metric"` | ||||
| 	Values []SamplePair `json:"values"` | ||||
| } | ||||
|  | ||||
| func (ss SampleStream) String() string { | ||||
| 	vals := make([]string, len(ss.Values)) | ||||
| 	for i, v := range ss.Values { | ||||
| 		vals[i] = v.String() | ||||
| 	} | ||||
| 	return fmt.Sprintf("%s =>\n%s", ss.Metric, strings.Join(vals, "\n")) | ||||
| } | ||||
|  | ||||
| // Value is a generic interface for values resulting from a query evaluation. | ||||
| type Value interface { | ||||
| 	Type() ValueType | ||||
| 	String() string | ||||
| } | ||||
|  | ||||
| func (Matrix) Type() ValueType  { return ValMatrix } | ||||
| func (Vector) Type() ValueType  { return ValVector } | ||||
| func (*Scalar) Type() ValueType { return ValScalar } | ||||
| func (*String) Type() ValueType { return ValString } | ||||
|  | ||||
| type ValueType int | ||||
|  | ||||
| const ( | ||||
| 	ValNone ValueType = iota | ||||
| 	ValScalar | ||||
| 	ValVector | ||||
| 	ValMatrix | ||||
| 	ValString | ||||
| ) | ||||
|  | ||||
| // MarshalJSON implements json.Marshaler. | ||||
| func (et ValueType) MarshalJSON() ([]byte, error) { | ||||
| 	return json.Marshal(et.String()) | ||||
| } | ||||
|  | ||||
| func (et *ValueType) UnmarshalJSON(b []byte) error { | ||||
| 	var s string | ||||
| 	if err := json.Unmarshal(b, &s); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	switch s { | ||||
| 	case "<ValNone>": | ||||
| 		*et = ValNone | ||||
| 	case "scalar": | ||||
| 		*et = ValScalar | ||||
| 	case "vector": | ||||
| 		*et = ValVector | ||||
| 	case "matrix": | ||||
| 		*et = ValMatrix | ||||
| 	case "string": | ||||
| 		*et = ValString | ||||
| 	default: | ||||
| 		return fmt.Errorf("unknown value type %q", s) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (e ValueType) String() string { | ||||
| 	switch e { | ||||
| 	case ValNone: | ||||
| 		return "<ValNone>" | ||||
| 	case ValScalar: | ||||
| 		return "scalar" | ||||
| 	case ValVector: | ||||
| 		return "vector" | ||||
| 	case ValMatrix: | ||||
| 		return "matrix" | ||||
| 	case ValString: | ||||
| 		return "string" | ||||
| 	} | ||||
| 	panic("ValueType.String: unhandled value type") | ||||
| } | ||||
|  | ||||
| // Scalar is a scalar value evaluated at the set timestamp. | ||||
| type Scalar struct { | ||||
| 	Value     SampleValue `json:"value"` | ||||
| 	Timestamp Time        `json:"timestamp"` | ||||
| } | ||||
|  | ||||
| func (s Scalar) String() string { | ||||
| 	return fmt.Sprintf("scalar: %v @[%v]", s.Value, s.Timestamp) | ||||
| } | ||||
|  | ||||
| // MarshalJSON implements json.Marshaler. | ||||
| func (s Scalar) MarshalJSON() ([]byte, error) { | ||||
| 	v := strconv.FormatFloat(float64(s.Value), 'f', -1, 64) | ||||
| 	return json.Marshal([...]interface{}{s.Timestamp, string(v)}) | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON implements json.Unmarshaler. | ||||
| func (s *Scalar) UnmarshalJSON(b []byte) error { | ||||
| 	var f string | ||||
| 	v := [...]interface{}{&s.Timestamp, &f} | ||||
|  | ||||
| 	if err := json.Unmarshal(b, &v); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	value, err := strconv.ParseFloat(f, 64) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("error parsing sample value: %s", err) | ||||
| 	} | ||||
| 	s.Value = SampleValue(value) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // String is a string value evaluated at the set timestamp. | ||||
| type String struct { | ||||
| 	Value     string `json:"value"` | ||||
| 	Timestamp Time   `json:"timestamp"` | ||||
| } | ||||
|  | ||||
| func (s *String) String() string { | ||||
| 	return s.Value | ||||
| } | ||||
|  | ||||
| // MarshalJSON implements json.Marshaler. | ||||
| func (s String) MarshalJSON() ([]byte, error) { | ||||
| 	return json.Marshal([]interface{}{s.Timestamp, s.Value}) | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON implements json.Unmarshaler. | ||||
| func (s *String) UnmarshalJSON(b []byte) error { | ||||
| 	v := [...]interface{}{&s.Timestamp, &s.Value} | ||||
| 	return json.Unmarshal(b, &v) | ||||
| } | ||||
|  | ||||
| // Vector is basically only an alias for Samples, but the | ||||
| // contract is that in a Vector, all Samples have the same timestamp. | ||||
| type Vector []*Sample | ||||
|  | ||||
| func (vec Vector) String() string { | ||||
| 	entries := make([]string, len(vec)) | ||||
| 	for i, s := range vec { | ||||
| 		entries[i] = s.String() | ||||
| 	} | ||||
| 	return strings.Join(entries, "\n") | ||||
| } | ||||
|  | ||||
| func (vec Vector) Len() int      { return len(vec) } | ||||
| func (vec Vector) Swap(i, j int) { vec[i], vec[j] = vec[j], vec[i] } | ||||
|  | ||||
| // Less compares first the metrics, then the timestamp. | ||||
| func (vec Vector) Less(i, j int) bool { | ||||
| 	switch { | ||||
| 	case vec[i].Metric.Before(vec[j].Metric): | ||||
| 		return true | ||||
| 	case vec[j].Metric.Before(vec[i].Metric): | ||||
| 		return false | ||||
| 	case vec[i].Timestamp.Before(vec[j].Timestamp): | ||||
| 		return true | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Equal compares two sets of samples and returns true if they are equal. | ||||
| func (vec Vector) Equal(o Vector) bool { | ||||
| 	if len(vec) != len(o) { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	for i, sample := range vec { | ||||
| 		if !sample.Equal(o[i]) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // Matrix is a list of time series. | ||||
| type Matrix []*SampleStream | ||||
|  | ||||
| func (m Matrix) Len() int           { return len(m) } | ||||
| func (m Matrix) Less(i, j int) bool { return m[i].Metric.Before(m[j].Metric) } | ||||
| func (m Matrix) Swap(i, j int)      { m[i], m[j] = m[j], m[i] } | ||||
|  | ||||
| func (mat Matrix) String() string { | ||||
| 	matCp := make(Matrix, len(mat)) | ||||
| 	copy(matCp, mat) | ||||
| 	sort.Sort(matCp) | ||||
|  | ||||
| 	strs := make([]string, len(matCp)) | ||||
|  | ||||
| 	for i, ss := range matCp { | ||||
| 		strs[i] = ss.String() | ||||
| 	} | ||||
|  | ||||
| 	return strings.Join(strs, "\n") | ||||
| } | ||||
							
								
								
									
										1
									
								
								vendor/github.com/prometheus/procfs/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/prometheus/procfs/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| /fixtures/ | ||||
							
								
								
									
										18
									
								
								vendor/github.com/prometheus/procfs/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/prometheus/procfs/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 `@...`) the maintainer of this repository (see | ||||
|   [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. | ||||
|  | ||||
| * If you plan to do something more involved, first discuss your ideas | ||||
|   on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). | ||||
|   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/procfs/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								vendor/github.com/prometheus/procfs/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. | ||||
							
								
								
									
										1
									
								
								vendor/github.com/prometheus/procfs/MAINTAINERS.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/prometheus/procfs/MAINTAINERS.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| * Tobias Schmidt <tobidt@gmail.com> | ||||
							
								
								
									
										30
									
								
								vendor/github.com/prometheus/procfs/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								vendor/github.com/prometheus/procfs/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| # Copyright 2018 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. | ||||
|  | ||||
| include Makefile.common | ||||
|  | ||||
| %/.unpacked: %.ttar | ||||
| 	./ttar -C $(dir $*) -x -f $*.ttar | ||||
| 	touch $@ | ||||
|  | ||||
| update_fixtures: fixtures.ttar sysfs/fixtures.ttar | ||||
|  | ||||
| %fixtures.ttar: %/fixtures | ||||
| 	rm -v $(dir $*)fixtures/.unpacked | ||||
| 	./ttar -C $(dir $*) -c -f $*fixtures.ttar fixtures/ | ||||
|  | ||||
| .PHONY: build | ||||
| build: | ||||
|  | ||||
| .PHONY: test | ||||
| test: fixtures/.unpacked sysfs/fixtures/.unpacked common-test | ||||
							
								
								
									
										223
									
								
								vendor/github.com/prometheus/procfs/Makefile.common
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								vendor/github.com/prometheus/procfs/Makefile.common
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,223 @@ | ||||
| # Copyright 2018 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 common Makefile that includes rules to be reused in different prometheus projects. | ||||
| # !!! Open PRs only against the prometheus/prometheus/Makefile.common repository! | ||||
|  | ||||
| # Example usage : | ||||
| # Create the main Makefile in the root project directory. | ||||
| # include Makefile.common | ||||
| # customTarget: | ||||
| # 	@echo ">> Running customTarget" | ||||
| # | ||||
|  | ||||
| # Ensure GOBIN is not set during build so that promu is installed to the correct path | ||||
| unexport GOBIN | ||||
|  | ||||
| GO           ?= go | ||||
| GOFMT        ?= $(GO)fmt | ||||
| FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) | ||||
| GOOPTS       ?= | ||||
|  | ||||
| GO_VERSION        ?= $(shell $(GO) version) | ||||
| GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) | ||||
| PRE_GO_111        ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') | ||||
|  | ||||
| unexport GOVENDOR | ||||
| ifeq (, $(PRE_GO_111)) | ||||
| 	ifneq (,$(wildcard go.mod)) | ||||
| 		# Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). | ||||
| 		GO111MODULE := on | ||||
|  | ||||
| 		ifneq (,$(wildcard vendor)) | ||||
| 			# Always use the local vendor/ directory to satisfy the dependencies. | ||||
| 			GOOPTS := $(GOOPTS) -mod=vendor | ||||
| 		endif | ||||
| 	endif | ||||
| else | ||||
| 	ifneq (,$(wildcard go.mod)) | ||||
| 		ifneq (,$(wildcard vendor)) | ||||
| $(warning This repository requires Go >= 1.11 because of Go modules) | ||||
| $(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)') | ||||
| 		endif | ||||
| 	else | ||||
| 		# This repository isn't using Go modules (yet). | ||||
| 		GOVENDOR := $(FIRST_GOPATH)/bin/govendor | ||||
| 	endif | ||||
|  | ||||
| 	unexport GO111MODULE | ||||
| endif | ||||
| PROMU        := $(FIRST_GOPATH)/bin/promu | ||||
| STATICCHECK  := $(FIRST_GOPATH)/bin/staticcheck | ||||
| pkgs          = ./... | ||||
|  | ||||
| GO_VERSION        ?= $(shell $(GO) version) | ||||
| GO_BUILD_PLATFORM ?= $(subst /,-,$(lastword $(GO_VERSION))) | ||||
|  | ||||
| PROMU_VERSION ?= 0.2.0 | ||||
| PROMU_URL     := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz | ||||
|  | ||||
| PREFIX                  ?= $(shell pwd) | ||||
| BIN_DIR                 ?= $(shell pwd) | ||||
| DOCKER_IMAGE_TAG        ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) | ||||
| DOCKER_REPO             ?= prom | ||||
|  | ||||
| .PHONY: all | ||||
| all: precheck style staticcheck unused build test | ||||
|  | ||||
| # This rule is used to forward a target like "build" to "common-build".  This | ||||
| # allows a new "build" target to be defined in a Makefile which includes this | ||||
| # one and override "common-build" without override warnings. | ||||
| %: common-% ; | ||||
|  | ||||
| .PHONY: common-style | ||||
| common-style: | ||||
| 	@echo ">> checking code style" | ||||
| 	@fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \ | ||||
| 	if [ -n "$${fmtRes}" ]; then \ | ||||
| 		echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \ | ||||
| 		echo "Please ensure you are using $$($(GO) version) for formatting code."; \ | ||||
| 		exit 1; \ | ||||
| 	fi | ||||
|  | ||||
| .PHONY: common-check_license | ||||
| common-check_license: | ||||
| 	@echo ">> checking license header" | ||||
| 	@licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \ | ||||
|                awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \ | ||||
|        done); \ | ||||
|        if [ -n "$${licRes}" ]; then \ | ||||
|                echo "license header checking failed:"; echo "$${licRes}"; \ | ||||
|                exit 1; \ | ||||
|        fi | ||||
|  | ||||
| .PHONY: common-test-short | ||||
| common-test-short: | ||||
| 	@echo ">> running short tests" | ||||
| 	GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs) | ||||
|  | ||||
| .PHONY: common-test | ||||
| common-test: | ||||
| 	@echo ">> running all tests" | ||||
| 	GO111MODULE=$(GO111MODULE) $(GO) test -race $(GOOPTS) $(pkgs) | ||||
|  | ||||
| .PHONY: common-format | ||||
| common-format: | ||||
| 	@echo ">> formatting code" | ||||
| 	GO111MODULE=$(GO111MODULE) $(GO) fmt $(GOOPTS) $(pkgs) | ||||
|  | ||||
| .PHONY: common-vet | ||||
| common-vet: | ||||
| 	@echo ">> vetting code" | ||||
| 	GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) | ||||
|  | ||||
| .PHONY: common-staticcheck | ||||
| common-staticcheck: $(STATICCHECK) | ||||
| 	@echo ">> running staticcheck" | ||||
| ifdef GO111MODULE | ||||
| 	GO111MODULE=$(GO111MODULE) $(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" -checks "SA*" $(pkgs) | ||||
| else | ||||
| 	$(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs) | ||||
| endif | ||||
|  | ||||
| .PHONY: common-unused | ||||
| common-unused: $(GOVENDOR) | ||||
| ifdef GOVENDOR | ||||
| 	@echo ">> running check for unused packages" | ||||
| 	@$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages' | ||||
| else | ||||
| ifdef GO111MODULE | ||||
| 	@echo ">> running check for unused/missing packages in go.mod" | ||||
| 	GO111MODULE=$(GO111MODULE) $(GO) mod tidy | ||||
| 	@git diff --exit-code -- go.sum go.mod | ||||
| ifneq (,$(wildcard vendor)) | ||||
| 	@echo ">> running check for unused packages in vendor/" | ||||
| 	GO111MODULE=$(GO111MODULE) $(GO) mod vendor | ||||
| 	@git diff --exit-code -- go.sum go.mod vendor/ | ||||
| endif | ||||
| endif | ||||
| endif | ||||
|  | ||||
| .PHONY: common-build | ||||
| common-build: promu | ||||
| 	@echo ">> building binaries" | ||||
| 	GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) | ||||
|  | ||||
| .PHONY: common-tarball | ||||
| common-tarball: promu | ||||
| 	@echo ">> building release tarball" | ||||
| 	$(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) | ||||
|  | ||||
| .PHONY: common-docker | ||||
| common-docker: | ||||
| 	docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" . | ||||
|  | ||||
| .PHONY: common-docker-publish | ||||
| common-docker-publish: | ||||
| 	docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)" | ||||
|  | ||||
| .PHONY: common-docker-tag-latest | ||||
| common-docker-tag-latest: | ||||
| 	docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):latest" | ||||
|  | ||||
| .PHONY: promu | ||||
| promu: $(PROMU) | ||||
|  | ||||
| $(PROMU): | ||||
| 	curl -s -L $(PROMU_URL) | tar -xvz -C /tmp | ||||
| 	mkdir -v -p $(FIRST_GOPATH)/bin | ||||
| 	cp -v /tmp/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(PROMU) | ||||
|  | ||||
| .PHONY: proto | ||||
| proto: | ||||
| 	@echo ">> generating code from proto files" | ||||
| 	@./scripts/genproto.sh | ||||
|  | ||||
| .PHONY: $(STATICCHECK) | ||||
| $(STATICCHECK): | ||||
| ifdef GO111MODULE | ||||
| # Get staticcheck from a temporary directory to avoid modifying the local go.{mod,sum}. | ||||
| # See https://github.com/golang/go/issues/27643. | ||||
| # For now, we are using the next branch of staticcheck because master isn't compatible yet with Go modules. | ||||
| 	tmpModule=$$(mktemp -d 2>&1) && \ | ||||
| 	mkdir -p $${tmpModule}/staticcheck && \ | ||||
| 	cd "$${tmpModule}"/staticcheck && \ | ||||
| 	GO111MODULE=on $(GO) mod init example.com/staticcheck && \ | ||||
| 	GO111MODULE=on GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck@next && \ | ||||
| 	rm -rf $${tmpModule}; | ||||
| else | ||||
| 	GOOS= GOARCH= GO111MODULE=off $(GO) get -u honnef.co/go/tools/cmd/staticcheck | ||||
| endif | ||||
|  | ||||
| ifdef GOVENDOR | ||||
| .PHONY: $(GOVENDOR) | ||||
| $(GOVENDOR): | ||||
| 	GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor | ||||
| endif | ||||
|  | ||||
| .PHONY: precheck | ||||
| precheck:: | ||||
|  | ||||
| define PRECHECK_COMMAND_template = | ||||
| precheck:: $(1)_precheck | ||||
|  | ||||
|  | ||||
| PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1))) | ||||
| .PHONY: $(1)_precheck | ||||
| $(1)_precheck: | ||||
| 	@if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \ | ||||
| 		echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \ | ||||
| 		exit 1; \ | ||||
| 	fi | ||||
| endef | ||||
							
								
								
									
										7
									
								
								vendor/github.com/prometheus/procfs/NOTICE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/prometheus/procfs/NOTICE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| procfs provides functions to retrieve system, kernel and process | ||||
| metrics from the pseudo-filesystem proc. | ||||
|  | ||||
| Copyright 2014-2015 The Prometheus Authors | ||||
|  | ||||
| This product includes software developed at | ||||
| SoundCloud Ltd. (http://soundcloud.com/). | ||||
							
								
								
									
										11
									
								
								vendor/github.com/prometheus/procfs/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/prometheus/procfs/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| # procfs | ||||
|  | ||||
| This procfs package provides functions to retrieve system, kernel and process | ||||
| metrics from the pseudo-filesystem proc. | ||||
|  | ||||
| *WARNING*: This package is a work in progress. Its API may still break in | ||||
| backwards-incompatible ways without warnings. Use it at your own risk. | ||||
|  | ||||
| [](https://godoc.org/github.com/prometheus/procfs) | ||||
| [](https://travis-ci.org/prometheus/procfs) | ||||
| [](https://goreportcard.com/report/github.com/prometheus/procfs) | ||||
							
								
								
									
										95
									
								
								vendor/github.com/prometheus/procfs/buddyinfo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								vendor/github.com/prometheus/procfs/buddyinfo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package procfs | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // A BuddyInfo is the details parsed from /proc/buddyinfo. | ||||
| // The data is comprised of an array of free fragments of each size. | ||||
| // The sizes are 2^n*PAGE_SIZE, where n is the array index. | ||||
| type BuddyInfo struct { | ||||
| 	Node  string | ||||
| 	Zone  string | ||||
| 	Sizes []float64 | ||||
| } | ||||
|  | ||||
| // NewBuddyInfo reads the buddyinfo statistics. | ||||
| func NewBuddyInfo() ([]BuddyInfo, error) { | ||||
| 	fs, err := NewFS(DefaultMountPoint) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return fs.NewBuddyInfo() | ||||
| } | ||||
|  | ||||
| // NewBuddyInfo reads the buddyinfo statistics from the specified `proc` filesystem. | ||||
| func (fs FS) NewBuddyInfo() ([]BuddyInfo, error) { | ||||
| 	file, err := os.Open(fs.Path("buddyinfo")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer file.Close() | ||||
|  | ||||
| 	return parseBuddyInfo(file) | ||||
| } | ||||
|  | ||||
| func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) { | ||||
| 	var ( | ||||
| 		buddyInfo   = []BuddyInfo{} | ||||
| 		scanner     = bufio.NewScanner(r) | ||||
| 		bucketCount = -1 | ||||
| 	) | ||||
|  | ||||
| 	for scanner.Scan() { | ||||
| 		var err error | ||||
| 		line := scanner.Text() | ||||
| 		parts := strings.Fields(line) | ||||
|  | ||||
| 		if len(parts) < 4 { | ||||
| 			return nil, fmt.Errorf("invalid number of fields when parsing buddyinfo") | ||||
| 		} | ||||
|  | ||||
| 		node := strings.TrimRight(parts[1], ",") | ||||
| 		zone := strings.TrimRight(parts[3], ",") | ||||
| 		arraySize := len(parts[4:]) | ||||
|  | ||||
| 		if bucketCount == -1 { | ||||
| 			bucketCount = arraySize | ||||
| 		} else { | ||||
| 			if bucketCount != arraySize { | ||||
| 				return nil, fmt.Errorf("mismatch in number of buddyinfo buckets, previous count %d, new count %d", bucketCount, arraySize) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		sizes := make([]float64, arraySize) | ||||
| 		for i := 0; i < arraySize; i++ { | ||||
| 			sizes[i], err = strconv.ParseFloat(parts[i+4], 64) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("invalid value in buddyinfo: %s", err) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		buddyInfo = append(buddyInfo, BuddyInfo{node, zone, sizes}) | ||||
| 	} | ||||
|  | ||||
| 	return buddyInfo, scanner.Err() | ||||
| } | ||||
							
								
								
									
										45
									
								
								vendor/github.com/prometheus/procfs/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/prometheus/procfs/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| // Copyright 2014 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. | ||||
|  | ||||
| // Package procfs provides functions to retrieve system, kernel and process | ||||
| // metrics from the pseudo-filesystem proc. | ||||
| // | ||||
| // Example: | ||||
| // | ||||
| //    package main | ||||
| // | ||||
| //    import ( | ||||
| //    	"fmt" | ||||
| //    	"log" | ||||
| // | ||||
| //    	"github.com/prometheus/procfs" | ||||
| //    ) | ||||
| // | ||||
| //    func main() { | ||||
| //    	p, err := procfs.Self() | ||||
| //    	if err != nil { | ||||
| //    		log.Fatalf("could not get process: %s", err) | ||||
| //    	} | ||||
| // | ||||
| //    	stat, err := p.NewStat() | ||||
| //    	if err != nil { | ||||
| //    		log.Fatalf("could not get process stat: %s", err) | ||||
| //    	} | ||||
| // | ||||
| //    	fmt.Printf("command:  %s\n", stat.Comm) | ||||
| //    	fmt.Printf("cpu time: %fs\n", stat.CPUTime()) | ||||
| //    	fmt.Printf("vsize:    %dB\n", stat.VirtualMemory()) | ||||
| //    	fmt.Printf("rss:      %dB\n", stat.ResidentMemory()) | ||||
| //    } | ||||
| // | ||||
| package procfs | ||||
							
								
								
									
										462
									
								
								vendor/github.com/prometheus/procfs/fixtures.ttar
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										462
									
								
								vendor/github.com/prometheus/procfs/fixtures.ttar
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,462 @@ | ||||
| # Archive created by ttar -c -f fixtures.ttar fixtures/ | ||||
| Directory: fixtures | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/26231 | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/cmdline | ||||
| Lines: 1 | ||||
| vimNULLBYTEtest.goNULLBYTE+10NULLBYTEEOF | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/comm | ||||
| Lines: 1 | ||||
| vim | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/cwd | ||||
| SymlinkTo: /usr/bin | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/exe | ||||
| SymlinkTo: /usr/bin/vim | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/26231/fd | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/fd/0 | ||||
| SymlinkTo: ../../symlinktargets/abc | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/fd/1 | ||||
| SymlinkTo: ../../symlinktargets/def | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/fd/10 | ||||
| SymlinkTo: ../../symlinktargets/xyz | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/fd/2 | ||||
| SymlinkTo: ../../symlinktargets/ghi | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/fd/3 | ||||
| SymlinkTo: ../../symlinktargets/uvw | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/io | ||||
| Lines: 7 | ||||
| rchar: 750339 | ||||
| wchar: 818609 | ||||
| syscr: 7405 | ||||
| syscw: 5245 | ||||
| read_bytes: 1024 | ||||
| write_bytes: 2048 | ||||
| cancelled_write_bytes: -1024 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/limits | ||||
| Lines: 17 | ||||
| Limit                     Soft Limit           Hard Limit           Units | ||||
| Max cpu time              unlimited            unlimited            seconds | ||||
| Max file size             unlimited            unlimited            bytes | ||||
| Max data size             unlimited            unlimited            bytes | ||||
| Max stack size            8388608              unlimited            bytes | ||||
| Max core file size        0                    unlimited            bytes | ||||
| Max resident set          unlimited            unlimited            bytes | ||||
| Max processes             62898                62898                processes | ||||
| Max open files            2048                 4096                 files | ||||
| Max locked memory         65536                65536                bytes | ||||
| Max address space         8589934592           unlimited            bytes | ||||
| Max file locks            unlimited            unlimited            locks | ||||
| Max pending signals       62898                62898                signals | ||||
| Max msgqueue size         819200               819200               bytes | ||||
| Max nice priority         0                    0 | ||||
| Max realtime priority     0                    0 | ||||
| Max realtime timeout      unlimited            unlimited            us | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/mountstats | ||||
| Lines: 19 | ||||
| device rootfs mounted on / with fstype rootfs | ||||
| device sysfs mounted on /sys with fstype sysfs | ||||
| device proc mounted on /proc with fstype proc | ||||
| device /dev/sda1 mounted on / with fstype ext4 | ||||
| device 192.168.1.1:/srv/test mounted on /mnt/nfs/test with fstype nfs4 statvers=1.1 | ||||
| 	opts:	rw,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,acregmin=3,acregmax=60,acdirmin=30,acdirmax=60,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.1.5,local_lock=none | ||||
| 	age:	13968 | ||||
| 	caps:	caps=0xfff7,wtmult=512,dtsize=32768,bsize=0,namlen=255 | ||||
| 	nfsv4:	bm0=0xfdffafff,bm1=0xf9be3e,bm2=0x0,acl=0x0,pnfs=not configured | ||||
| 	sec:	flavor=1,pseudoflavor=1 | ||||
| 	events:	52 226 0 0 1 13 398 0 0 331 0 47 0 0 77 0 0 77 0 0 0 0 0 0 0 0 0 | ||||
| 	bytes:	1207640230 0 0 0 1210214218 0 295483 0 | ||||
| 	RPC iostats version: 1.0  p/v: 100003/4 (nfs) | ||||
| 	xprt:	tcp 832 0 1 0 11 6428 6428 0 12154 0 24 26 5726 | ||||
| 	per-op statistics | ||||
| 	        NULL: 0 0 0 0 0 0 0 0 | ||||
| 	        READ: 1298 1298 0 207680 1210292152 6 79386 79407 | ||||
| 	       WRITE: 0 0 0 0 0 0 0 0 | ||||
|  | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/26231/net | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/net/dev | ||||
| Lines: 4 | ||||
| Inter-|   Receive                                                |  Transmit | ||||
|  face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed | ||||
|     lo:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0 | ||||
|   eth0:     438       5    0    0    0     0          0         0      648       8    0    0    0     0       0          0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/26231/ns | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/ns/mnt | ||||
| SymlinkTo: mnt:[4026531840] | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/ns/net | ||||
| SymlinkTo: net:[4026531993] | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/root | ||||
| SymlinkTo: / | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26231/stat | ||||
| Lines: 1 | ||||
| 26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/26232 | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26232/cmdline | ||||
| Lines: 0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26232/comm | ||||
| Lines: 1 | ||||
| ata_sff | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26232/cwd | ||||
| SymlinkTo: /does/not/exist | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/26232/fd | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26232/fd/0 | ||||
| SymlinkTo: ../../symlinktargets/abc | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26232/fd/1 | ||||
| SymlinkTo: ../../symlinktargets/def | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26232/fd/2 | ||||
| SymlinkTo: ../../symlinktargets/ghi | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26232/fd/3 | ||||
| SymlinkTo: ../../symlinktargets/uvw | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26232/fd/4 | ||||
| SymlinkTo: ../../symlinktargets/xyz | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26232/limits | ||||
| Lines: 17 | ||||
| Limit                     Soft Limit           Hard Limit           Units      | ||||
| Max cpu time              unlimited            unlimited            seconds    | ||||
| Max file size             unlimited            unlimited            bytes      | ||||
| Max data size             unlimited            unlimited            bytes      | ||||
| Max stack size            8388608              unlimited            bytes      | ||||
| Max core file size        0                    unlimited            bytes      | ||||
| Max resident set          unlimited            unlimited            bytes      | ||||
| Max processes             29436                29436                processes  | ||||
| Max open files            1024                 4096                 files      | ||||
| Max locked memory         65536                65536                bytes      | ||||
| Max address space         unlimited            unlimited            bytes      | ||||
| Max file locks            unlimited            unlimited            locks      | ||||
| Max pending signals       29436                29436                signals    | ||||
| Max msgqueue size         819200               819200               bytes      | ||||
| Max nice priority         0                    0                     | ||||
| Max realtime priority     0                    0                     | ||||
| Max realtime timeout      unlimited            unlimited            us         | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26232/root | ||||
| SymlinkTo: /does/not/exist | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26232/stat | ||||
| Lines: 1 | ||||
| 33 (ata_sff) S 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 5 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 18446744073709551615 0 0 17 1 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/26233 | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/26233/cmdline | ||||
| Lines: 1 | ||||
| com.github.uiautomatorNULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTENULLBYTEEOF | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/584 | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/584/stat | ||||
| Lines: 2 | ||||
| 1020 ((a b ) ( c d) ) R 28378 1020 28378 34842 1020 4218880 286 0 0 0 0 0 0 0 20 0 1 0 10839175 10395648 155 18446744073709551615 4194304 4238788 140736466511168 140736466511168 140609271124624 0 0 0 0 0 0 0 17 5 0 0 0 0 0 6336016 6337300 25579520 140736466515030 140736466515061 140736466515061 140736466518002 0 | ||||
| #!/bin/cat /proc/self/stat | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/buddyinfo | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/buddyinfo/short | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/buddyinfo/short/buddyinfo | ||||
| Lines: 3 | ||||
| Node 0, zone | ||||
| Node 0, zone | ||||
| Node 0, zone | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/buddyinfo/sizemismatch | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/buddyinfo/sizemismatch/buddyinfo | ||||
| Lines: 3 | ||||
| Node 0, zone      DMA      1      0      1      0      2      1      1      0      1      1      3  | ||||
| Node 0, zone    DMA32    759    572    791    475    194     45     12      0      0      0      0      0 | ||||
| Node 0, zone   Normal   4381   1093    185   1530    567    102      4      0      0      0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/buddyinfo/valid | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/buddyinfo/valid/buddyinfo | ||||
| Lines: 3 | ||||
| Node 0, zone      DMA      1      0      1      0      2      1      1      0      1      1      3  | ||||
| Node 0, zone    DMA32    759    572    791    475    194     45     12      0      0      0      0  | ||||
| Node 0, zone   Normal   4381   1093    185   1530    567    102      4      0      0      0      0  | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/fs | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/fs/xfs | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/fs/xfs/stat | ||||
| Lines: 23 | ||||
| extent_alloc 92447 97589 92448 93751 | ||||
| abt 0 0 0 0 | ||||
| blk_map 1767055 188820 184891 92447 92448 2140766 0 | ||||
| bmbt 0 0 0 0 | ||||
| dir 185039 92447 92444 136422 | ||||
| trans 706 944304 0 | ||||
| ig 185045 58807 0 126238 0 33637 22 | ||||
| log 2883 113448 9 17360 739 | ||||
| push_ail 945014 0 134260 15483 0 3940 464 159985 0 40 | ||||
| xstrat 92447 0 | ||||
| rw 107739 94045 | ||||
| attr 4 0 0 0 | ||||
| icluster 8677 7849 135802 | ||||
| vnodes 92601 0 0 0 92444 92444 92444 0 | ||||
| buf 2666287 7122 2659202 3599 2 7085 0 10297 7085 | ||||
| abtb2 184941 1277345 13257 13278 0 0 0 0 0 0 0 0 0 0 2746147 | ||||
| abtc2 345295 2416764 172637 172658 0 0 0 0 0 0 0 0 0 0 21406023 | ||||
| bmbt2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||||
| ibt2 343004 1358467 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||||
| fibt2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||||
| qm 0 0 0 0 0 0 0 0 | ||||
| xpc 399724544 92823103 86219234 | ||||
| debug 0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/mdstat | ||||
| Lines: 26 | ||||
| Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10] | ||||
| md3 : active raid6 sda1[8] sdh1[7] sdg1[6] sdf1[5] sde1[11] sdd1[3] sdc1[10] sdb1[9] | ||||
|       5853468288 blocks super 1.2 level 6, 64k chunk, algorithm 2 [8/8] [UUUUUUUU] | ||||
|        | ||||
| md127 : active raid1 sdi2[0] sdj2[1] | ||||
|       312319552 blocks [2/2] [UU] | ||||
|        | ||||
| md0 : active raid1 sdk[2](S) sdi1[0] sdj1[1] | ||||
|       248896 blocks [2/2] [UU] | ||||
|        | ||||
| md4 : inactive raid1 sda3[0] sdb3[1] | ||||
|       4883648 blocks [2/2] [UU] | ||||
|  | ||||
| md6 : active raid1 sdb2[2] sda2[0] | ||||
|       195310144 blocks [2/1] [U_] | ||||
|       [=>...................]  recovery =  8.5% (16775552/195310144) finish=17.0min speed=259783K/sec | ||||
|  | ||||
| md8 : active raid1 sdb1[1] sda1[0] | ||||
|       195310144 blocks [2/2] [UU] | ||||
|       [=>...................]  resync =  8.5% (16775552/195310144) finish=17.0min speed=259783K/sec | ||||
|  | ||||
| md7 : active raid6 sdb1[0] sde1[3] sdd1[2] sdc1[1] | ||||
|       7813735424 blocks super 1.2 level 6, 512k chunk, algorithm 2 [4/3] [U_UU] | ||||
|       bitmap: 0/30 pages [0KB], 65536KB chunk | ||||
|  | ||||
| unused devices: <none> | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/net | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/net/dev | ||||
| Lines: 6 | ||||
| Inter-|   Receive                                                |  Transmit | ||||
|  face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed | ||||
| vethf345468:     648       8    0    0    0     0          0         0      438       5    0    0    0     0       0          0 | ||||
|     lo: 1664039048 1566805    0    0    0     0          0         0 1664039048 1566805    0    0    0     0       0          0 | ||||
| docker0:    2568      38    0    0    0     0          0         0      438       5    0    0    0     0       0          0 | ||||
|   eth0: 874354587 1036395    0    0    0     0          0         0 563352563  732147    0    0    0     0       0          0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/net/ip_vs | ||||
| Lines: 21 | ||||
| IP Virtual Server version 1.2.1 (size=4096) | ||||
| Prot LocalAddress:Port Scheduler Flags | ||||
|   -> RemoteAddress:Port Forward Weight ActiveConn InActConn | ||||
| TCP  C0A80016:0CEA wlc | ||||
|   -> C0A85216:0CEA      Tunnel  100    248        2 | ||||
|   -> C0A85318:0CEA      Tunnel  100    248        2 | ||||
|   -> C0A85315:0CEA      Tunnel  100    248        1 | ||||
| TCP  C0A80039:0CEA wlc | ||||
|   -> C0A85416:0CEA      Tunnel  0      0          0 | ||||
|   -> C0A85215:0CEA      Tunnel  100    1499       0 | ||||
|   -> C0A83215:0CEA      Tunnel  100    1498       0 | ||||
| TCP  C0A80037:0CEA wlc | ||||
|   -> C0A8321A:0CEA      Tunnel  0      0          0 | ||||
|   -> C0A83120:0CEA      Tunnel  100    0          0 | ||||
| TCP  [2620:0000:0000:0000:0000:0000:0000:0001]:0050 sh | ||||
|   -> [2620:0000:0000:0000:0000:0000:0000:0002]:0050      Route   1      0          0 | ||||
|   -> [2620:0000:0000:0000:0000:0000:0000:0003]:0050      Route   1      0          0 | ||||
|   -> [2620:0000:0000:0000:0000:0000:0000:0004]:0050      Route   1      1          1 | ||||
| FWM  10001000 wlc | ||||
|   -> C0A8321A:0CEA      Route   0      0          1 | ||||
|   -> C0A83215:0CEA      Route   0      0          2 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/net/ip_vs_stats | ||||
| Lines: 6 | ||||
|    Total Incoming Outgoing         Incoming         Outgoing | ||||
|    Conns  Packets  Packets            Bytes            Bytes | ||||
|  16AA370 E33656E5        0     51D8C8883AB3                0 | ||||
|  | ||||
|  Conns/s   Pkts/s   Pkts/s          Bytes/s          Bytes/s | ||||
|        4    1FB3C        0          1282A8F                0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/net/rpc | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/net/rpc/nfs | ||||
| Lines: 5 | ||||
| net 18628 0 18628 6 | ||||
| rpc 4329785 0 4338291 | ||||
| proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2 | ||||
| proc3 22 1 4084749 29200 94754 32580 186 47747 7981 8639 0 6356 0 6962 0 7958 0 0 241 4 4 2 39 | ||||
| proc4 61 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/net/rpc/nfsd | ||||
| Lines: 11 | ||||
| rc 0 6 18622 | ||||
| fh 0 0 0 0 0 | ||||
| io 157286400 0 | ||||
| th 8 0 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 | ||||
| ra 32 0 0 0 0 0 0 0 0 0 0 0 | ||||
| net 18628 0 18628 6 | ||||
| rpc 18628 0 0 0 0 | ||||
| proc2 18 2 69 0 0 4410 0 0 0 0 0 0 0 0 0 0 0 99 2 | ||||
| proc3 22 2 112 0 2719 111 0 0 0 0 0 0 0 0 0 0 0 27 216 0 2 1 0 | ||||
| proc4 2 2 10853 | ||||
| proc4ops 72 0 0 0 1098 2 0 0 0 0 8179 5896 0 0 0 0 5900 0 0 2 0 2 0 9609 0 2 150 1272 0 0 0 1236 0 0 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/net/xfrm_stat | ||||
| Lines: 28 | ||||
| XfrmInError                     1 | ||||
| XfrmInBufferError               2 | ||||
| XfrmInHdrError                  4 | ||||
| XfrmInNoStates                  3 | ||||
| XfrmInStateProtoError           40 | ||||
| XfrmInStateModeError            100 | ||||
| XfrmInStateSeqError             6000 | ||||
| XfrmInStateExpired              4 | ||||
| XfrmInStateMismatch             23451 | ||||
| XfrmInStateInvalid              55555 | ||||
| XfrmInTmplMismatch              51 | ||||
| XfrmInNoPols                    65432 | ||||
| XfrmInPolBlock                  100 | ||||
| XfrmInPolError                  10000 | ||||
| XfrmOutError                    1000000 | ||||
| XfrmOutBundleGenError           43321 | ||||
| XfrmOutBundleCheckError         555 | ||||
| XfrmOutNoStates                 869 | ||||
| XfrmOutStateProtoError          4542 | ||||
| XfrmOutStateModeError           4 | ||||
| XfrmOutStateSeqError            543 | ||||
| XfrmOutStateExpired             565 | ||||
| XfrmOutPolBlock                 43456 | ||||
| XfrmOutPolDead                  7656 | ||||
| XfrmOutPolError                 1454 | ||||
| XfrmFwdHdrError                 6654 | ||||
| XfrmOutStateInvalid             28765 | ||||
| XfrmAcquireError                24532 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/self | ||||
| SymlinkTo: 26231 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/stat | ||||
| Lines: 16 | ||||
| cpu  301854 612 111922 8979004 3552 2 3944 0 0 0 | ||||
| cpu0 44490 19 21045 1087069 220 1 3410 0 0 0 | ||||
| cpu1 47869 23 16474 1110787 591 0 46 0 0 0 | ||||
| cpu2 46504 36 15916 1112321 441 0 326 0 0 0 | ||||
| cpu3 47054 102 15683 1113230 533 0 60 0 0 0 | ||||
| cpu4 28413 25 10776 1140321 217 0 8 0 0 0 | ||||
| cpu5 29271 101 11586 1136270 672 0 30 0 0 0 | ||||
| cpu6 29152 36 10276 1139721 319 0 29 0 0 0 | ||||
| cpu7 29098 268 10164 1139282 555 0 31 0 0 0 | ||||
| intr 8885917 17 0 0 0 0 0 0 0 1 79281 0 0 0 0 0 0 0 231237 0 0 0 0 250586 103 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 223424 190745 13 906 1283803 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | ||||
| ctxt 38014093 | ||||
| btime 1418183276 | ||||
| processes 26442 | ||||
| procs_running 2 | ||||
| procs_blocked 1 | ||||
| softirq 5057579 250191 1481983 1647 211099 186066 0 1783454 622196 12499 508444 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Directory: fixtures/symlinktargets | ||||
| Mode: 755 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/symlinktargets/README | ||||
| Lines: 2 | ||||
| This directory contains some empty files that are the symlinks the files in the "fd" directory point to. | ||||
| They are otherwise ignored by the tests | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/symlinktargets/abc | ||||
| Lines: 0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/symlinktargets/def | ||||
| Lines: 0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/symlinktargets/ghi | ||||
| Lines: 0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/symlinktargets/uvw | ||||
| Lines: 0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/symlinktargets/xyz | ||||
| Lines: 0 | ||||
| Mode: 644 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
| Path: fixtures/.unpacked | ||||
| Lines: 0 | ||||
| Mode: 664 | ||||
| # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||||
							
								
								
									
										82
									
								
								vendor/github.com/prometheus/procfs/fs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/prometheus/procfs/fs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| // Copyright 2018 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 procfs | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path" | ||||
|  | ||||
| 	"github.com/prometheus/procfs/nfs" | ||||
| 	"github.com/prometheus/procfs/xfs" | ||||
| ) | ||||
|  | ||||
| // FS represents the pseudo-filesystem proc, which provides an interface to | ||||
| // kernel data structures. | ||||
| type FS string | ||||
|  | ||||
| // DefaultMountPoint is the common mount point of the proc filesystem. | ||||
| const DefaultMountPoint = "/proc" | ||||
|  | ||||
| // NewFS returns a new FS mounted under the given mountPoint. It will error | ||||
| // if the mount point can't be read. | ||||
| func NewFS(mountPoint string) (FS, error) { | ||||
| 	info, err := os.Stat(mountPoint) | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("could not read %s: %s", mountPoint, err) | ||||
| 	} | ||||
| 	if !info.IsDir() { | ||||
| 		return "", fmt.Errorf("mount point %s is not a directory", mountPoint) | ||||
| 	} | ||||
|  | ||||
| 	return FS(mountPoint), nil | ||||
| } | ||||
|  | ||||
| // Path returns the path of the given subsystem relative to the procfs root. | ||||
| func (fs FS) Path(p ...string) string { | ||||
| 	return path.Join(append([]string{string(fs)}, p...)...) | ||||
| } | ||||
|  | ||||
| // XFSStats retrieves XFS filesystem runtime statistics. | ||||
| func (fs FS) XFSStats() (*xfs.Stats, error) { | ||||
| 	f, err := os.Open(fs.Path("fs/xfs/stat")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	return xfs.ParseStats(f) | ||||
| } | ||||
|  | ||||
| // NFSClientRPCStats retrieves NFS client RPC statistics. | ||||
| func (fs FS) NFSClientRPCStats() (*nfs.ClientRPCStats, error) { | ||||
| 	f, err := os.Open(fs.Path("net/rpc/nfs")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	return nfs.ParseClientRPCStats(f) | ||||
| } | ||||
|  | ||||
| // NFSdServerRPCStats retrieves NFS daemon RPC statistics. | ||||
| func (fs FS) NFSdServerRPCStats() (*nfs.ServerRPCStats, error) { | ||||
| 	f, err := os.Open(fs.Path("net/rpc/nfsd")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	return nfs.ParseServerRPCStats(f) | ||||
| } | ||||
							
								
								
									
										1
									
								
								vendor/github.com/prometheus/procfs/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/prometheus/procfs/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| module github.com/prometheus/procfs | ||||
							
								
								
									
										59
									
								
								vendor/github.com/prometheus/procfs/internal/util/parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								vendor/github.com/prometheus/procfs/internal/util/parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| // Copyright 2018 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 util | ||||
|  | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // ParseUint32s parses a slice of strings into a slice of uint32s. | ||||
| func ParseUint32s(ss []string) ([]uint32, error) { | ||||
| 	us := make([]uint32, 0, len(ss)) | ||||
| 	for _, s := range ss { | ||||
| 		u, err := strconv.ParseUint(s, 10, 32) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		us = append(us, uint32(u)) | ||||
| 	} | ||||
|  | ||||
| 	return us, nil | ||||
| } | ||||
|  | ||||
| // ParseUint64s parses a slice of strings into a slice of uint64s. | ||||
| func ParseUint64s(ss []string) ([]uint64, error) { | ||||
| 	us := make([]uint64, 0, len(ss)) | ||||
| 	for _, s := range ss { | ||||
| 		u, err := strconv.ParseUint(s, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		us = append(us, u) | ||||
| 	} | ||||
|  | ||||
| 	return us, nil | ||||
| } | ||||
|  | ||||
| // ReadUintFromFile reads a file and attempts to parse a uint64 from it. | ||||
| func ReadUintFromFile(path string) (uint64, error) { | ||||
| 	data, err := ioutil.ReadFile(path) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) | ||||
| } | ||||
							
								
								
									
										45
									
								
								vendor/github.com/prometheus/procfs/internal/util/sysreadfile_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/prometheus/procfs/internal/util/sysreadfile_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| // Copyright 2018 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 !windows | ||||
|  | ||||
| package util | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"os" | ||||
| 	"syscall" | ||||
| ) | ||||
|  | ||||
| // SysReadFile is a simplified ioutil.ReadFile that invokes syscall.Read directly. | ||||
| // https://github.com/prometheus/node_exporter/pull/728/files | ||||
| func SysReadFile(file string) (string, error) { | ||||
| 	f, err := os.Open(file) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	// On some machines, hwmon drivers are broken and return EAGAIN.  This causes | ||||
| 	// Go's ioutil.ReadFile implementation to poll forever. | ||||
| 	// | ||||
| 	// Since we either want to read data or bail immediately, do the simplest | ||||
| 	// possible read using syscall directly. | ||||
| 	b := make([]byte, 128) | ||||
| 	n, err := syscall.Read(int(f.Fd()), b) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	return string(bytes.TrimSpace(b[:n])), nil | ||||
| } | ||||
							
								
								
									
										259
									
								
								vendor/github.com/prometheus/procfs/ipvs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								vendor/github.com/prometheus/procfs/ipvs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,259 @@ | ||||
| // Copyright 2018 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 procfs | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"encoding/hex" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // IPVSStats holds IPVS statistics, as exposed by the kernel in `/proc/net/ip_vs_stats`. | ||||
| type IPVSStats struct { | ||||
| 	// Total count of connections. | ||||
| 	Connections uint64 | ||||
| 	// Total incoming packages processed. | ||||
| 	IncomingPackets uint64 | ||||
| 	// Total outgoing packages processed. | ||||
| 	OutgoingPackets uint64 | ||||
| 	// Total incoming traffic. | ||||
| 	IncomingBytes uint64 | ||||
| 	// Total outgoing traffic. | ||||
| 	OutgoingBytes uint64 | ||||
| } | ||||
|  | ||||
| // IPVSBackendStatus holds current metrics of one virtual / real address pair. | ||||
| type IPVSBackendStatus struct { | ||||
| 	// The local (virtual) IP address. | ||||
| 	LocalAddress net.IP | ||||
| 	// The remote (real) IP address. | ||||
| 	RemoteAddress net.IP | ||||
| 	// The local (virtual) port. | ||||
| 	LocalPort uint16 | ||||
| 	// The remote (real) port. | ||||
| 	RemotePort uint16 | ||||
| 	// The local firewall mark | ||||
| 	LocalMark string | ||||
| 	// The transport protocol (TCP, UDP). | ||||
| 	Proto string | ||||
| 	// The current number of active connections for this virtual/real address pair. | ||||
| 	ActiveConn uint64 | ||||
| 	// The current number of inactive connections for this virtual/real address pair. | ||||
| 	InactConn uint64 | ||||
| 	// The current weight of this virtual/real address pair. | ||||
| 	Weight uint64 | ||||
| } | ||||
|  | ||||
| // NewIPVSStats reads the IPVS statistics. | ||||
| func NewIPVSStats() (IPVSStats, error) { | ||||
| 	fs, err := NewFS(DefaultMountPoint) | ||||
| 	if err != nil { | ||||
| 		return IPVSStats{}, err | ||||
| 	} | ||||
|  | ||||
| 	return fs.NewIPVSStats() | ||||
| } | ||||
|  | ||||
| // NewIPVSStats reads the IPVS statistics from the specified `proc` filesystem. | ||||
| func (fs FS) NewIPVSStats() (IPVSStats, error) { | ||||
| 	file, err := os.Open(fs.Path("net/ip_vs_stats")) | ||||
| 	if err != nil { | ||||
| 		return IPVSStats{}, err | ||||
| 	} | ||||
| 	defer file.Close() | ||||
|  | ||||
| 	return parseIPVSStats(file) | ||||
| } | ||||
|  | ||||
| // parseIPVSStats performs the actual parsing of `ip_vs_stats`. | ||||
| func parseIPVSStats(file io.Reader) (IPVSStats, error) { | ||||
| 	var ( | ||||
| 		statContent []byte | ||||
| 		statLines   []string | ||||
| 		statFields  []string | ||||
| 		stats       IPVSStats | ||||
| 	) | ||||
|  | ||||
| 	statContent, err := ioutil.ReadAll(file) | ||||
| 	if err != nil { | ||||
| 		return IPVSStats{}, err | ||||
| 	} | ||||
|  | ||||
| 	statLines = strings.SplitN(string(statContent), "\n", 4) | ||||
| 	if len(statLines) != 4 { | ||||
| 		return IPVSStats{}, errors.New("ip_vs_stats corrupt: too short") | ||||
| 	} | ||||
|  | ||||
| 	statFields = strings.Fields(statLines[2]) | ||||
| 	if len(statFields) != 5 { | ||||
| 		return IPVSStats{}, errors.New("ip_vs_stats corrupt: unexpected number of fields") | ||||
| 	} | ||||
|  | ||||
| 	stats.Connections, err = strconv.ParseUint(statFields[0], 16, 64) | ||||
| 	if err != nil { | ||||
| 		return IPVSStats{}, err | ||||
| 	} | ||||
| 	stats.IncomingPackets, err = strconv.ParseUint(statFields[1], 16, 64) | ||||
| 	if err != nil { | ||||
| 		return IPVSStats{}, err | ||||
| 	} | ||||
| 	stats.OutgoingPackets, err = strconv.ParseUint(statFields[2], 16, 64) | ||||
| 	if err != nil { | ||||
| 		return IPVSStats{}, err | ||||
| 	} | ||||
| 	stats.IncomingBytes, err = strconv.ParseUint(statFields[3], 16, 64) | ||||
| 	if err != nil { | ||||
| 		return IPVSStats{}, err | ||||
| 	} | ||||
| 	stats.OutgoingBytes, err = strconv.ParseUint(statFields[4], 16, 64) | ||||
| 	if err != nil { | ||||
| 		return IPVSStats{}, err | ||||
| 	} | ||||
|  | ||||
| 	return stats, nil | ||||
| } | ||||
|  | ||||
| // NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs. | ||||
| func NewIPVSBackendStatus() ([]IPVSBackendStatus, error) { | ||||
| 	fs, err := NewFS(DefaultMountPoint) | ||||
| 	if err != nil { | ||||
| 		return []IPVSBackendStatus{}, err | ||||
| 	} | ||||
|  | ||||
| 	return fs.NewIPVSBackendStatus() | ||||
| } | ||||
|  | ||||
| // NewIPVSBackendStatus reads and returns the status of all (virtual,real) server pairs from the specified `proc` filesystem. | ||||
| func (fs FS) NewIPVSBackendStatus() ([]IPVSBackendStatus, error) { | ||||
| 	file, err := os.Open(fs.Path("net/ip_vs")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer file.Close() | ||||
|  | ||||
| 	return parseIPVSBackendStatus(file) | ||||
| } | ||||
|  | ||||
| func parseIPVSBackendStatus(file io.Reader) ([]IPVSBackendStatus, error) { | ||||
| 	var ( | ||||
| 		status       []IPVSBackendStatus | ||||
| 		scanner      = bufio.NewScanner(file) | ||||
| 		proto        string | ||||
| 		localMark    string | ||||
| 		localAddress net.IP | ||||
| 		localPort    uint16 | ||||
| 		err          error | ||||
| 	) | ||||
|  | ||||
| 	for scanner.Scan() { | ||||
| 		fields := strings.Fields(scanner.Text()) | ||||
| 		if len(fields) == 0 { | ||||
| 			continue | ||||
| 		} | ||||
| 		switch { | ||||
| 		case fields[0] == "IP" || fields[0] == "Prot" || fields[1] == "RemoteAddress:Port": | ||||
| 			continue | ||||
| 		case fields[0] == "TCP" || fields[0] == "UDP": | ||||
| 			if len(fields) < 2 { | ||||
| 				continue | ||||
| 			} | ||||
| 			proto = fields[0] | ||||
| 			localMark = "" | ||||
| 			localAddress, localPort, err = parseIPPort(fields[1]) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		case fields[0] == "FWM": | ||||
| 			if len(fields) < 2 { | ||||
| 				continue | ||||
| 			} | ||||
| 			proto = fields[0] | ||||
| 			localMark = fields[1] | ||||
| 			localAddress = nil | ||||
| 			localPort = 0 | ||||
| 		case fields[0] == "->": | ||||
| 			if len(fields) < 6 { | ||||
| 				continue | ||||
| 			} | ||||
| 			remoteAddress, remotePort, err := parseIPPort(fields[1]) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			weight, err := strconv.ParseUint(fields[3], 10, 64) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			activeConn, err := strconv.ParseUint(fields[4], 10, 64) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			inactConn, err := strconv.ParseUint(fields[5], 10, 64) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			status = append(status, IPVSBackendStatus{ | ||||
| 				LocalAddress:  localAddress, | ||||
| 				LocalPort:     localPort, | ||||
| 				LocalMark:     localMark, | ||||
| 				RemoteAddress: remoteAddress, | ||||
| 				RemotePort:    remotePort, | ||||
| 				Proto:         proto, | ||||
| 				Weight:        weight, | ||||
| 				ActiveConn:    activeConn, | ||||
| 				InactConn:     inactConn, | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| 	return status, nil | ||||
| } | ||||
|  | ||||
| func parseIPPort(s string) (net.IP, uint16, error) { | ||||
| 	var ( | ||||
| 		ip  net.IP | ||||
| 		err error | ||||
| 	) | ||||
|  | ||||
| 	switch len(s) { | ||||
| 	case 13: | ||||
| 		ip, err = hex.DecodeString(s[0:8]) | ||||
| 		if err != nil { | ||||
| 			return nil, 0, err | ||||
| 		} | ||||
| 	case 46: | ||||
| 		ip = net.ParseIP(s[1:40]) | ||||
| 		if ip == nil { | ||||
| 			return nil, 0, fmt.Errorf("invalid IPv6 address: %s", s[1:40]) | ||||
| 		} | ||||
| 	default: | ||||
| 		return nil, 0, fmt.Errorf("unexpected IP:Port: %s", s) | ||||
| 	} | ||||
|  | ||||
| 	portString := s[len(s)-4:] | ||||
| 	if len(portString) != 4 { | ||||
| 		return nil, 0, fmt.Errorf("unexpected port string format: %s", portString) | ||||
| 	} | ||||
| 	port, err := strconv.ParseUint(portString, 16, 16) | ||||
| 	if err != nil { | ||||
| 		return nil, 0, err | ||||
| 	} | ||||
|  | ||||
| 	return ip, uint16(port), nil | ||||
| } | ||||
							
								
								
									
										151
									
								
								vendor/github.com/prometheus/procfs/mdstat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								vendor/github.com/prometheus/procfs/mdstat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| // Copyright 2018 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 procfs | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	statuslineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[[U_]+\]`) | ||||
| 	buildlineRE  = regexp.MustCompile(`\((\d+)/\d+\)`) | ||||
| ) | ||||
|  | ||||
| // MDStat holds info parsed from /proc/mdstat. | ||||
| type MDStat struct { | ||||
| 	// Name of the device. | ||||
| 	Name string | ||||
| 	// activity-state of the device. | ||||
| 	ActivityState string | ||||
| 	// Number of active disks. | ||||
| 	DisksActive int64 | ||||
| 	// Total number of disks the device consists of. | ||||
| 	DisksTotal int64 | ||||
| 	// Number of blocks the device holds. | ||||
| 	BlocksTotal int64 | ||||
| 	// Number of blocks on the device that are in sync. | ||||
| 	BlocksSynced int64 | ||||
| } | ||||
|  | ||||
| // ParseMDStat parses an mdstat-file and returns a struct with the relevant infos. | ||||
| func (fs FS) ParseMDStat() (mdstates []MDStat, err error) { | ||||
| 	mdStatusFilePath := fs.Path("mdstat") | ||||
| 	content, err := ioutil.ReadFile(mdStatusFilePath) | ||||
| 	if err != nil { | ||||
| 		return []MDStat{}, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) | ||||
| 	} | ||||
|  | ||||
| 	mdStates := []MDStat{} | ||||
| 	lines := strings.Split(string(content), "\n") | ||||
| 	for i, l := range lines { | ||||
| 		if l == "" { | ||||
| 			continue | ||||
| 		} | ||||
| 		if l[0] == ' ' { | ||||
| 			continue | ||||
| 		} | ||||
| 		if strings.HasPrefix(l, "Personalities") || strings.HasPrefix(l, "unused") { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		mainLine := strings.Split(l, " ") | ||||
| 		if len(mainLine) < 3 { | ||||
| 			return mdStates, fmt.Errorf("error parsing mdline: %s", l) | ||||
| 		} | ||||
| 		mdName := mainLine[0] | ||||
| 		activityState := mainLine[2] | ||||
|  | ||||
| 		if len(lines) <= i+3 { | ||||
| 			return mdStates, fmt.Errorf( | ||||
| 				"error parsing %s: too few lines for md device %s", | ||||
| 				mdStatusFilePath, | ||||
| 				mdName, | ||||
| 			) | ||||
| 		} | ||||
|  | ||||
| 		active, total, size, err := evalStatusline(lines[i+1]) | ||||
| 		if err != nil { | ||||
| 			return mdStates, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) | ||||
| 		} | ||||
|  | ||||
| 		// j is the line number of the syncing-line. | ||||
| 		j := i + 2 | ||||
| 		if strings.Contains(lines[i+2], "bitmap") { // skip bitmap line | ||||
| 			j = i + 3 | ||||
| 		} | ||||
|  | ||||
| 		// If device is syncing at the moment, get the number of currently | ||||
| 		// synced bytes, otherwise that number equals the size of the device. | ||||
| 		syncedBlocks := size | ||||
| 		if strings.Contains(lines[j], "recovery") || strings.Contains(lines[j], "resync") { | ||||
| 			syncedBlocks, err = evalBuildline(lines[j]) | ||||
| 			if err != nil { | ||||
| 				return mdStates, fmt.Errorf("error parsing %s: %s", mdStatusFilePath, err) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		mdStates = append(mdStates, MDStat{ | ||||
| 			Name:          mdName, | ||||
| 			ActivityState: activityState, | ||||
| 			DisksActive:   active, | ||||
| 			DisksTotal:    total, | ||||
| 			BlocksTotal:   size, | ||||
| 			BlocksSynced:  syncedBlocks, | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	return mdStates, nil | ||||
| } | ||||
|  | ||||
| func evalStatusline(statusline string) (active, total, size int64, err error) { | ||||
| 	matches := statuslineRE.FindStringSubmatch(statusline) | ||||
| 	if len(matches) != 4 { | ||||
| 		return 0, 0, 0, fmt.Errorf("unexpected statusline: %s", statusline) | ||||
| 	} | ||||
|  | ||||
| 	size, err = strconv.ParseInt(matches[1], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) | ||||
| 	} | ||||
|  | ||||
| 	total, err = strconv.ParseInt(matches[2], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) | ||||
| 	} | ||||
|  | ||||
| 	active, err = strconv.ParseInt(matches[3], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return 0, 0, 0, fmt.Errorf("unexpected statusline %s: %s", statusline, err) | ||||
| 	} | ||||
|  | ||||
| 	return active, total, size, nil | ||||
| } | ||||
|  | ||||
| func evalBuildline(buildline string) (syncedBlocks int64, err error) { | ||||
| 	matches := buildlineRE.FindStringSubmatch(buildline) | ||||
| 	if len(matches) != 2 { | ||||
| 		return 0, fmt.Errorf("unexpected buildline: %s", buildline) | ||||
| 	} | ||||
|  | ||||
| 	syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return 0, fmt.Errorf("%s in buildline: %s", err, buildline) | ||||
| 	} | ||||
|  | ||||
| 	return syncedBlocks, nil | ||||
| } | ||||
							
								
								
									
										606
									
								
								vendor/github.com/prometheus/procfs/mountstats.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										606
									
								
								vendor/github.com/prometheus/procfs/mountstats.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,606 @@ | ||||
| // Copyright 2018 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 procfs | ||||
|  | ||||
| // While implementing parsing of /proc/[pid]/mountstats, this blog was used | ||||
| // heavily as a reference: | ||||
| //   https://utcc.utoronto.ca/~cks/space/blog/linux/NFSMountstatsIndex | ||||
| // | ||||
| // Special thanks to Chris Siebenmann for all of his posts explaining the | ||||
| // various statistics available for NFS. | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // Constants shared between multiple functions. | ||||
| const ( | ||||
| 	deviceEntryLen = 8 | ||||
|  | ||||
| 	fieldBytesLen  = 8 | ||||
| 	fieldEventsLen = 27 | ||||
|  | ||||
| 	statVersion10 = "1.0" | ||||
| 	statVersion11 = "1.1" | ||||
|  | ||||
| 	fieldTransport10TCPLen = 10 | ||||
| 	fieldTransport10UDPLen = 7 | ||||
|  | ||||
| 	fieldTransport11TCPLen = 13 | ||||
| 	fieldTransport11UDPLen = 10 | ||||
| ) | ||||
|  | ||||
| // A Mount is a device mount parsed from /proc/[pid]/mountstats. | ||||
| type Mount struct { | ||||
| 	// Name of the device. | ||||
| 	Device string | ||||
| 	// The mount point of the device. | ||||
| 	Mount string | ||||
| 	// The filesystem type used by the device. | ||||
| 	Type string | ||||
| 	// If available additional statistics related to this Mount. | ||||
| 	// Use a type assertion to determine if additional statistics are available. | ||||
| 	Stats MountStats | ||||
| } | ||||
|  | ||||
| // A MountStats is a type which contains detailed statistics for a specific | ||||
| // type of Mount. | ||||
| type MountStats interface { | ||||
| 	mountStats() | ||||
| } | ||||
|  | ||||
| // A MountStatsNFS is a MountStats implementation for NFSv3 and v4 mounts. | ||||
| type MountStatsNFS struct { | ||||
| 	// The version of statistics provided. | ||||
| 	StatVersion string | ||||
| 	// The age of the NFS mount. | ||||
| 	Age time.Duration | ||||
| 	// Statistics related to byte counters for various operations. | ||||
| 	Bytes NFSBytesStats | ||||
| 	// Statistics related to various NFS event occurrences. | ||||
| 	Events NFSEventsStats | ||||
| 	// Statistics broken down by filesystem operation. | ||||
| 	Operations []NFSOperationStats | ||||
| 	// Statistics about the NFS RPC transport. | ||||
| 	Transport NFSTransportStats | ||||
| } | ||||
|  | ||||
| // mountStats implements MountStats. | ||||
| func (m MountStatsNFS) mountStats() {} | ||||
|  | ||||
| // A NFSBytesStats contains statistics about the number of bytes read and written | ||||
| // by an NFS client to and from an NFS server. | ||||
| type NFSBytesStats struct { | ||||
| 	// Number of bytes read using the read() syscall. | ||||
| 	Read uint64 | ||||
| 	// Number of bytes written using the write() syscall. | ||||
| 	Write uint64 | ||||
| 	// Number of bytes read using the read() syscall in O_DIRECT mode. | ||||
| 	DirectRead uint64 | ||||
| 	// Number of bytes written using the write() syscall in O_DIRECT mode. | ||||
| 	DirectWrite uint64 | ||||
| 	// Number of bytes read from the NFS server, in total. | ||||
| 	ReadTotal uint64 | ||||
| 	// Number of bytes written to the NFS server, in total. | ||||
| 	WriteTotal uint64 | ||||
| 	// Number of pages read directly via mmap()'d files. | ||||
| 	ReadPages uint64 | ||||
| 	// Number of pages written directly via mmap()'d files. | ||||
| 	WritePages uint64 | ||||
| } | ||||
|  | ||||
| // A NFSEventsStats contains statistics about NFS event occurrences. | ||||
| type NFSEventsStats struct { | ||||
| 	// Number of times cached inode attributes are re-validated from the server. | ||||
| 	InodeRevalidate uint64 | ||||
| 	// Number of times cached dentry nodes are re-validated from the server. | ||||
| 	DnodeRevalidate uint64 | ||||
| 	// Number of times an inode cache is cleared. | ||||
| 	DataInvalidate uint64 | ||||
| 	// Number of times cached inode attributes are invalidated. | ||||
| 	AttributeInvalidate uint64 | ||||
| 	// Number of times files or directories have been open()'d. | ||||
| 	VFSOpen uint64 | ||||
| 	// Number of times a directory lookup has occurred. | ||||
| 	VFSLookup uint64 | ||||
| 	// Number of times permissions have been checked. | ||||
| 	VFSAccess uint64 | ||||
| 	// Number of updates (and potential writes) to pages. | ||||
| 	VFSUpdatePage uint64 | ||||
| 	// Number of pages read directly via mmap()'d files. | ||||
| 	VFSReadPage uint64 | ||||
| 	// Number of times a group of pages have been read. | ||||
| 	VFSReadPages uint64 | ||||
| 	// Number of pages written directly via mmap()'d files. | ||||
| 	VFSWritePage uint64 | ||||
| 	// Number of times a group of pages have been written. | ||||
| 	VFSWritePages uint64 | ||||
| 	// Number of times directory entries have been read with getdents(). | ||||
| 	VFSGetdents uint64 | ||||
| 	// Number of times attributes have been set on inodes. | ||||
| 	VFSSetattr uint64 | ||||
| 	// Number of pending writes that have been forcefully flushed to the server. | ||||
| 	VFSFlush uint64 | ||||
| 	// Number of times fsync() has been called on directories and files. | ||||
| 	VFSFsync uint64 | ||||
| 	// Number of times locking has been attempted on a file. | ||||
| 	VFSLock uint64 | ||||
| 	// Number of times files have been closed and released. | ||||
| 	VFSFileRelease uint64 | ||||
| 	// Unknown.  Possibly unused. | ||||
| 	CongestionWait uint64 | ||||
| 	// Number of times files have been truncated. | ||||
| 	Truncation uint64 | ||||
| 	// Number of times a file has been grown due to writes beyond its existing end. | ||||
| 	WriteExtension uint64 | ||||
| 	// Number of times a file was removed while still open by another process. | ||||
| 	SillyRename uint64 | ||||
| 	// Number of times the NFS server gave less data than expected while reading. | ||||
| 	ShortRead uint64 | ||||
| 	// Number of times the NFS server wrote less data than expected while writing. | ||||
| 	ShortWrite uint64 | ||||
| 	// Number of times the NFS server indicated EJUKEBOX; retrieving data from | ||||
| 	// offline storage. | ||||
| 	JukeboxDelay uint64 | ||||
| 	// Number of NFS v4.1+ pNFS reads. | ||||
| 	PNFSRead uint64 | ||||
| 	// Number of NFS v4.1+ pNFS writes. | ||||
| 	PNFSWrite uint64 | ||||
| } | ||||
|  | ||||
| // A NFSOperationStats contains statistics for a single operation. | ||||
| type NFSOperationStats struct { | ||||
| 	// The name of the operation. | ||||
| 	Operation string | ||||
| 	// Number of requests performed for this operation. | ||||
| 	Requests uint64 | ||||
| 	// Number of times an actual RPC request has been transmitted for this operation. | ||||
| 	Transmissions uint64 | ||||
| 	// Number of times a request has had a major timeout. | ||||
| 	MajorTimeouts uint64 | ||||
| 	// Number of bytes sent for this operation, including RPC headers and payload. | ||||
| 	BytesSent uint64 | ||||
| 	// Number of bytes received for this operation, including RPC headers and payload. | ||||
| 	BytesReceived uint64 | ||||
| 	// Duration all requests spent queued for transmission before they were sent. | ||||
| 	CumulativeQueueTime time.Duration | ||||
| 	// Duration it took to get a reply back after the request was transmitted. | ||||
| 	CumulativeTotalResponseTime time.Duration | ||||
| 	// Duration from when a request was enqueued to when it was completely handled. | ||||
| 	CumulativeTotalRequestTime time.Duration | ||||
| } | ||||
|  | ||||
| // A NFSTransportStats contains statistics for the NFS mount RPC requests and | ||||
| // responses. | ||||
| type NFSTransportStats struct { | ||||
| 	// The transport protocol used for the NFS mount. | ||||
| 	Protocol string | ||||
| 	// The local port used for the NFS mount. | ||||
| 	Port uint64 | ||||
| 	// Number of times the client has had to establish a connection from scratch | ||||
| 	// to the NFS server. | ||||
| 	Bind uint64 | ||||
| 	// Number of times the client has made a TCP connection to the NFS server. | ||||
| 	Connect uint64 | ||||
| 	// Duration (in jiffies, a kernel internal unit of time) the NFS mount has | ||||
| 	// spent waiting for connections to the server to be established. | ||||
| 	ConnectIdleTime uint64 | ||||
| 	// Duration since the NFS mount last saw any RPC traffic. | ||||
| 	IdleTime time.Duration | ||||
| 	// Number of RPC requests for this mount sent to the NFS server. | ||||
| 	Sends uint64 | ||||
| 	// Number of RPC responses for this mount received from the NFS server. | ||||
| 	Receives uint64 | ||||
| 	// Number of times the NFS server sent a response with a transaction ID | ||||
| 	// unknown to this client. | ||||
| 	BadTransactionIDs uint64 | ||||
| 	// A running counter, incremented on each request as the current difference | ||||
| 	// ebetween sends and receives. | ||||
| 	CumulativeActiveRequests uint64 | ||||
| 	// A running counter, incremented on each request by the current backlog | ||||
| 	// queue size. | ||||
| 	CumulativeBacklog uint64 | ||||
|  | ||||
| 	// Stats below only available with stat version 1.1. | ||||
|  | ||||
| 	// Maximum number of simultaneously active RPC requests ever used. | ||||
| 	MaximumRPCSlotsUsed uint64 | ||||
| 	// A running counter, incremented on each request as the current size of the | ||||
| 	// sending queue. | ||||
| 	CumulativeSendingQueue uint64 | ||||
| 	// A running counter, incremented on each request as the current size of the | ||||
| 	// pending queue. | ||||
| 	CumulativePendingQueue uint64 | ||||
| } | ||||
|  | ||||
| // parseMountStats parses a /proc/[pid]/mountstats file and returns a slice | ||||
| // of Mount structures containing detailed information about each mount. | ||||
| // If available, statistics for each mount are parsed as well. | ||||
| func parseMountStats(r io.Reader) ([]*Mount, error) { | ||||
| 	const ( | ||||
| 		device            = "device" | ||||
| 		statVersionPrefix = "statvers=" | ||||
|  | ||||
| 		nfs3Type = "nfs" | ||||
| 		nfs4Type = "nfs4" | ||||
| 	) | ||||
|  | ||||
| 	var mounts []*Mount | ||||
|  | ||||
| 	s := bufio.NewScanner(r) | ||||
| 	for s.Scan() { | ||||
| 		// Only look for device entries in this function | ||||
| 		ss := strings.Fields(string(s.Bytes())) | ||||
| 		if len(ss) == 0 || ss[0] != device { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		m, err := parseMount(ss) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		// Does this mount also possess statistics information? | ||||
| 		if len(ss) > deviceEntryLen { | ||||
| 			// Only NFSv3 and v4 are supported for parsing statistics | ||||
| 			if m.Type != nfs3Type && m.Type != nfs4Type { | ||||
| 				return nil, fmt.Errorf("cannot parse MountStats for fstype %q", m.Type) | ||||
| 			} | ||||
|  | ||||
| 			statVersion := strings.TrimPrefix(ss[8], statVersionPrefix) | ||||
|  | ||||
| 			stats, err := parseMountStatsNFS(s, statVersion) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			m.Stats = stats | ||||
| 		} | ||||
|  | ||||
| 		mounts = append(mounts, m) | ||||
| 	} | ||||
|  | ||||
| 	return mounts, s.Err() | ||||
| } | ||||
|  | ||||
| // parseMount parses an entry in /proc/[pid]/mountstats in the format: | ||||
| //   device [device] mounted on [mount] with fstype [type] | ||||
| func parseMount(ss []string) (*Mount, error) { | ||||
| 	if len(ss) < deviceEntryLen { | ||||
| 		return nil, fmt.Errorf("invalid device entry: %v", ss) | ||||
| 	} | ||||
|  | ||||
| 	// Check for specific words appearing at specific indices to ensure | ||||
| 	// the format is consistent with what we expect | ||||
| 	format := []struct { | ||||
| 		i int | ||||
| 		s string | ||||
| 	}{ | ||||
| 		{i: 0, s: "device"}, | ||||
| 		{i: 2, s: "mounted"}, | ||||
| 		{i: 3, s: "on"}, | ||||
| 		{i: 5, s: "with"}, | ||||
| 		{i: 6, s: "fstype"}, | ||||
| 	} | ||||
|  | ||||
| 	for _, f := range format { | ||||
| 		if ss[f.i] != f.s { | ||||
| 			return nil, fmt.Errorf("invalid device entry: %v", ss) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &Mount{ | ||||
| 		Device: ss[1], | ||||
| 		Mount:  ss[4], | ||||
| 		Type:   ss[7], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // parseMountStatsNFS parses a MountStatsNFS by scanning additional information | ||||
| // related to NFS statistics. | ||||
| func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, error) { | ||||
| 	// Field indicators for parsing specific types of data | ||||
| 	const ( | ||||
| 		fieldAge        = "age:" | ||||
| 		fieldBytes      = "bytes:" | ||||
| 		fieldEvents     = "events:" | ||||
| 		fieldPerOpStats = "per-op" | ||||
| 		fieldTransport  = "xprt:" | ||||
| 	) | ||||
|  | ||||
| 	stats := &MountStatsNFS{ | ||||
| 		StatVersion: statVersion, | ||||
| 	} | ||||
|  | ||||
| 	for s.Scan() { | ||||
| 		ss := strings.Fields(string(s.Bytes())) | ||||
| 		if len(ss) == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 		if len(ss) < 2 { | ||||
| 			return nil, fmt.Errorf("not enough information for NFS stats: %v", ss) | ||||
| 		} | ||||
|  | ||||
| 		switch ss[0] { | ||||
| 		case fieldAge: | ||||
| 			// Age integer is in seconds | ||||
| 			d, err := time.ParseDuration(ss[1] + "s") | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			stats.Age = d | ||||
| 		case fieldBytes: | ||||
| 			bstats, err := parseNFSBytesStats(ss[1:]) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			stats.Bytes = *bstats | ||||
| 		case fieldEvents: | ||||
| 			estats, err := parseNFSEventsStats(ss[1:]) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			stats.Events = *estats | ||||
| 		case fieldTransport: | ||||
| 			if len(ss) < 3 { | ||||
| 				return nil, fmt.Errorf("not enough information for NFS transport stats: %v", ss) | ||||
| 			} | ||||
|  | ||||
| 			tstats, err := parseNFSTransportStats(ss[1:], statVersion) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			stats.Transport = *tstats | ||||
| 		} | ||||
|  | ||||
| 		// When encountering "per-operation statistics", we must break this | ||||
| 		// loop and parse them separately to ensure we can terminate parsing | ||||
| 		// before reaching another device entry; hence why this 'if' statement | ||||
| 		// is not just another switch case | ||||
| 		if ss[0] == fieldPerOpStats { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := s.Err(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// NFS per-operation stats appear last before the next device entry | ||||
| 	perOpStats, err := parseNFSOperationStats(s) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	stats.Operations = perOpStats | ||||
|  | ||||
| 	return stats, nil | ||||
| } | ||||
|  | ||||
| // parseNFSBytesStats parses a NFSBytesStats line using an input set of | ||||
| // integer fields. | ||||
| func parseNFSBytesStats(ss []string) (*NFSBytesStats, error) { | ||||
| 	if len(ss) != fieldBytesLen { | ||||
| 		return nil, fmt.Errorf("invalid NFS bytes stats: %v", ss) | ||||
| 	} | ||||
|  | ||||
| 	ns := make([]uint64, 0, fieldBytesLen) | ||||
| 	for _, s := range ss { | ||||
| 		n, err := strconv.ParseUint(s, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		ns = append(ns, n) | ||||
| 	} | ||||
|  | ||||
| 	return &NFSBytesStats{ | ||||
| 		Read:        ns[0], | ||||
| 		Write:       ns[1], | ||||
| 		DirectRead:  ns[2], | ||||
| 		DirectWrite: ns[3], | ||||
| 		ReadTotal:   ns[4], | ||||
| 		WriteTotal:  ns[5], | ||||
| 		ReadPages:   ns[6], | ||||
| 		WritePages:  ns[7], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // parseNFSEventsStats parses a NFSEventsStats line using an input set of | ||||
| // integer fields. | ||||
| func parseNFSEventsStats(ss []string) (*NFSEventsStats, error) { | ||||
| 	if len(ss) != fieldEventsLen { | ||||
| 		return nil, fmt.Errorf("invalid NFS events stats: %v", ss) | ||||
| 	} | ||||
|  | ||||
| 	ns := make([]uint64, 0, fieldEventsLen) | ||||
| 	for _, s := range ss { | ||||
| 		n, err := strconv.ParseUint(s, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		ns = append(ns, n) | ||||
| 	} | ||||
|  | ||||
| 	return &NFSEventsStats{ | ||||
| 		InodeRevalidate:     ns[0], | ||||
| 		DnodeRevalidate:     ns[1], | ||||
| 		DataInvalidate:      ns[2], | ||||
| 		AttributeInvalidate: ns[3], | ||||
| 		VFSOpen:             ns[4], | ||||
| 		VFSLookup:           ns[5], | ||||
| 		VFSAccess:           ns[6], | ||||
| 		VFSUpdatePage:       ns[7], | ||||
| 		VFSReadPage:         ns[8], | ||||
| 		VFSReadPages:        ns[9], | ||||
| 		VFSWritePage:        ns[10], | ||||
| 		VFSWritePages:       ns[11], | ||||
| 		VFSGetdents:         ns[12], | ||||
| 		VFSSetattr:          ns[13], | ||||
| 		VFSFlush:            ns[14], | ||||
| 		VFSFsync:            ns[15], | ||||
| 		VFSLock:             ns[16], | ||||
| 		VFSFileRelease:      ns[17], | ||||
| 		CongestionWait:      ns[18], | ||||
| 		Truncation:          ns[19], | ||||
| 		WriteExtension:      ns[20], | ||||
| 		SillyRename:         ns[21], | ||||
| 		ShortRead:           ns[22], | ||||
| 		ShortWrite:          ns[23], | ||||
| 		JukeboxDelay:        ns[24], | ||||
| 		PNFSRead:            ns[25], | ||||
| 		PNFSWrite:           ns[26], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // parseNFSOperationStats parses a slice of NFSOperationStats by scanning | ||||
| // additional information about per-operation statistics until an empty | ||||
| // line is reached. | ||||
| func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) { | ||||
| 	const ( | ||||
| 		// Number of expected fields in each per-operation statistics set | ||||
| 		numFields = 9 | ||||
| 	) | ||||
|  | ||||
| 	var ops []NFSOperationStats | ||||
|  | ||||
| 	for s.Scan() { | ||||
| 		ss := strings.Fields(string(s.Bytes())) | ||||
| 		if len(ss) == 0 { | ||||
| 			// Must break when reading a blank line after per-operation stats to | ||||
| 			// enable top-level function to parse the next device entry | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		if len(ss) != numFields { | ||||
| 			return nil, fmt.Errorf("invalid NFS per-operations stats: %v", ss) | ||||
| 		} | ||||
|  | ||||
| 		// Skip string operation name for integers | ||||
| 		ns := make([]uint64, 0, numFields-1) | ||||
| 		for _, st := range ss[1:] { | ||||
| 			n, err := strconv.ParseUint(st, 10, 64) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			ns = append(ns, n) | ||||
| 		} | ||||
|  | ||||
| 		ops = append(ops, NFSOperationStats{ | ||||
| 			Operation:                   strings.TrimSuffix(ss[0], ":"), | ||||
| 			Requests:                    ns[0], | ||||
| 			Transmissions:               ns[1], | ||||
| 			MajorTimeouts:               ns[2], | ||||
| 			BytesSent:                   ns[3], | ||||
| 			BytesReceived:               ns[4], | ||||
| 			CumulativeQueueTime:         time.Duration(ns[5]) * time.Millisecond, | ||||
| 			CumulativeTotalResponseTime: time.Duration(ns[6]) * time.Millisecond, | ||||
| 			CumulativeTotalRequestTime:  time.Duration(ns[7]) * time.Millisecond, | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	return ops, s.Err() | ||||
| } | ||||
|  | ||||
| // parseNFSTransportStats parses a NFSTransportStats line using an input set of | ||||
| // integer fields matched to a specific stats version. | ||||
| func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats, error) { | ||||
| 	// Extract the protocol field. It is the only string value in the line | ||||
| 	protocol := ss[0] | ||||
| 	ss = ss[1:] | ||||
|  | ||||
| 	switch statVersion { | ||||
| 	case statVersion10: | ||||
| 		var expectedLength int | ||||
| 		if protocol == "tcp" { | ||||
| 			expectedLength = fieldTransport10TCPLen | ||||
| 		} else if protocol == "udp" { | ||||
| 			expectedLength = fieldTransport10UDPLen | ||||
| 		} else { | ||||
| 			return nil, fmt.Errorf("invalid NFS protocol \"%s\" in stats 1.0 statement: %v", protocol, ss) | ||||
| 		} | ||||
| 		if len(ss) != expectedLength { | ||||
| 			return nil, fmt.Errorf("invalid NFS transport stats 1.0 statement: %v", ss) | ||||
| 		} | ||||
| 	case statVersion11: | ||||
| 		var expectedLength int | ||||
| 		if protocol == "tcp" { | ||||
| 			expectedLength = fieldTransport11TCPLen | ||||
| 		} else if protocol == "udp" { | ||||
| 			expectedLength = fieldTransport11UDPLen | ||||
| 		} else { | ||||
| 			return nil, fmt.Errorf("invalid NFS protocol \"%s\" in stats 1.1 statement: %v", protocol, ss) | ||||
| 		} | ||||
| 		if len(ss) != expectedLength { | ||||
| 			return nil, fmt.Errorf("invalid NFS transport stats 1.1 statement: %v", ss) | ||||
| 		} | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("unrecognized NFS transport stats version: %q", statVersion) | ||||
| 	} | ||||
|  | ||||
| 	// Allocate enough for v1.1 stats since zero value for v1.1 stats will be okay | ||||
| 	// in a v1.0 response. Since the stat length is bigger for TCP stats, we use | ||||
| 	// the TCP length here. | ||||
| 	// | ||||
| 	// Note: slice length must be set to length of v1.1 stats to avoid a panic when | ||||
| 	// only v1.0 stats are present. | ||||
| 	// See: https://github.com/prometheus/node_exporter/issues/571. | ||||
| 	ns := make([]uint64, fieldTransport11TCPLen) | ||||
| 	for i, s := range ss { | ||||
| 		n, err := strconv.ParseUint(s, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		ns[i] = n | ||||
| 	} | ||||
|  | ||||
| 	// The fields differ depending on the transport protocol (TCP or UDP) | ||||
| 	// From https://utcc.utoronto.ca/%7Ecks/space/blog/linux/NFSMountstatsXprt | ||||
| 	// | ||||
| 	// For the udp RPC transport there is no connection count, connect idle time, | ||||
| 	// or idle time (fields #3, #4, and #5); all other fields are the same. So | ||||
| 	// we set them to 0 here. | ||||
| 	if protocol == "udp" { | ||||
| 		ns = append(ns[:2], append(make([]uint64, 3), ns[2:]...)...) | ||||
| 	} | ||||
|  | ||||
| 	return &NFSTransportStats{ | ||||
| 		Protocol:                 protocol, | ||||
| 		Port:                     ns[0], | ||||
| 		Bind:                     ns[1], | ||||
| 		Connect:                  ns[2], | ||||
| 		ConnectIdleTime:          ns[3], | ||||
| 		IdleTime:                 time.Duration(ns[4]) * time.Second, | ||||
| 		Sends:                    ns[5], | ||||
| 		Receives:                 ns[6], | ||||
| 		BadTransactionIDs:        ns[7], | ||||
| 		CumulativeActiveRequests: ns[8], | ||||
| 		CumulativeBacklog:        ns[9], | ||||
| 		MaximumRPCSlotsUsed:      ns[10], | ||||
| 		CumulativeSendingQueue:   ns[11], | ||||
| 		CumulativePendingQueue:   ns[12], | ||||
| 	}, nil | ||||
| } | ||||
							
								
								
									
										216
									
								
								vendor/github.com/prometheus/procfs/net_dev.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								vendor/github.com/prometheus/procfs/net_dev.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | ||||
| // Copyright 2018 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 procfs | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"errors" | ||||
| 	"os" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // NetDevLine is single line parsed from /proc/net/dev or /proc/[pid]/net/dev. | ||||
| type NetDevLine struct { | ||||
| 	Name         string `json:"name"`          // The name of the interface. | ||||
| 	RxBytes      uint64 `json:"rx_bytes"`      // Cumulative count of bytes received. | ||||
| 	RxPackets    uint64 `json:"rx_packets"`    // Cumulative count of packets received. | ||||
| 	RxErrors     uint64 `json:"rx_errors"`     // Cumulative count of receive errors encountered. | ||||
| 	RxDropped    uint64 `json:"rx_dropped"`    // Cumulative count of packets dropped while receiving. | ||||
| 	RxFIFO       uint64 `json:"rx_fifo"`       // Cumulative count of FIFO buffer errors. | ||||
| 	RxFrame      uint64 `json:"rx_frame"`      // Cumulative count of packet framing errors. | ||||
| 	RxCompressed uint64 `json:"rx_compressed"` // Cumulative count of compressed packets received by the device driver. | ||||
| 	RxMulticast  uint64 `json:"rx_multicast"`  // Cumulative count of multicast frames received by the device driver. | ||||
| 	TxBytes      uint64 `json:"tx_bytes"`      // Cumulative count of bytes transmitted. | ||||
| 	TxPackets    uint64 `json:"tx_packets"`    // Cumulative count of packets transmitted. | ||||
| 	TxErrors     uint64 `json:"tx_errors"`     // Cumulative count of transmit errors encountered. | ||||
| 	TxDropped    uint64 `json:"tx_dropped"`    // Cumulative count of packets dropped while transmitting. | ||||
| 	TxFIFO       uint64 `json:"tx_fifo"`       // Cumulative count of FIFO buffer errors. | ||||
| 	TxCollisions uint64 `json:"tx_collisions"` // Cumulative count of collisions detected on the interface. | ||||
| 	TxCarrier    uint64 `json:"tx_carrier"`    // Cumulative count of carrier losses detected by the device driver. | ||||
| 	TxCompressed uint64 `json:"tx_compressed"` // Cumulative count of compressed packets transmitted by the device driver. | ||||
| } | ||||
|  | ||||
| // NetDev is parsed from /proc/net/dev or /proc/[pid]/net/dev. The map keys | ||||
| // are interface names. | ||||
| type NetDev map[string]NetDevLine | ||||
|  | ||||
| // NewNetDev returns kernel/system statistics read from /proc/net/dev. | ||||
| func NewNetDev() (NetDev, error) { | ||||
| 	fs, err := NewFS(DefaultMountPoint) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return fs.NewNetDev() | ||||
| } | ||||
|  | ||||
| // NewNetDev returns kernel/system statistics read from /proc/net/dev. | ||||
| func (fs FS) NewNetDev() (NetDev, error) { | ||||
| 	return newNetDev(fs.Path("net/dev")) | ||||
| } | ||||
|  | ||||
| // NewNetDev returns kernel/system statistics read from /proc/[pid]/net/dev. | ||||
| func (p Proc) NewNetDev() (NetDev, error) { | ||||
| 	return newNetDev(p.path("net/dev")) | ||||
| } | ||||
|  | ||||
| // newNetDev creates a new NetDev from the contents of the given file. | ||||
| func newNetDev(file string) (NetDev, error) { | ||||
| 	f, err := os.Open(file) | ||||
| 	if err != nil { | ||||
| 		return NetDev{}, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	nd := NetDev{} | ||||
| 	s := bufio.NewScanner(f) | ||||
| 	for n := 0; s.Scan(); n++ { | ||||
| 		// Skip the 2 header lines. | ||||
| 		if n < 2 { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		line, err := nd.parseLine(s.Text()) | ||||
| 		if err != nil { | ||||
| 			return nd, err | ||||
| 		} | ||||
|  | ||||
| 		nd[line.Name] = *line | ||||
| 	} | ||||
|  | ||||
| 	return nd, s.Err() | ||||
| } | ||||
|  | ||||
| // parseLine parses a single line from the /proc/net/dev file. Header lines | ||||
| // must be filtered prior to calling this method. | ||||
| func (nd NetDev) parseLine(rawLine string) (*NetDevLine, error) { | ||||
| 	parts := strings.SplitN(rawLine, ":", 2) | ||||
| 	if len(parts) != 2 { | ||||
| 		return nil, errors.New("invalid net/dev line, missing colon") | ||||
| 	} | ||||
| 	fields := strings.Fields(strings.TrimSpace(parts[1])) | ||||
|  | ||||
| 	var err error | ||||
| 	line := &NetDevLine{} | ||||
|  | ||||
| 	// Interface Name | ||||
| 	line.Name = strings.TrimSpace(parts[0]) | ||||
| 	if line.Name == "" { | ||||
| 		return nil, errors.New("invalid net/dev line, empty interface name") | ||||
| 	} | ||||
|  | ||||
| 	// RX | ||||
| 	line.RxBytes, err = strconv.ParseUint(fields[0], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.RxPackets, err = strconv.ParseUint(fields[1], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.RxErrors, err = strconv.ParseUint(fields[2], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.RxDropped, err = strconv.ParseUint(fields[3], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.RxFIFO, err = strconv.ParseUint(fields[4], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.RxFrame, err = strconv.ParseUint(fields[5], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.RxCompressed, err = strconv.ParseUint(fields[6], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.RxMulticast, err = strconv.ParseUint(fields[7], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// TX | ||||
| 	line.TxBytes, err = strconv.ParseUint(fields[8], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.TxPackets, err = strconv.ParseUint(fields[9], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.TxErrors, err = strconv.ParseUint(fields[10], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.TxDropped, err = strconv.ParseUint(fields[11], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.TxFIFO, err = strconv.ParseUint(fields[12], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.TxCollisions, err = strconv.ParseUint(fields[13], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.TxCarrier, err = strconv.ParseUint(fields[14], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	line.TxCompressed, err = strconv.ParseUint(fields[15], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return line, nil | ||||
| } | ||||
|  | ||||
| // Total aggregates the values across interfaces and returns a new NetDevLine. | ||||
| // The Name field will be a sorted comma separated list of interface names. | ||||
| func (nd NetDev) Total() NetDevLine { | ||||
| 	total := NetDevLine{} | ||||
|  | ||||
| 	names := make([]string, 0, len(nd)) | ||||
| 	for _, ifc := range nd { | ||||
| 		names = append(names, ifc.Name) | ||||
| 		total.RxBytes += ifc.RxBytes | ||||
| 		total.RxPackets += ifc.RxPackets | ||||
| 		total.RxPackets += ifc.RxPackets | ||||
| 		total.RxErrors += ifc.RxErrors | ||||
| 		total.RxDropped += ifc.RxDropped | ||||
| 		total.RxFIFO += ifc.RxFIFO | ||||
| 		total.RxFrame += ifc.RxFrame | ||||
| 		total.RxCompressed += ifc.RxCompressed | ||||
| 		total.RxMulticast += ifc.RxMulticast | ||||
| 		total.TxBytes += ifc.TxBytes | ||||
| 		total.TxPackets += ifc.TxPackets | ||||
| 		total.TxErrors += ifc.TxErrors | ||||
| 		total.TxDropped += ifc.TxDropped | ||||
| 		total.TxFIFO += ifc.TxFIFO | ||||
| 		total.TxCollisions += ifc.TxCollisions | ||||
| 		total.TxCarrier += ifc.TxCarrier | ||||
| 		total.TxCompressed += ifc.TxCompressed | ||||
| 	} | ||||
| 	sort.Strings(names) | ||||
| 	total.Name = strings.Join(names, ", ") | ||||
|  | ||||
| 	return total | ||||
| } | ||||
							
								
								
									
										263
									
								
								vendor/github.com/prometheus/procfs/nfs/nfs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								vendor/github.com/prometheus/procfs/nfs/nfs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,263 @@ | ||||
| // Copyright 2018 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 nfs implements parsing of /proc/net/rpc/nfsd. | ||||
| // Fields are documented in https://www.svennd.be/nfsd-stats-explained-procnetrpcnfsd/ | ||||
| package nfs | ||||
|  | ||||
| // ReplyCache models the "rc" line. | ||||
| type ReplyCache struct { | ||||
| 	Hits    uint64 | ||||
| 	Misses  uint64 | ||||
| 	NoCache uint64 | ||||
| } | ||||
|  | ||||
| // FileHandles models the "fh" line. | ||||
| type FileHandles struct { | ||||
| 	Stale        uint64 | ||||
| 	TotalLookups uint64 | ||||
| 	AnonLookups  uint64 | ||||
| 	DirNoCache   uint64 | ||||
| 	NoDirNoCache uint64 | ||||
| } | ||||
|  | ||||
| // InputOutput models the "io" line. | ||||
| type InputOutput struct { | ||||
| 	Read  uint64 | ||||
| 	Write uint64 | ||||
| } | ||||
|  | ||||
| // Threads models the "th" line. | ||||
| type Threads struct { | ||||
| 	Threads uint64 | ||||
| 	FullCnt uint64 | ||||
| } | ||||
|  | ||||
| // ReadAheadCache models the "ra" line. | ||||
| type ReadAheadCache struct { | ||||
| 	CacheSize      uint64 | ||||
| 	CacheHistogram []uint64 | ||||
| 	NotFound       uint64 | ||||
| } | ||||
|  | ||||
| // Network models the "net" line. | ||||
| type Network struct { | ||||
| 	NetCount   uint64 | ||||
| 	UDPCount   uint64 | ||||
| 	TCPCount   uint64 | ||||
| 	TCPConnect uint64 | ||||
| } | ||||
|  | ||||
| // ClientRPC models the nfs "rpc" line. | ||||
| type ClientRPC struct { | ||||
| 	RPCCount        uint64 | ||||
| 	Retransmissions uint64 | ||||
| 	AuthRefreshes   uint64 | ||||
| } | ||||
|  | ||||
| // ServerRPC models the nfsd "rpc" line. | ||||
| type ServerRPC struct { | ||||
| 	RPCCount uint64 | ||||
| 	BadCnt   uint64 | ||||
| 	BadFmt   uint64 | ||||
| 	BadAuth  uint64 | ||||
| 	BadcInt  uint64 | ||||
| } | ||||
|  | ||||
| // V2Stats models the "proc2" line. | ||||
| type V2Stats struct { | ||||
| 	Null     uint64 | ||||
| 	GetAttr  uint64 | ||||
| 	SetAttr  uint64 | ||||
| 	Root     uint64 | ||||
| 	Lookup   uint64 | ||||
| 	ReadLink uint64 | ||||
| 	Read     uint64 | ||||
| 	WrCache  uint64 | ||||
| 	Write    uint64 | ||||
| 	Create   uint64 | ||||
| 	Remove   uint64 | ||||
| 	Rename   uint64 | ||||
| 	Link     uint64 | ||||
| 	SymLink  uint64 | ||||
| 	MkDir    uint64 | ||||
| 	RmDir    uint64 | ||||
| 	ReadDir  uint64 | ||||
| 	FsStat   uint64 | ||||
| } | ||||
|  | ||||
| // V3Stats models the "proc3" line. | ||||
| type V3Stats struct { | ||||
| 	Null        uint64 | ||||
| 	GetAttr     uint64 | ||||
| 	SetAttr     uint64 | ||||
| 	Lookup      uint64 | ||||
| 	Access      uint64 | ||||
| 	ReadLink    uint64 | ||||
| 	Read        uint64 | ||||
| 	Write       uint64 | ||||
| 	Create      uint64 | ||||
| 	MkDir       uint64 | ||||
| 	SymLink     uint64 | ||||
| 	MkNod       uint64 | ||||
| 	Remove      uint64 | ||||
| 	RmDir       uint64 | ||||
| 	Rename      uint64 | ||||
| 	Link        uint64 | ||||
| 	ReadDir     uint64 | ||||
| 	ReadDirPlus uint64 | ||||
| 	FsStat      uint64 | ||||
| 	FsInfo      uint64 | ||||
| 	PathConf    uint64 | ||||
| 	Commit      uint64 | ||||
| } | ||||
|  | ||||
| // ClientV4Stats models the nfs "proc4" line. | ||||
| type ClientV4Stats struct { | ||||
| 	Null               uint64 | ||||
| 	Read               uint64 | ||||
| 	Write              uint64 | ||||
| 	Commit             uint64 | ||||
| 	Open               uint64 | ||||
| 	OpenConfirm        uint64 | ||||
| 	OpenNoattr         uint64 | ||||
| 	OpenDowngrade      uint64 | ||||
| 	Close              uint64 | ||||
| 	Setattr            uint64 | ||||
| 	FsInfo             uint64 | ||||
| 	Renew              uint64 | ||||
| 	SetClientID        uint64 | ||||
| 	SetClientIDConfirm uint64 | ||||
| 	Lock               uint64 | ||||
| 	Lockt              uint64 | ||||
| 	Locku              uint64 | ||||
| 	Access             uint64 | ||||
| 	Getattr            uint64 | ||||
| 	Lookup             uint64 | ||||
| 	LookupRoot         uint64 | ||||
| 	Remove             uint64 | ||||
| 	Rename             uint64 | ||||
| 	Link               uint64 | ||||
| 	Symlink            uint64 | ||||
| 	Create             uint64 | ||||
| 	Pathconf           uint64 | ||||
| 	StatFs             uint64 | ||||
| 	ReadLink           uint64 | ||||
| 	ReadDir            uint64 | ||||
| 	ServerCaps         uint64 | ||||
| 	DelegReturn        uint64 | ||||
| 	GetACL             uint64 | ||||
| 	SetACL             uint64 | ||||
| 	FsLocations        uint64 | ||||
| 	ReleaseLockowner   uint64 | ||||
| 	Secinfo            uint64 | ||||
| 	FsidPresent        uint64 | ||||
| 	ExchangeID         uint64 | ||||
| 	CreateSession      uint64 | ||||
| 	DestroySession     uint64 | ||||
| 	Sequence           uint64 | ||||
| 	GetLeaseTime       uint64 | ||||
| 	ReclaimComplete    uint64 | ||||
| 	LayoutGet          uint64 | ||||
| 	GetDeviceInfo      uint64 | ||||
| 	LayoutCommit       uint64 | ||||
| 	LayoutReturn       uint64 | ||||
| 	SecinfoNoName      uint64 | ||||
| 	TestStateID        uint64 | ||||
| 	FreeStateID        uint64 | ||||
| 	GetDeviceList      uint64 | ||||
| 	BindConnToSession  uint64 | ||||
| 	DestroyClientID    uint64 | ||||
| 	Seek               uint64 | ||||
| 	Allocate           uint64 | ||||
| 	DeAllocate         uint64 | ||||
| 	LayoutStats        uint64 | ||||
| 	Clone              uint64 | ||||
| } | ||||
|  | ||||
| // ServerV4Stats models the nfsd "proc4" line. | ||||
| type ServerV4Stats struct { | ||||
| 	Null     uint64 | ||||
| 	Compound uint64 | ||||
| } | ||||
|  | ||||
| // V4Ops models the "proc4ops" line: NFSv4 operations | ||||
| // Variable list, see: | ||||
| // v4.0 https://tools.ietf.org/html/rfc3010 (38 operations) | ||||
| // v4.1 https://tools.ietf.org/html/rfc5661 (58 operations) | ||||
| // v4.2 https://tools.ietf.org/html/draft-ietf-nfsv4-minorversion2-41 (71 operations) | ||||
| type V4Ops struct { | ||||
| 	//Values       uint64 // Variable depending on v4.x sub-version. TODO: Will this always at least include the fields in this struct? | ||||
| 	Op0Unused    uint64 | ||||
| 	Op1Unused    uint64 | ||||
| 	Op2Future    uint64 | ||||
| 	Access       uint64 | ||||
| 	Close        uint64 | ||||
| 	Commit       uint64 | ||||
| 	Create       uint64 | ||||
| 	DelegPurge   uint64 | ||||
| 	DelegReturn  uint64 | ||||
| 	GetAttr      uint64 | ||||
| 	GetFH        uint64 | ||||
| 	Link         uint64 | ||||
| 	Lock         uint64 | ||||
| 	Lockt        uint64 | ||||
| 	Locku        uint64 | ||||
| 	Lookup       uint64 | ||||
| 	LookupRoot   uint64 | ||||
| 	Nverify      uint64 | ||||
| 	Open         uint64 | ||||
| 	OpenAttr     uint64 | ||||
| 	OpenConfirm  uint64 | ||||
| 	OpenDgrd     uint64 | ||||
| 	PutFH        uint64 | ||||
| 	PutPubFH     uint64 | ||||
| 	PutRootFH    uint64 | ||||
| 	Read         uint64 | ||||
| 	ReadDir      uint64 | ||||
| 	ReadLink     uint64 | ||||
| 	Remove       uint64 | ||||
| 	Rename       uint64 | ||||
| 	Renew        uint64 | ||||
| 	RestoreFH    uint64 | ||||
| 	SaveFH       uint64 | ||||
| 	SecInfo      uint64 | ||||
| 	SetAttr      uint64 | ||||
| 	Verify       uint64 | ||||
| 	Write        uint64 | ||||
| 	RelLockOwner uint64 | ||||
| } | ||||
|  | ||||
| // ClientRPCStats models all stats from /proc/net/rpc/nfs. | ||||
| type ClientRPCStats struct { | ||||
| 	Network       Network | ||||
| 	ClientRPC     ClientRPC | ||||
| 	V2Stats       V2Stats | ||||
| 	V3Stats       V3Stats | ||||
| 	ClientV4Stats ClientV4Stats | ||||
| } | ||||
|  | ||||
| // ServerRPCStats models all stats from /proc/net/rpc/nfsd. | ||||
| type ServerRPCStats struct { | ||||
| 	ReplyCache     ReplyCache | ||||
| 	FileHandles    FileHandles | ||||
| 	InputOutput    InputOutput | ||||
| 	Threads        Threads | ||||
| 	ReadAheadCache ReadAheadCache | ||||
| 	Network        Network | ||||
| 	ServerRPC      ServerRPC | ||||
| 	V2Stats        V2Stats | ||||
| 	V3Stats        V3Stats | ||||
| 	ServerV4Stats  ServerV4Stats | ||||
| 	V4Ops          V4Ops | ||||
| } | ||||
							
								
								
									
										317
									
								
								vendor/github.com/prometheus/procfs/nfs/parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										317
									
								
								vendor/github.com/prometheus/procfs/nfs/parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,317 @@ | ||||
| // Copyright 2018 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 nfs | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
|  | ||||
| func parseReplyCache(v []uint64) (ReplyCache, error) { | ||||
| 	if len(v) != 3 { | ||||
| 		return ReplyCache{}, fmt.Errorf("invalid ReplyCache line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	return ReplyCache{ | ||||
| 		Hits:    v[0], | ||||
| 		Misses:  v[1], | ||||
| 		NoCache: v[2], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseFileHandles(v []uint64) (FileHandles, error) { | ||||
| 	if len(v) != 5 { | ||||
| 		return FileHandles{}, fmt.Errorf("invalid FileHandles, line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	return FileHandles{ | ||||
| 		Stale:        v[0], | ||||
| 		TotalLookups: v[1], | ||||
| 		AnonLookups:  v[2], | ||||
| 		DirNoCache:   v[3], | ||||
| 		NoDirNoCache: v[4], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseInputOutput(v []uint64) (InputOutput, error) { | ||||
| 	if len(v) != 2 { | ||||
| 		return InputOutput{}, fmt.Errorf("invalid InputOutput line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	return InputOutput{ | ||||
| 		Read:  v[0], | ||||
| 		Write: v[1], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseThreads(v []uint64) (Threads, error) { | ||||
| 	if len(v) != 2 { | ||||
| 		return Threads{}, fmt.Errorf("invalid Threads line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	return Threads{ | ||||
| 		Threads: v[0], | ||||
| 		FullCnt: v[1], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseReadAheadCache(v []uint64) (ReadAheadCache, error) { | ||||
| 	if len(v) != 12 { | ||||
| 		return ReadAheadCache{}, fmt.Errorf("invalid ReadAheadCache line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	return ReadAheadCache{ | ||||
| 		CacheSize:      v[0], | ||||
| 		CacheHistogram: v[1:11], | ||||
| 		NotFound:       v[11], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseNetwork(v []uint64) (Network, error) { | ||||
| 	if len(v) != 4 { | ||||
| 		return Network{}, fmt.Errorf("invalid Network line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	return Network{ | ||||
| 		NetCount:   v[0], | ||||
| 		UDPCount:   v[1], | ||||
| 		TCPCount:   v[2], | ||||
| 		TCPConnect: v[3], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseServerRPC(v []uint64) (ServerRPC, error) { | ||||
| 	if len(v) != 5 { | ||||
| 		return ServerRPC{}, fmt.Errorf("invalid RPC line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	return ServerRPC{ | ||||
| 		RPCCount: v[0], | ||||
| 		BadCnt:   v[1], | ||||
| 		BadFmt:   v[2], | ||||
| 		BadAuth:  v[3], | ||||
| 		BadcInt:  v[4], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseClientRPC(v []uint64) (ClientRPC, error) { | ||||
| 	if len(v) != 3 { | ||||
| 		return ClientRPC{}, fmt.Errorf("invalid RPC line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	return ClientRPC{ | ||||
| 		RPCCount:        v[0], | ||||
| 		Retransmissions: v[1], | ||||
| 		AuthRefreshes:   v[2], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseV2Stats(v []uint64) (V2Stats, error) { | ||||
| 	values := int(v[0]) | ||||
| 	if len(v[1:]) != values || values != 18 { | ||||
| 		return V2Stats{}, fmt.Errorf("invalid V2Stats line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	return V2Stats{ | ||||
| 		Null:     v[1], | ||||
| 		GetAttr:  v[2], | ||||
| 		SetAttr:  v[3], | ||||
| 		Root:     v[4], | ||||
| 		Lookup:   v[5], | ||||
| 		ReadLink: v[6], | ||||
| 		Read:     v[7], | ||||
| 		WrCache:  v[8], | ||||
| 		Write:    v[9], | ||||
| 		Create:   v[10], | ||||
| 		Remove:   v[11], | ||||
| 		Rename:   v[12], | ||||
| 		Link:     v[13], | ||||
| 		SymLink:  v[14], | ||||
| 		MkDir:    v[15], | ||||
| 		RmDir:    v[16], | ||||
| 		ReadDir:  v[17], | ||||
| 		FsStat:   v[18], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseV3Stats(v []uint64) (V3Stats, error) { | ||||
| 	values := int(v[0]) | ||||
| 	if len(v[1:]) != values || values != 22 { | ||||
| 		return V3Stats{}, fmt.Errorf("invalid V3Stats line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	return V3Stats{ | ||||
| 		Null:        v[1], | ||||
| 		GetAttr:     v[2], | ||||
| 		SetAttr:     v[3], | ||||
| 		Lookup:      v[4], | ||||
| 		Access:      v[5], | ||||
| 		ReadLink:    v[6], | ||||
| 		Read:        v[7], | ||||
| 		Write:       v[8], | ||||
| 		Create:      v[9], | ||||
| 		MkDir:       v[10], | ||||
| 		SymLink:     v[11], | ||||
| 		MkNod:       v[12], | ||||
| 		Remove:      v[13], | ||||
| 		RmDir:       v[14], | ||||
| 		Rename:      v[15], | ||||
| 		Link:        v[16], | ||||
| 		ReadDir:     v[17], | ||||
| 		ReadDirPlus: v[18], | ||||
| 		FsStat:      v[19], | ||||
| 		FsInfo:      v[20], | ||||
| 		PathConf:    v[21], | ||||
| 		Commit:      v[22], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseClientV4Stats(v []uint64) (ClientV4Stats, error) { | ||||
| 	values := int(v[0]) | ||||
| 	if len(v[1:]) != values { | ||||
| 		return ClientV4Stats{}, fmt.Errorf("invalid ClientV4Stats line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	// This function currently supports mapping 59 NFS v4 client stats.  Older | ||||
| 	// kernels may emit fewer stats, so we must detect this and pad out the | ||||
| 	// values to match the expected slice size. | ||||
| 	if values < 59 { | ||||
| 		newValues := make([]uint64, 60) | ||||
| 		copy(newValues, v) | ||||
| 		v = newValues | ||||
| 	} | ||||
|  | ||||
| 	return ClientV4Stats{ | ||||
| 		Null:               v[1], | ||||
| 		Read:               v[2], | ||||
| 		Write:              v[3], | ||||
| 		Commit:             v[4], | ||||
| 		Open:               v[5], | ||||
| 		OpenConfirm:        v[6], | ||||
| 		OpenNoattr:         v[7], | ||||
| 		OpenDowngrade:      v[8], | ||||
| 		Close:              v[9], | ||||
| 		Setattr:            v[10], | ||||
| 		FsInfo:             v[11], | ||||
| 		Renew:              v[12], | ||||
| 		SetClientID:        v[13], | ||||
| 		SetClientIDConfirm: v[14], | ||||
| 		Lock:               v[15], | ||||
| 		Lockt:              v[16], | ||||
| 		Locku:              v[17], | ||||
| 		Access:             v[18], | ||||
| 		Getattr:            v[19], | ||||
| 		Lookup:             v[20], | ||||
| 		LookupRoot:         v[21], | ||||
| 		Remove:             v[22], | ||||
| 		Rename:             v[23], | ||||
| 		Link:               v[24], | ||||
| 		Symlink:            v[25], | ||||
| 		Create:             v[26], | ||||
| 		Pathconf:           v[27], | ||||
| 		StatFs:             v[28], | ||||
| 		ReadLink:           v[29], | ||||
| 		ReadDir:            v[30], | ||||
| 		ServerCaps:         v[31], | ||||
| 		DelegReturn:        v[32], | ||||
| 		GetACL:             v[33], | ||||
| 		SetACL:             v[34], | ||||
| 		FsLocations:        v[35], | ||||
| 		ReleaseLockowner:   v[36], | ||||
| 		Secinfo:            v[37], | ||||
| 		FsidPresent:        v[38], | ||||
| 		ExchangeID:         v[39], | ||||
| 		CreateSession:      v[40], | ||||
| 		DestroySession:     v[41], | ||||
| 		Sequence:           v[42], | ||||
| 		GetLeaseTime:       v[43], | ||||
| 		ReclaimComplete:    v[44], | ||||
| 		LayoutGet:          v[45], | ||||
| 		GetDeviceInfo:      v[46], | ||||
| 		LayoutCommit:       v[47], | ||||
| 		LayoutReturn:       v[48], | ||||
| 		SecinfoNoName:      v[49], | ||||
| 		TestStateID:        v[50], | ||||
| 		FreeStateID:        v[51], | ||||
| 		GetDeviceList:      v[52], | ||||
| 		BindConnToSession:  v[53], | ||||
| 		DestroyClientID:    v[54], | ||||
| 		Seek:               v[55], | ||||
| 		Allocate:           v[56], | ||||
| 		DeAllocate:         v[57], | ||||
| 		LayoutStats:        v[58], | ||||
| 		Clone:              v[59], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseServerV4Stats(v []uint64) (ServerV4Stats, error) { | ||||
| 	values := int(v[0]) | ||||
| 	if len(v[1:]) != values || values != 2 { | ||||
| 		return ServerV4Stats{}, fmt.Errorf("invalid V4Stats line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	return ServerV4Stats{ | ||||
| 		Null:     v[1], | ||||
| 		Compound: v[2], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func parseV4Ops(v []uint64) (V4Ops, error) { | ||||
| 	values := int(v[0]) | ||||
| 	if len(v[1:]) != values || values < 39 { | ||||
| 		return V4Ops{}, fmt.Errorf("invalid V4Ops line %q", v) | ||||
| 	} | ||||
|  | ||||
| 	stats := V4Ops{ | ||||
| 		Op0Unused:    v[1], | ||||
| 		Op1Unused:    v[2], | ||||
| 		Op2Future:    v[3], | ||||
| 		Access:       v[4], | ||||
| 		Close:        v[5], | ||||
| 		Commit:       v[6], | ||||
| 		Create:       v[7], | ||||
| 		DelegPurge:   v[8], | ||||
| 		DelegReturn:  v[9], | ||||
| 		GetAttr:      v[10], | ||||
| 		GetFH:        v[11], | ||||
| 		Link:         v[12], | ||||
| 		Lock:         v[13], | ||||
| 		Lockt:        v[14], | ||||
| 		Locku:        v[15], | ||||
| 		Lookup:       v[16], | ||||
| 		LookupRoot:   v[17], | ||||
| 		Nverify:      v[18], | ||||
| 		Open:         v[19], | ||||
| 		OpenAttr:     v[20], | ||||
| 		OpenConfirm:  v[21], | ||||
| 		OpenDgrd:     v[22], | ||||
| 		PutFH:        v[23], | ||||
| 		PutPubFH:     v[24], | ||||
| 		PutRootFH:    v[25], | ||||
| 		Read:         v[26], | ||||
| 		ReadDir:      v[27], | ||||
| 		ReadLink:     v[28], | ||||
| 		Remove:       v[29], | ||||
| 		Rename:       v[30], | ||||
| 		Renew:        v[31], | ||||
| 		RestoreFH:    v[32], | ||||
| 		SaveFH:       v[33], | ||||
| 		SecInfo:      v[34], | ||||
| 		SetAttr:      v[35], | ||||
| 		Verify:       v[36], | ||||
| 		Write:        v[37], | ||||
| 		RelLockOwner: v[38], | ||||
| 	} | ||||
|  | ||||
| 	return stats, nil | ||||
| } | ||||
							
								
								
									
										67
									
								
								vendor/github.com/prometheus/procfs/nfs/parse_nfs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								vendor/github.com/prometheus/procfs/nfs/parse_nfs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| // Copyright 2018 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 nfs | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/prometheus/procfs/internal/util" | ||||
| ) | ||||
|  | ||||
| // ParseClientRPCStats returns stats read from /proc/net/rpc/nfs | ||||
| func ParseClientRPCStats(r io.Reader) (*ClientRPCStats, error) { | ||||
| 	stats := &ClientRPCStats{} | ||||
|  | ||||
| 	scanner := bufio.NewScanner(r) | ||||
| 	for scanner.Scan() { | ||||
| 		line := scanner.Text() | ||||
| 		parts := strings.Fields(scanner.Text()) | ||||
| 		// require at least <key> <value> | ||||
| 		if len(parts) < 2 { | ||||
| 			return nil, fmt.Errorf("invalid NFS metric line %q", line) | ||||
| 		} | ||||
|  | ||||
| 		values, err := util.ParseUint64s(parts[1:]) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("error parsing NFS metric line: %s", err) | ||||
| 		} | ||||
|  | ||||
| 		switch metricLine := parts[0]; metricLine { | ||||
| 		case "net": | ||||
| 			stats.Network, err = parseNetwork(values) | ||||
| 		case "rpc": | ||||
| 			stats.ClientRPC, err = parseClientRPC(values) | ||||
| 		case "proc2": | ||||
| 			stats.V2Stats, err = parseV2Stats(values) | ||||
| 		case "proc3": | ||||
| 			stats.V3Stats, err = parseV3Stats(values) | ||||
| 		case "proc4": | ||||
| 			stats.ClientV4Stats, err = parseClientV4Stats(values) | ||||
| 		default: | ||||
| 			return nil, fmt.Errorf("unknown NFS metric line %q", metricLine) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("errors parsing NFS metric line: %s", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := scanner.Err(); err != nil { | ||||
| 		return nil, fmt.Errorf("error scanning NFS file: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	return stats, nil | ||||
| } | ||||
							
								
								
									
										89
									
								
								vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | ||||
| // Copyright 2018 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 nfs | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/prometheus/procfs/internal/util" | ||||
| ) | ||||
|  | ||||
| // ParseServerRPCStats returns stats read from /proc/net/rpc/nfsd | ||||
| func ParseServerRPCStats(r io.Reader) (*ServerRPCStats, error) { | ||||
| 	stats := &ServerRPCStats{} | ||||
|  | ||||
| 	scanner := bufio.NewScanner(r) | ||||
| 	for scanner.Scan() { | ||||
| 		line := scanner.Text() | ||||
| 		parts := strings.Fields(scanner.Text()) | ||||
| 		// require at least <key> <value> | ||||
| 		if len(parts) < 2 { | ||||
| 			return nil, fmt.Errorf("invalid NFSd metric line %q", line) | ||||
| 		} | ||||
| 		label := parts[0] | ||||
|  | ||||
| 		var values []uint64 | ||||
| 		var err error | ||||
| 		if label == "th" { | ||||
| 			if len(parts) < 3 { | ||||
| 				return nil, fmt.Errorf("invalid NFSd th metric line %q", line) | ||||
| 			} | ||||
| 			values, err = util.ParseUint64s(parts[1:3]) | ||||
| 		} else { | ||||
| 			values, err = util.ParseUint64s(parts[1:]) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("error parsing NFSd metric line: %s", err) | ||||
| 		} | ||||
|  | ||||
| 		switch metricLine := parts[0]; metricLine { | ||||
| 		case "rc": | ||||
| 			stats.ReplyCache, err = parseReplyCache(values) | ||||
| 		case "fh": | ||||
| 			stats.FileHandles, err = parseFileHandles(values) | ||||
| 		case "io": | ||||
| 			stats.InputOutput, err = parseInputOutput(values) | ||||
| 		case "th": | ||||
| 			stats.Threads, err = parseThreads(values) | ||||
| 		case "ra": | ||||
| 			stats.ReadAheadCache, err = parseReadAheadCache(values) | ||||
| 		case "net": | ||||
| 			stats.Network, err = parseNetwork(values) | ||||
| 		case "rpc": | ||||
| 			stats.ServerRPC, err = parseServerRPC(values) | ||||
| 		case "proc2": | ||||
| 			stats.V2Stats, err = parseV2Stats(values) | ||||
| 		case "proc3": | ||||
| 			stats.V3Stats, err = parseV3Stats(values) | ||||
| 		case "proc4": | ||||
| 			stats.ServerV4Stats, err = parseServerV4Stats(values) | ||||
| 		case "proc4ops": | ||||
| 			stats.V4Ops, err = parseV4Ops(values) | ||||
| 		default: | ||||
| 			return nil, fmt.Errorf("unknown NFSd metric line %q", metricLine) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("errors parsing NFSd metric line: %s", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := scanner.Err(); err != nil { | ||||
| 		return nil, fmt.Errorf("error scanning NFSd file: %s", err) | ||||
| 	} | ||||
|  | ||||
| 	return stats, nil | ||||
| } | ||||
							
								
								
									
										258
									
								
								vendor/github.com/prometheus/procfs/proc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								vendor/github.com/prometheus/procfs/proc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,258 @@ | ||||
| // Copyright 2018 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 procfs | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // Proc provides information about a running process. | ||||
| type Proc struct { | ||||
| 	// The process ID. | ||||
| 	PID int | ||||
|  | ||||
| 	fs FS | ||||
| } | ||||
|  | ||||
| // Procs represents a list of Proc structs. | ||||
| type Procs []Proc | ||||
|  | ||||
| func (p Procs) Len() int           { return len(p) } | ||||
| func (p Procs) Swap(i, j int)      { p[i], p[j] = p[j], p[i] } | ||||
| func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID } | ||||
|  | ||||
| // Self returns a process for the current process read via /proc/self. | ||||
| func Self() (Proc, error) { | ||||
| 	fs, err := NewFS(DefaultMountPoint) | ||||
| 	if err != nil { | ||||
| 		return Proc{}, err | ||||
| 	} | ||||
| 	return fs.Self() | ||||
| } | ||||
|  | ||||
| // NewProc returns a process for the given pid under /proc. | ||||
| func NewProc(pid int) (Proc, error) { | ||||
| 	fs, err := NewFS(DefaultMountPoint) | ||||
| 	if err != nil { | ||||
| 		return Proc{}, err | ||||
| 	} | ||||
| 	return fs.NewProc(pid) | ||||
| } | ||||
|  | ||||
| // AllProcs returns a list of all currently available processes under /proc. | ||||
| func AllProcs() (Procs, error) { | ||||
| 	fs, err := NewFS(DefaultMountPoint) | ||||
| 	if err != nil { | ||||
| 		return Procs{}, err | ||||
| 	} | ||||
| 	return fs.AllProcs() | ||||
| } | ||||
|  | ||||
| // Self returns a process for the current process. | ||||
| func (fs FS) Self() (Proc, error) { | ||||
| 	p, err := os.Readlink(fs.Path("self")) | ||||
| 	if err != nil { | ||||
| 		return Proc{}, err | ||||
| 	} | ||||
| 	pid, err := strconv.Atoi(strings.Replace(p, string(fs), "", -1)) | ||||
| 	if err != nil { | ||||
| 		return Proc{}, err | ||||
| 	} | ||||
| 	return fs.NewProc(pid) | ||||
| } | ||||
|  | ||||
| // NewProc returns a process for the given pid. | ||||
| func (fs FS) NewProc(pid int) (Proc, error) { | ||||
| 	if _, err := os.Stat(fs.Path(strconv.Itoa(pid))); err != nil { | ||||
| 		return Proc{}, err | ||||
| 	} | ||||
| 	return Proc{PID: pid, fs: fs}, nil | ||||
| } | ||||
|  | ||||
| // AllProcs returns a list of all currently available processes. | ||||
| func (fs FS) AllProcs() (Procs, error) { | ||||
| 	d, err := os.Open(fs.Path()) | ||||
| 	if err != nil { | ||||
| 		return Procs{}, err | ||||
| 	} | ||||
| 	defer d.Close() | ||||
|  | ||||
| 	names, err := d.Readdirnames(-1) | ||||
| 	if err != nil { | ||||
| 		return Procs{}, fmt.Errorf("could not read %s: %s", d.Name(), err) | ||||
| 	} | ||||
|  | ||||
| 	p := Procs{} | ||||
| 	for _, n := range names { | ||||
| 		pid, err := strconv.ParseInt(n, 10, 64) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		p = append(p, Proc{PID: int(pid), fs: fs}) | ||||
| 	} | ||||
|  | ||||
| 	return p, nil | ||||
| } | ||||
|  | ||||
| // CmdLine returns the command line of a process. | ||||
| func (p Proc) CmdLine() ([]string, error) { | ||||
| 	f, err := os.Open(p.path("cmdline")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	data, err := ioutil.ReadAll(f) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if len(data) < 1 { | ||||
| 		return []string{}, nil | ||||
| 	} | ||||
|  | ||||
| 	return strings.Split(string(bytes.TrimRight(data, string("\x00"))), string(byte(0))), nil | ||||
| } | ||||
|  | ||||
| // Comm returns the command name of a process. | ||||
| func (p Proc) Comm() (string, error) { | ||||
| 	f, err := os.Open(p.path("comm")) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	data, err := ioutil.ReadAll(f) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	return strings.TrimSpace(string(data)), nil | ||||
| } | ||||
|  | ||||
| // Executable returns the absolute path of the executable command of a process. | ||||
| func (p Proc) Executable() (string, error) { | ||||
| 	exe, err := os.Readlink(p.path("exe")) | ||||
| 	if os.IsNotExist(err) { | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	return exe, err | ||||
| } | ||||
|  | ||||
| // Cwd returns the absolute path to the current working directory of the process. | ||||
| func (p Proc) Cwd() (string, error) { | ||||
| 	wd, err := os.Readlink(p.path("cwd")) | ||||
| 	if os.IsNotExist(err) { | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	return wd, err | ||||
| } | ||||
|  | ||||
| // RootDir returns the absolute path to the process's root directory (as set by chroot) | ||||
| func (p Proc) RootDir() (string, error) { | ||||
| 	rdir, err := os.Readlink(p.path("root")) | ||||
| 	if os.IsNotExist(err) { | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	return rdir, err | ||||
| } | ||||
|  | ||||
| // FileDescriptors returns the currently open file descriptors of a process. | ||||
| func (p Proc) FileDescriptors() ([]uintptr, error) { | ||||
| 	names, err := p.fileDescriptors() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	fds := make([]uintptr, len(names)) | ||||
| 	for i, n := range names { | ||||
| 		fd, err := strconv.ParseInt(n, 10, 32) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("could not parse fd %s: %s", n, err) | ||||
| 		} | ||||
| 		fds[i] = uintptr(fd) | ||||
| 	} | ||||
|  | ||||
| 	return fds, nil | ||||
| } | ||||
|  | ||||
| // FileDescriptorTargets returns the targets of all file descriptors of a process. | ||||
| // If a file descriptor is not a symlink to a file (like a socket), that value will be the empty string. | ||||
| func (p Proc) FileDescriptorTargets() ([]string, error) { | ||||
| 	names, err := p.fileDescriptors() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	targets := make([]string, len(names)) | ||||
|  | ||||
| 	for i, name := range names { | ||||
| 		target, err := os.Readlink(p.path("fd", name)) | ||||
| 		if err == nil { | ||||
| 			targets[i] = target | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return targets, nil | ||||
| } | ||||
|  | ||||
| // FileDescriptorsLen returns the number of currently open file descriptors of | ||||
| // a process. | ||||
| func (p Proc) FileDescriptorsLen() (int, error) { | ||||
| 	fds, err := p.fileDescriptors() | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 	return len(fds), nil | ||||
| } | ||||
|  | ||||
| // MountStats retrieves statistics and configuration for mount points in a | ||||
| // process's namespace. | ||||
| func (p Proc) MountStats() ([]*Mount, error) { | ||||
| 	f, err := os.Open(p.path("mountstats")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	return parseMountStats(f) | ||||
| } | ||||
|  | ||||
| func (p Proc) fileDescriptors() ([]string, error) { | ||||
| 	d, err := os.Open(p.path("fd")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer d.Close() | ||||
|  | ||||
| 	names, err := d.Readdirnames(-1) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("could not read %s: %s", d.Name(), err) | ||||
| 	} | ||||
|  | ||||
| 	return names, nil | ||||
| } | ||||
|  | ||||
| func (p Proc) path(pa ...string) string { | ||||
| 	return p.fs.Path(append([]string{strconv.Itoa(p.PID)}, pa...)...) | ||||
| } | ||||
							
								
								
									
										65
									
								
								vendor/github.com/prometheus/procfs/proc_io.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/prometheus/procfs/proc_io.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| // Copyright 2018 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 procfs | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| ) | ||||
|  | ||||
| // ProcIO models the content of /proc/<pid>/io. | ||||
| type ProcIO struct { | ||||
| 	// Chars read. | ||||
| 	RChar uint64 | ||||
| 	// Chars written. | ||||
| 	WChar uint64 | ||||
| 	// Read syscalls. | ||||
| 	SyscR uint64 | ||||
| 	// Write syscalls. | ||||
| 	SyscW uint64 | ||||
| 	// Bytes read. | ||||
| 	ReadBytes uint64 | ||||
| 	// Bytes written. | ||||
| 	WriteBytes uint64 | ||||
| 	// Bytes written, but taking into account truncation. See | ||||
| 	// Documentation/filesystems/proc.txt in the kernel sources for | ||||
| 	// detailed explanation. | ||||
| 	CancelledWriteBytes int64 | ||||
| } | ||||
|  | ||||
| // NewIO creates a new ProcIO instance from a given Proc instance. | ||||
| func (p Proc) NewIO() (ProcIO, error) { | ||||
| 	pio := ProcIO{} | ||||
|  | ||||
| 	f, err := os.Open(p.path("io")) | ||||
| 	if err != nil { | ||||
| 		return pio, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	data, err := ioutil.ReadAll(f) | ||||
| 	if err != nil { | ||||
| 		return pio, err | ||||
| 	} | ||||
|  | ||||
| 	ioFormat := "rchar: %d\nwchar: %d\nsyscr: %d\nsyscw: %d\n" + | ||||
| 		"read_bytes: %d\nwrite_bytes: %d\n" + | ||||
| 		"cancelled_write_bytes: %d\n" | ||||
|  | ||||
| 	_, err = fmt.Sscanf(string(data), ioFormat, &pio.RChar, &pio.WChar, &pio.SyscR, | ||||
| 		&pio.SyscW, &pio.ReadBytes, &pio.WriteBytes, &pio.CancelledWriteBytes) | ||||
|  | ||||
| 	return pio, err | ||||
| } | ||||
							
								
								
									
										150
									
								
								vendor/github.com/prometheus/procfs/proc_limits.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								vendor/github.com/prometheus/procfs/proc_limits.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | ||||
| // Copyright 2018 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 procfs | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // ProcLimits represents the soft limits for each of the process's resource | ||||
| // limits. For more information see getrlimit(2): | ||||
| // http://man7.org/linux/man-pages/man2/getrlimit.2.html. | ||||
| type ProcLimits struct { | ||||
| 	// CPU time limit in seconds. | ||||
| 	CPUTime int64 | ||||
| 	// Maximum size of files that the process may create. | ||||
| 	FileSize int64 | ||||
| 	// Maximum size of the process's data segment (initialized data, | ||||
| 	// uninitialized data, and heap). | ||||
| 	DataSize int64 | ||||
| 	// Maximum size of the process stack in bytes. | ||||
| 	StackSize int64 | ||||
| 	// Maximum size of a core file. | ||||
| 	CoreFileSize int64 | ||||
| 	// Limit of the process's resident set in pages. | ||||
| 	ResidentSet int64 | ||||
| 	// Maximum number of processes that can be created for the real user ID of | ||||
| 	// the calling process. | ||||
| 	Processes int64 | ||||
| 	// Value one greater than the maximum file descriptor number that can be | ||||
| 	// opened by this process. | ||||
| 	OpenFiles int64 | ||||
| 	// Maximum number of bytes of memory that may be locked into RAM. | ||||
| 	LockedMemory int64 | ||||
| 	// Maximum size of the process's virtual memory address space in bytes. | ||||
| 	AddressSpace int64 | ||||
| 	// Limit on the combined number of flock(2) locks and fcntl(2) leases that | ||||
| 	// this process may establish. | ||||
| 	FileLocks int64 | ||||
| 	// Limit of signals that may be queued for the real user ID of the calling | ||||
| 	// process. | ||||
| 	PendingSignals int64 | ||||
| 	// Limit on the number of bytes that can be allocated for POSIX message | ||||
| 	// queues for the real user ID of the calling process. | ||||
| 	MsqqueueSize int64 | ||||
| 	// Limit of the nice priority set using setpriority(2) or nice(2). | ||||
| 	NicePriority int64 | ||||
| 	// Limit of the real-time priority set using sched_setscheduler(2) or | ||||
| 	// sched_setparam(2). | ||||
| 	RealtimePriority int64 | ||||
| 	// Limit (in microseconds) on the amount of CPU time that a process | ||||
| 	// scheduled under a real-time scheduling policy may consume without making | ||||
| 	// a blocking system call. | ||||
| 	RealtimeTimeout int64 | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	limitsFields    = 3 | ||||
| 	limitsUnlimited = "unlimited" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	limitsDelimiter = regexp.MustCompile("  +") | ||||
| ) | ||||
|  | ||||
| // NewLimits returns the current soft limits of the process. | ||||
| func (p Proc) NewLimits() (ProcLimits, error) { | ||||
| 	f, err := os.Open(p.path("limits")) | ||||
| 	if err != nil { | ||||
| 		return ProcLimits{}, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	var ( | ||||
| 		l = ProcLimits{} | ||||
| 		s = bufio.NewScanner(f) | ||||
| 	) | ||||
| 	for s.Scan() { | ||||
| 		fields := limitsDelimiter.Split(s.Text(), limitsFields) | ||||
| 		if len(fields) != limitsFields { | ||||
| 			return ProcLimits{}, fmt.Errorf( | ||||
| 				"couldn't parse %s line %s", f.Name(), s.Text()) | ||||
| 		} | ||||
|  | ||||
| 		switch fields[0] { | ||||
| 		case "Max cpu time": | ||||
| 			l.CPUTime, err = parseInt(fields[1]) | ||||
| 		case "Max file size": | ||||
| 			l.FileSize, err = parseInt(fields[1]) | ||||
| 		case "Max data size": | ||||
| 			l.DataSize, err = parseInt(fields[1]) | ||||
| 		case "Max stack size": | ||||
| 			l.StackSize, err = parseInt(fields[1]) | ||||
| 		case "Max core file size": | ||||
| 			l.CoreFileSize, err = parseInt(fields[1]) | ||||
| 		case "Max resident set": | ||||
| 			l.ResidentSet, err = parseInt(fields[1]) | ||||
| 		case "Max processes": | ||||
| 			l.Processes, err = parseInt(fields[1]) | ||||
| 		case "Max open files": | ||||
| 			l.OpenFiles, err = parseInt(fields[1]) | ||||
| 		case "Max locked memory": | ||||
| 			l.LockedMemory, err = parseInt(fields[1]) | ||||
| 		case "Max address space": | ||||
| 			l.AddressSpace, err = parseInt(fields[1]) | ||||
| 		case "Max file locks": | ||||
| 			l.FileLocks, err = parseInt(fields[1]) | ||||
| 		case "Max pending signals": | ||||
| 			l.PendingSignals, err = parseInt(fields[1]) | ||||
| 		case "Max msgqueue size": | ||||
| 			l.MsqqueueSize, err = parseInt(fields[1]) | ||||
| 		case "Max nice priority": | ||||
| 			l.NicePriority, err = parseInt(fields[1]) | ||||
| 		case "Max realtime priority": | ||||
| 			l.RealtimePriority, err = parseInt(fields[1]) | ||||
| 		case "Max realtime timeout": | ||||
| 			l.RealtimeTimeout, err = parseInt(fields[1]) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return ProcLimits{}, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return l, s.Err() | ||||
| } | ||||
|  | ||||
| func parseInt(s string) (int64, error) { | ||||
| 	if s == limitsUnlimited { | ||||
| 		return -1, nil | ||||
| 	} | ||||
| 	i, err := strconv.ParseInt(s, 10, 64) | ||||
| 	if err != nil { | ||||
| 		return 0, fmt.Errorf("couldn't parse value %s: %s", s, err) | ||||
| 	} | ||||
| 	return i, nil | ||||
| } | ||||
							
								
								
									
										68
									
								
								vendor/github.com/prometheus/procfs/proc_ns.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								vendor/github.com/prometheus/procfs/proc_ns.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| // Copyright 2018 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 procfs | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // Namespace represents a single namespace of a process. | ||||
| type Namespace struct { | ||||
| 	Type  string // Namespace type. | ||||
| 	Inode uint32 // Inode number of the namespace. If two processes are in the same namespace their inodes will match. | ||||
| } | ||||
|  | ||||
| // Namespaces contains all of the namespaces that the process is contained in. | ||||
| type Namespaces map[string]Namespace | ||||
|  | ||||
| // NewNamespaces reads from /proc/[pid/ns/* to get the namespaces of which the | ||||
| // process is a member. | ||||
| func (p Proc) NewNamespaces() (Namespaces, error) { | ||||
| 	d, err := os.Open(p.path("ns")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer d.Close() | ||||
|  | ||||
| 	names, err := d.Readdirnames(-1) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to read contents of ns dir: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	ns := make(Namespaces, len(names)) | ||||
| 	for _, name := range names { | ||||
| 		target, err := os.Readlink(p.path("ns", name)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		fields := strings.SplitN(target, ":", 2) | ||||
| 		if len(fields) != 2 { | ||||
| 			return nil, fmt.Errorf("failed to parse namespace type and inode from '%v'", target) | ||||
| 		} | ||||
|  | ||||
| 		typ := fields[0] | ||||
| 		inode, err := strconv.ParseUint(strings.Trim(fields[1], "[]"), 10, 32) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("failed to parse inode from '%v': %v", fields[1], err) | ||||
| 		} | ||||
|  | ||||
| 		ns[name] = Namespace{typ, uint32(inode)} | ||||
| 	} | ||||
|  | ||||
| 	return ns, nil | ||||
| } | ||||
							
								
								
									
										188
									
								
								vendor/github.com/prometheus/procfs/proc_stat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								vendor/github.com/prometheus/procfs/proc_stat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,188 @@ | ||||
| // Copyright 2018 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 procfs | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| ) | ||||
|  | ||||
| // Originally, this USER_HZ value was dynamically retrieved via a sysconf call | ||||
| // which required cgo. However, that caused a lot of problems regarding | ||||
| // cross-compilation. Alternatives such as running a binary to determine the | ||||
| // value, or trying to derive it in some other way were all problematic.  After | ||||
| // much research it was determined that USER_HZ is actually hardcoded to 100 on | ||||
| // all Go-supported platforms as of the time of this writing. This is why we | ||||
| // decided to hardcode it here as well. It is not impossible that there could | ||||
| // be systems with exceptions, but they should be very exotic edge cases, and | ||||
| // in that case, the worst outcome will be two misreported metrics. | ||||
| // | ||||
| // See also the following discussions: | ||||
| // | ||||
| // - https://github.com/prometheus/node_exporter/issues/52 | ||||
| // - https://github.com/prometheus/procfs/pull/2 | ||||
| // - http://stackoverflow.com/questions/17410841/how-does-user-hz-solve-the-jiffy-scaling-issue | ||||
| const userHZ = 100 | ||||
|  | ||||
| // ProcStat provides status information about the process, | ||||
| // read from /proc/[pid]/stat. | ||||
| type ProcStat struct { | ||||
| 	// The process ID. | ||||
| 	PID int | ||||
| 	// The filename of the executable. | ||||
| 	Comm string | ||||
| 	// The process state. | ||||
| 	State string | ||||
| 	// The PID of the parent of this process. | ||||
| 	PPID int | ||||
| 	// The process group ID of the process. | ||||
| 	PGRP int | ||||
| 	// The session ID of the process. | ||||
| 	Session int | ||||
| 	// The controlling terminal of the process. | ||||
| 	TTY int | ||||
| 	// The ID of the foreground process group of the controlling terminal of | ||||
| 	// the process. | ||||
| 	TPGID int | ||||
| 	// The kernel flags word of the process. | ||||
| 	Flags uint | ||||
| 	// The number of minor faults the process has made which have not required | ||||
| 	// loading a memory page from disk. | ||||
| 	MinFlt uint | ||||
| 	// The number of minor faults that the process's waited-for children have | ||||
| 	// made. | ||||
| 	CMinFlt uint | ||||
| 	// The number of major faults the process has made which have required | ||||
| 	// loading a memory page from disk. | ||||
| 	MajFlt uint | ||||
| 	// The number of major faults that the process's waited-for children have | ||||
| 	// made. | ||||
| 	CMajFlt uint | ||||
| 	// Amount of time that this process has been scheduled in user mode, | ||||
| 	// measured in clock ticks. | ||||
| 	UTime uint | ||||
| 	// Amount of time that this process has been scheduled in kernel mode, | ||||
| 	// measured in clock ticks. | ||||
| 	STime uint | ||||
| 	// Amount of time that this process's waited-for children have been | ||||
| 	// scheduled in user mode, measured in clock ticks. | ||||
| 	CUTime uint | ||||
| 	// Amount of time that this process's waited-for children have been | ||||
| 	// scheduled in kernel mode, measured in clock ticks. | ||||
| 	CSTime uint | ||||
| 	// For processes running a real-time scheduling policy, this is the negated | ||||
| 	// scheduling priority, minus one. | ||||
| 	Priority int | ||||
| 	// The nice value, a value in the range 19 (low priority) to -20 (high | ||||
| 	// priority). | ||||
| 	Nice int | ||||
| 	// Number of threads in this process. | ||||
| 	NumThreads int | ||||
| 	// The time the process started after system boot, the value is expressed | ||||
| 	// in clock ticks. | ||||
| 	Starttime uint64 | ||||
| 	// Virtual memory size in bytes. | ||||
| 	VSize int | ||||
| 	// Resident set size in pages. | ||||
| 	RSS int | ||||
|  | ||||
| 	fs FS | ||||
| } | ||||
|  | ||||
| // NewStat returns the current status information of the process. | ||||
| func (p Proc) NewStat() (ProcStat, error) { | ||||
| 	f, err := os.Open(p.path("stat")) | ||||
| 	if err != nil { | ||||
| 		return ProcStat{}, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	data, err := ioutil.ReadAll(f) | ||||
| 	if err != nil { | ||||
| 		return ProcStat{}, err | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		ignore int | ||||
|  | ||||
| 		s = ProcStat{PID: p.PID, fs: p.fs} | ||||
| 		l = bytes.Index(data, []byte("(")) | ||||
| 		r = bytes.LastIndex(data, []byte(")")) | ||||
| 	) | ||||
|  | ||||
| 	if l < 0 || r < 0 { | ||||
| 		return ProcStat{}, fmt.Errorf( | ||||
| 			"unexpected format, couldn't extract comm: %s", | ||||
| 			data, | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	s.Comm = string(data[l+1 : r]) | ||||
| 	_, err = fmt.Fscan( | ||||
| 		bytes.NewBuffer(data[r+2:]), | ||||
| 		&s.State, | ||||
| 		&s.PPID, | ||||
| 		&s.PGRP, | ||||
| 		&s.Session, | ||||
| 		&s.TTY, | ||||
| 		&s.TPGID, | ||||
| 		&s.Flags, | ||||
| 		&s.MinFlt, | ||||
| 		&s.CMinFlt, | ||||
| 		&s.MajFlt, | ||||
| 		&s.CMajFlt, | ||||
| 		&s.UTime, | ||||
| 		&s.STime, | ||||
| 		&s.CUTime, | ||||
| 		&s.CSTime, | ||||
| 		&s.Priority, | ||||
| 		&s.Nice, | ||||
| 		&s.NumThreads, | ||||
| 		&ignore, | ||||
| 		&s.Starttime, | ||||
| 		&s.VSize, | ||||
| 		&s.RSS, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return ProcStat{}, err | ||||
| 	} | ||||
|  | ||||
| 	return s, nil | ||||
| } | ||||
|  | ||||
| // VirtualMemory returns the virtual memory size in bytes. | ||||
| func (s ProcStat) VirtualMemory() int { | ||||
| 	return s.VSize | ||||
| } | ||||
|  | ||||
| // ResidentMemory returns the resident memory size in bytes. | ||||
| func (s ProcStat) ResidentMemory() int { | ||||
| 	return s.RSS * os.Getpagesize() | ||||
| } | ||||
|  | ||||
| // StartTime returns the unix timestamp of the process in seconds. | ||||
| func (s ProcStat) StartTime() (float64, error) { | ||||
| 	stat, err := s.fs.NewStat() | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return float64(stat.BootTime) + (float64(s.Starttime) / userHZ), nil | ||||
| } | ||||
|  | ||||
| // CPUTime returns the total CPU user and system time in seconds. | ||||
| func (s ProcStat) CPUTime() float64 { | ||||
| 	return float64(s.UTime+s.STime) / userHZ | ||||
| } | ||||
							
								
								
									
										232
									
								
								vendor/github.com/prometheus/procfs/stat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								vendor/github.com/prometheus/procfs/stat.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,232 @@ | ||||
| // Copyright 2018 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 procfs | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // CPUStat shows how much time the cpu spend in various stages. | ||||
| type CPUStat struct { | ||||
| 	User      float64 | ||||
| 	Nice      float64 | ||||
| 	System    float64 | ||||
| 	Idle      float64 | ||||
| 	Iowait    float64 | ||||
| 	IRQ       float64 | ||||
| 	SoftIRQ   float64 | ||||
| 	Steal     float64 | ||||
| 	Guest     float64 | ||||
| 	GuestNice float64 | ||||
| } | ||||
|  | ||||
| // SoftIRQStat represent the softirq statistics as exported in the procfs stat file. | ||||
| // A nice introduction can be found at https://0xax.gitbooks.io/linux-insides/content/interrupts/interrupts-9.html | ||||
| // It is possible to get per-cpu stats by reading /proc/softirqs | ||||
| type SoftIRQStat struct { | ||||
| 	Hi          uint64 | ||||
| 	Timer       uint64 | ||||
| 	NetTx       uint64 | ||||
| 	NetRx       uint64 | ||||
| 	Block       uint64 | ||||
| 	BlockIoPoll uint64 | ||||
| 	Tasklet     uint64 | ||||
| 	Sched       uint64 | ||||
| 	Hrtimer     uint64 | ||||
| 	Rcu         uint64 | ||||
| } | ||||
|  | ||||
| // Stat represents kernel/system statistics. | ||||
| type Stat struct { | ||||
| 	// Boot time in seconds since the Epoch. | ||||
| 	BootTime uint64 | ||||
| 	// Summed up cpu statistics. | ||||
| 	CPUTotal CPUStat | ||||
| 	// Per-CPU statistics. | ||||
| 	CPU []CPUStat | ||||
| 	// Number of times interrupts were handled, which contains numbered and unnumbered IRQs. | ||||
| 	IRQTotal uint64 | ||||
| 	// Number of times a numbered IRQ was triggered. | ||||
| 	IRQ []uint64 | ||||
| 	// Number of times a context switch happened. | ||||
| 	ContextSwitches uint64 | ||||
| 	// Number of times a process was created. | ||||
| 	ProcessCreated uint64 | ||||
| 	// Number of processes currently running. | ||||
| 	ProcessesRunning uint64 | ||||
| 	// Number of processes currently blocked (waiting for IO). | ||||
| 	ProcessesBlocked uint64 | ||||
| 	// Number of times a softirq was scheduled. | ||||
| 	SoftIRQTotal uint64 | ||||
| 	// Detailed softirq statistics. | ||||
| 	SoftIRQ SoftIRQStat | ||||
| } | ||||
|  | ||||
| // NewStat returns kernel/system statistics read from /proc/stat. | ||||
| func NewStat() (Stat, error) { | ||||
| 	fs, err := NewFS(DefaultMountPoint) | ||||
| 	if err != nil { | ||||
| 		return Stat{}, err | ||||
| 	} | ||||
|  | ||||
| 	return fs.NewStat() | ||||
| } | ||||
|  | ||||
| // Parse a cpu statistics line and returns the CPUStat struct plus the cpu id (or -1 for the overall sum). | ||||
| func parseCPUStat(line string) (CPUStat, int64, error) { | ||||
| 	cpuStat := CPUStat{} | ||||
| 	var cpu string | ||||
|  | ||||
| 	count, err := fmt.Sscanf(line, "%s %f %f %f %f %f %f %f %f %f %f", | ||||
| 		&cpu, | ||||
| 		&cpuStat.User, &cpuStat.Nice, &cpuStat.System, &cpuStat.Idle, | ||||
| 		&cpuStat.Iowait, &cpuStat.IRQ, &cpuStat.SoftIRQ, &cpuStat.Steal, | ||||
| 		&cpuStat.Guest, &cpuStat.GuestNice) | ||||
|  | ||||
| 	if err != nil && err != io.EOF { | ||||
| 		return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): %s", line, err) | ||||
| 	} | ||||
| 	if count == 0 { | ||||
| 		return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu): 0 elements parsed", line) | ||||
| 	} | ||||
|  | ||||
| 	cpuStat.User /= userHZ | ||||
| 	cpuStat.Nice /= userHZ | ||||
| 	cpuStat.System /= userHZ | ||||
| 	cpuStat.Idle /= userHZ | ||||
| 	cpuStat.Iowait /= userHZ | ||||
| 	cpuStat.IRQ /= userHZ | ||||
| 	cpuStat.SoftIRQ /= userHZ | ||||
| 	cpuStat.Steal /= userHZ | ||||
| 	cpuStat.Guest /= userHZ | ||||
| 	cpuStat.GuestNice /= userHZ | ||||
|  | ||||
| 	if cpu == "cpu" { | ||||
| 		return cpuStat, -1, nil | ||||
| 	} | ||||
|  | ||||
| 	cpuID, err := strconv.ParseInt(cpu[3:], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return CPUStat{}, -1, fmt.Errorf("couldn't parse %s (cpu/cpuid): %s", line, err) | ||||
| 	} | ||||
|  | ||||
| 	return cpuStat, cpuID, nil | ||||
| } | ||||
|  | ||||
| // Parse a softirq line. | ||||
| func parseSoftIRQStat(line string) (SoftIRQStat, uint64, error) { | ||||
| 	softIRQStat := SoftIRQStat{} | ||||
| 	var total uint64 | ||||
| 	var prefix string | ||||
|  | ||||
| 	_, err := fmt.Sscanf(line, "%s %d %d %d %d %d %d %d %d %d %d %d", | ||||
| 		&prefix, &total, | ||||
| 		&softIRQStat.Hi, &softIRQStat.Timer, &softIRQStat.NetTx, &softIRQStat.NetRx, | ||||
| 		&softIRQStat.Block, &softIRQStat.BlockIoPoll, | ||||
| 		&softIRQStat.Tasklet, &softIRQStat.Sched, | ||||
| 		&softIRQStat.Hrtimer, &softIRQStat.Rcu) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return SoftIRQStat{}, 0, fmt.Errorf("couldn't parse %s (softirq): %s", line, err) | ||||
| 	} | ||||
|  | ||||
| 	return softIRQStat, total, nil | ||||
| } | ||||
|  | ||||
| // NewStat returns an information about current kernel/system statistics. | ||||
| func (fs FS) NewStat() (Stat, error) { | ||||
| 	// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt | ||||
|  | ||||
| 	f, err := os.Open(fs.Path("stat")) | ||||
| 	if err != nil { | ||||
| 		return Stat{}, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	stat := Stat{} | ||||
|  | ||||
| 	scanner := bufio.NewScanner(f) | ||||
| 	for scanner.Scan() { | ||||
| 		line := scanner.Text() | ||||
| 		parts := strings.Fields(scanner.Text()) | ||||
| 		// require at least <key> <value> | ||||
| 		if len(parts) < 2 { | ||||
| 			continue | ||||
| 		} | ||||
| 		switch { | ||||
| 		case parts[0] == "btime": | ||||
| 			if stat.BootTime, err = strconv.ParseUint(parts[1], 10, 64); err != nil { | ||||
| 				return Stat{}, fmt.Errorf("couldn't parse %s (btime): %s", parts[1], err) | ||||
| 			} | ||||
| 		case parts[0] == "intr": | ||||
| 			if stat.IRQTotal, err = strconv.ParseUint(parts[1], 10, 64); err != nil { | ||||
| 				return Stat{}, fmt.Errorf("couldn't parse %s (intr): %s", parts[1], err) | ||||
| 			} | ||||
| 			numberedIRQs := parts[2:] | ||||
| 			stat.IRQ = make([]uint64, len(numberedIRQs)) | ||||
| 			for i, count := range numberedIRQs { | ||||
| 				if stat.IRQ[i], err = strconv.ParseUint(count, 10, 64); err != nil { | ||||
| 					return Stat{}, fmt.Errorf("couldn't parse %s (intr%d): %s", count, i, err) | ||||
| 				} | ||||
| 			} | ||||
| 		case parts[0] == "ctxt": | ||||
| 			if stat.ContextSwitches, err = strconv.ParseUint(parts[1], 10, 64); err != nil { | ||||
| 				return Stat{}, fmt.Errorf("couldn't parse %s (ctxt): %s", parts[1], err) | ||||
| 			} | ||||
| 		case parts[0] == "processes": | ||||
| 			if stat.ProcessCreated, err = strconv.ParseUint(parts[1], 10, 64); err != nil { | ||||
| 				return Stat{}, fmt.Errorf("couldn't parse %s (processes): %s", parts[1], err) | ||||
| 			} | ||||
| 		case parts[0] == "procs_running": | ||||
| 			if stat.ProcessesRunning, err = strconv.ParseUint(parts[1], 10, 64); err != nil { | ||||
| 				return Stat{}, fmt.Errorf("couldn't parse %s (procs_running): %s", parts[1], err) | ||||
| 			} | ||||
| 		case parts[0] == "procs_blocked": | ||||
| 			if stat.ProcessesBlocked, err = strconv.ParseUint(parts[1], 10, 64); err != nil { | ||||
| 				return Stat{}, fmt.Errorf("couldn't parse %s (procs_blocked): %s", parts[1], err) | ||||
| 			} | ||||
| 		case parts[0] == "softirq": | ||||
| 			softIRQStats, total, err := parseSoftIRQStat(line) | ||||
| 			if err != nil { | ||||
| 				return Stat{}, err | ||||
| 			} | ||||
| 			stat.SoftIRQTotal = total | ||||
| 			stat.SoftIRQ = softIRQStats | ||||
| 		case strings.HasPrefix(parts[0], "cpu"): | ||||
| 			cpuStat, cpuID, err := parseCPUStat(line) | ||||
| 			if err != nil { | ||||
| 				return Stat{}, err | ||||
| 			} | ||||
| 			if cpuID == -1 { | ||||
| 				stat.CPUTotal = cpuStat | ||||
| 			} else { | ||||
| 				for int64(len(stat.CPU)) <= cpuID { | ||||
| 					stat.CPU = append(stat.CPU, CPUStat{}) | ||||
| 				} | ||||
| 				stat.CPU[cpuID] = cpuStat | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := scanner.Err(); err != nil { | ||||
| 		return Stat{}, fmt.Errorf("couldn't parse %s: %s", f.Name(), err) | ||||
| 	} | ||||
|  | ||||
| 	return stat, nil | ||||
| } | ||||
							
								
								
									
										389
									
								
								vendor/github.com/prometheus/procfs/ttar
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										389
									
								
								vendor/github.com/prometheus/procfs/ttar
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,389 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| # Purpose: plain text tar format | ||||
| # Limitations: - only suitable for text files, directories, and symlinks | ||||
| #              - stores only filename, content, and mode | ||||
| #              - not designed for untrusted input | ||||
| # | ||||
| # Note: must work with bash version 3.2 (macOS) | ||||
|  | ||||
| # Copyright 2017 Roger Luethi | ||||
| # | ||||
| # 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. | ||||
|  | ||||
| set -o errexit -o nounset | ||||
|  | ||||
| # Sanitize environment (for instance, standard sorting of glob matches) | ||||
| export LC_ALL=C | ||||
|  | ||||
| path="" | ||||
| CMD="" | ||||
| ARG_STRING="$*" | ||||
|  | ||||
| #------------------------------------------------------------------------------ | ||||
| # Not all sed implementations can work on null bytes. In order to make ttar | ||||
| # work out of the box on macOS, use Python as a stream editor. | ||||
|  | ||||
| USE_PYTHON=0 | ||||
|  | ||||
| PYTHON_CREATE_FILTER=$(cat << 'PCF' | ||||
| #!/usr/bin/env python | ||||
|  | ||||
| import re | ||||
| import sys | ||||
|  | ||||
| for line in sys.stdin: | ||||
|     line = re.sub(r'EOF', r'\EOF', line) | ||||
|     line = re.sub(r'NULLBYTE', r'\NULLBYTE', line) | ||||
|     line = re.sub('\x00', r'NULLBYTE', line) | ||||
|     sys.stdout.write(line) | ||||
| PCF | ||||
| ) | ||||
|  | ||||
| PYTHON_EXTRACT_FILTER=$(cat << 'PEF' | ||||
| #!/usr/bin/env python | ||||
|  | ||||
| import re | ||||
| import sys | ||||
|  | ||||
| for line in sys.stdin: | ||||
|     line = re.sub(r'(?<!\\)NULLBYTE', '\x00', line) | ||||
|     line = re.sub(r'\\NULLBYTE', 'NULLBYTE', line) | ||||
|     line = re.sub(r'([^\\])EOF', r'\1', line) | ||||
|     line = re.sub(r'\\EOF', 'EOF', line) | ||||
|     sys.stdout.write(line) | ||||
| PEF | ||||
| ) | ||||
|  | ||||
| function test_environment { | ||||
|     if [[ "$(echo "a" | sed 's/a/\x0/' | wc -c)" -ne 2 ]]; then | ||||
|         echo "WARNING sed unable to handle null bytes, using Python (slow)." | ||||
|         if ! which python >/dev/null; then | ||||
|             echo "ERROR Python not found. Aborting." | ||||
|             exit 2 | ||||
|         fi | ||||
|         USE_PYTHON=1 | ||||
|     fi | ||||
| } | ||||
|  | ||||
| #------------------------------------------------------------------------------ | ||||
|  | ||||
| function usage { | ||||
|     bname=$(basename "$0") | ||||
|     cat << USAGE | ||||
| Usage:   $bname [-C <DIR>] -c -f <ARCHIVE> <FILE...> (create archive) | ||||
|          $bname            -t -f <ARCHIVE>           (list archive contents) | ||||
|          $bname [-C <DIR>] -x -f <ARCHIVE>           (extract archive) | ||||
|  | ||||
| Options: | ||||
|          -C <DIR>                                    (change directory) | ||||
|          -v                                          (verbose) | ||||
|  | ||||
| Example: Change to sysfs directory, create ttar file from fixtures directory | ||||
|          $bname -C sysfs -c -f sysfs/fixtures.ttar fixtures/ | ||||
| USAGE | ||||
| exit "$1" | ||||
| } | ||||
|  | ||||
| function vecho { | ||||
|     if [ "${VERBOSE:-}" == "yes" ]; then | ||||
|         echo >&7 "$@" | ||||
|     fi | ||||
| } | ||||
|  | ||||
| function set_cmd { | ||||
|     if [ -n "$CMD" ]; then | ||||
|         echo "ERROR: more than one command given" | ||||
|         echo | ||||
|         usage 2 | ||||
|     fi | ||||
|     CMD=$1 | ||||
| } | ||||
|  | ||||
| unset VERBOSE | ||||
|  | ||||
| while getopts :cf:htxvC: opt; do | ||||
|     case $opt in | ||||
|         c) | ||||
|             set_cmd "create" | ||||
|             ;; | ||||
|         f) | ||||
|             ARCHIVE=$OPTARG | ||||
|             ;; | ||||
|         h) | ||||
|             usage 0 | ||||
|             ;; | ||||
|         t) | ||||
|             set_cmd "list" | ||||
|             ;; | ||||
|         x) | ||||
|             set_cmd "extract" | ||||
|             ;; | ||||
|         v) | ||||
|             VERBOSE=yes | ||||
|             exec 7>&1 | ||||
|             ;; | ||||
|         C) | ||||
|             CDIR=$OPTARG | ||||
|             ;; | ||||
|         *) | ||||
|             echo >&2 "ERROR: invalid option -$OPTARG" | ||||
|             echo | ||||
|             usage 1 | ||||
|             ;; | ||||
|     esac | ||||
| done | ||||
|  | ||||
| # Remove processed options from arguments | ||||
| shift $(( OPTIND - 1 )); | ||||
|  | ||||
| if [ "${CMD:-}" == "" ]; then | ||||
|     echo >&2 "ERROR: no command given" | ||||
|     echo | ||||
|     usage 1 | ||||
| elif [ "${ARCHIVE:-}" == "" ]; then | ||||
|     echo >&2 "ERROR: no archive name given" | ||||
|     echo | ||||
|     usage 1 | ||||
| fi | ||||
|  | ||||
| function list { | ||||
|     local path="" | ||||
|     local size=0 | ||||
|     local line_no=0 | ||||
|     local ttar_file=$1 | ||||
|     if [ -n "${2:-}" ]; then | ||||
|         echo >&2 "ERROR: too many arguments." | ||||
|         echo | ||||
|         usage 1 | ||||
|     fi | ||||
|     if [ ! -e "$ttar_file" ]; then | ||||
|         echo >&2 "ERROR: file not found ($ttar_file)" | ||||
|         echo | ||||
|         usage 1 | ||||
|     fi | ||||
|     while read -r line; do | ||||
|         line_no=$(( line_no + 1 )) | ||||
|         if [ $size -gt 0 ]; then | ||||
|             size=$(( size - 1 )) | ||||
|             continue | ||||
|         fi | ||||
|         if [[ $line =~ ^Path:\ (.*)$ ]]; then | ||||
|             path=${BASH_REMATCH[1]} | ||||
|         elif [[ $line =~ ^Lines:\ (.*)$ ]]; then | ||||
|             size=${BASH_REMATCH[1]} | ||||
|             echo "$path" | ||||
|         elif [[ $line =~ ^Directory:\ (.*)$ ]]; then | ||||
|             path=${BASH_REMATCH[1]} | ||||
|             echo "$path/" | ||||
|         elif [[ $line =~ ^SymlinkTo:\ (.*)$ ]]; then | ||||
|             echo  "$path -> ${BASH_REMATCH[1]}" | ||||
|         fi | ||||
|     done < "$ttar_file" | ||||
| } | ||||
|  | ||||
| function extract { | ||||
|     local path="" | ||||
|     local size=0 | ||||
|     local line_no=0 | ||||
|     local ttar_file=$1 | ||||
|     if [ -n "${2:-}" ]; then | ||||
|         echo >&2 "ERROR: too many arguments." | ||||
|         echo | ||||
|         usage 1 | ||||
|     fi | ||||
|     if [ ! -e "$ttar_file" ]; then | ||||
|         echo >&2 "ERROR: file not found ($ttar_file)" | ||||
|         echo | ||||
|         usage 1 | ||||
|     fi | ||||
|     while IFS= read -r line; do | ||||
|         line_no=$(( line_no + 1 )) | ||||
|         local eof_without_newline | ||||
|         if [ "$size" -gt 0 ]; then | ||||
|             if [[ "$line" =~ [^\\]EOF ]]; then | ||||
|                 # An EOF not preceeded by a backslash indicates that the line | ||||
|                 # does not end with a newline | ||||
|                 eof_without_newline=1 | ||||
|             else | ||||
|                 eof_without_newline=0 | ||||
|             fi | ||||
|             # Replace NULLBYTE with null byte if at beginning of line | ||||
|             # Replace NULLBYTE with null byte unless preceeded by backslash | ||||
|             # Remove one backslash in front of NULLBYTE (if any) | ||||
|             # Remove EOF unless preceeded by backslash | ||||
|             # Remove one backslash in front of EOF | ||||
|             if [ $USE_PYTHON -eq 1 ]; then | ||||
|                 echo -n "$line" | python -c "$PYTHON_EXTRACT_FILTER" >> "$path" | ||||
|             else | ||||
|                 # The repeated pattern makes up for sed's lack of negative | ||||
|                 # lookbehind assertions (for consecutive null bytes). | ||||
|                 echo -n "$line" | \ | ||||
|                     sed -e 's/^NULLBYTE/\x0/g; | ||||
|                             s/\([^\\]\)NULLBYTE/\1\x0/g; | ||||
|                             s/\([^\\]\)NULLBYTE/\1\x0/g; | ||||
|                             s/\\NULLBYTE/NULLBYTE/g; | ||||
|                             s/\([^\\]\)EOF/\1/g; | ||||
|                             s/\\EOF/EOF/g; | ||||
|                     ' >> "$path" | ||||
|             fi | ||||
|             if [[ "$eof_without_newline" -eq 0 ]]; then | ||||
|                 echo >> "$path" | ||||
|             fi | ||||
|             size=$(( size - 1 )) | ||||
|             continue | ||||
|         fi | ||||
|         if [[ $line =~ ^Path:\ (.*)$ ]]; then | ||||
|             path=${BASH_REMATCH[1]} | ||||
|             if [ -e "$path" ] || [ -L "$path" ]; then | ||||
|                 rm "$path" | ||||
|             fi | ||||
|         elif [[ $line =~ ^Lines:\ (.*)$ ]]; then | ||||
|             size=${BASH_REMATCH[1]} | ||||
|             # Create file even if it is zero-length. | ||||
|             touch "$path" | ||||
|             vecho "    $path" | ||||
|         elif [[ $line =~ ^Mode:\ (.*)$ ]]; then | ||||
|             mode=${BASH_REMATCH[1]} | ||||
|             chmod "$mode" "$path" | ||||
|             vecho "$mode" | ||||
|         elif [[ $line =~ ^Directory:\ (.*)$ ]]; then | ||||
|             path=${BASH_REMATCH[1]} | ||||
|             mkdir -p "$path" | ||||
|             vecho "    $path/" | ||||
|         elif [[ $line =~ ^SymlinkTo:\ (.*)$ ]]; then | ||||
|             ln -s "${BASH_REMATCH[1]}" "$path" | ||||
|             vecho "    $path -> ${BASH_REMATCH[1]}" | ||||
|         elif [[ $line =~ ^# ]]; then | ||||
|             # Ignore comments between files | ||||
|             continue | ||||
|         else | ||||
|             echo >&2 "ERROR: Unknown keyword on line $line_no: $line" | ||||
|             exit 1 | ||||
|         fi | ||||
|     done < "$ttar_file" | ||||
| } | ||||
|  | ||||
| function div { | ||||
|     echo "# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" \ | ||||
|          "- - - - - -" | ||||
| } | ||||
|  | ||||
| function get_mode { | ||||
|     local mfile=$1 | ||||
|     if [ -z "${STAT_OPTION:-}" ]; then | ||||
|         if stat -c '%a' "$mfile" >/dev/null 2>&1; then | ||||
|             # GNU stat | ||||
|             STAT_OPTION='-c' | ||||
|             STAT_FORMAT='%a' | ||||
|         else | ||||
|             # BSD stat | ||||
|             STAT_OPTION='-f' | ||||
|             # Octal output, user/group/other (omit file type, sticky bit) | ||||
|             STAT_FORMAT='%OLp' | ||||
|         fi | ||||
|     fi | ||||
|     stat "${STAT_OPTION}" "${STAT_FORMAT}" "$mfile" | ||||
| } | ||||
|  | ||||
| function _create { | ||||
|     shopt -s nullglob | ||||
|     local mode | ||||
|     local eof_without_newline | ||||
|     while (( "$#" )); do | ||||
|         file=$1 | ||||
|         if [ -L "$file" ]; then | ||||
|             echo "Path: $file" | ||||
|             symlinkTo=$(readlink "$file") | ||||
|             echo "SymlinkTo: $symlinkTo" | ||||
|             vecho "    $file -> $symlinkTo" | ||||
|             div | ||||
|         elif [ -d "$file" ]; then | ||||
|             # Strip trailing slash (if there is one) | ||||
|             file=${file%/} | ||||
|             echo "Directory: $file" | ||||
|             mode=$(get_mode "$file") | ||||
|             echo "Mode: $mode" | ||||
|             vecho "$mode $file/" | ||||
|             div | ||||
|             # Find all files and dirs, including hidden/dot files | ||||
|             for x in "$file/"{*,.[^.]*}; do | ||||
|                 _create "$x" | ||||
|             done | ||||
|         elif [ -f "$file" ]; then | ||||
|             echo "Path: $file" | ||||
|             lines=$(wc -l "$file"|awk '{print $1}') | ||||
|             eof_without_newline=0 | ||||
|             if [[ "$(wc -c "$file"|awk '{print $1}')" -gt 0 ]] && \ | ||||
|                     [[ "$(tail -c 1 "$file" | wc -l)" -eq 0 ]]; then | ||||
|                 eof_without_newline=1 | ||||
|                 lines=$((lines+1)) | ||||
|             fi | ||||
|             echo "Lines: $lines" | ||||
|             # Add backslash in front of EOF | ||||
|             # Add backslash in front of NULLBYTE | ||||
|             # Replace null byte with NULLBYTE | ||||
|             if [ $USE_PYTHON -eq 1 ]; then | ||||
|                 < "$file" python -c "$PYTHON_CREATE_FILTER" | ||||
|             else | ||||
|                 < "$file" \ | ||||
|                     sed 's/EOF/\\EOF/g; | ||||
|                          s/NULLBYTE/\\NULLBYTE/g; | ||||
|                          s/\x0/NULLBYTE/g; | ||||
|                     ' | ||||
|             fi | ||||
|             if [[ "$eof_without_newline" -eq 1 ]]; then | ||||
|                 # Finish line with EOF to indicate that the original line did | ||||
|                 # not end with a linefeed | ||||
|                 echo "EOF" | ||||
|             fi | ||||
|             mode=$(get_mode "$file") | ||||
|             echo "Mode: $mode" | ||||
|             vecho "$mode $file" | ||||
|             div | ||||
|         else | ||||
|             echo >&2 "ERROR: file not found ($file in $(pwd))" | ||||
|             exit 2 | ||||
|         fi | ||||
|         shift | ||||
|     done | ||||
| } | ||||
|  | ||||
| function create { | ||||
|     ttar_file=$1 | ||||
|     shift | ||||
|     if [ -z "${1:-}" ]; then | ||||
|         echo >&2 "ERROR: missing arguments." | ||||
|         echo | ||||
|         usage 1 | ||||
|     fi | ||||
|     if [ -e "$ttar_file" ]; then | ||||
|         rm "$ttar_file" | ||||
|     fi | ||||
|     exec > "$ttar_file" | ||||
|     echo "# Archive created by ttar $ARG_STRING" | ||||
|     _create "$@" | ||||
| } | ||||
|  | ||||
| test_environment | ||||
|  | ||||
| if [ -n "${CDIR:-}" ]; then | ||||
|     if [[ "$ARCHIVE" != /* ]]; then | ||||
|         # Relative path: preserve the archive's location before changing | ||||
|         # directory | ||||
|         ARCHIVE="$(pwd)/$ARCHIVE" | ||||
|     fi | ||||
|     cd "$CDIR" | ||||
| fi | ||||
|  | ||||
| "$CMD" "$ARCHIVE" "$@" | ||||
							
								
								
									
										187
									
								
								vendor/github.com/prometheus/procfs/xfrm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								vendor/github.com/prometheus/procfs/xfrm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,187 @@ | ||||
| // Copyright 2017 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. | ||||
|  | ||||
| package procfs | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // XfrmStat models the contents of /proc/net/xfrm_stat. | ||||
| type XfrmStat struct { | ||||
| 	// All errors which are not matched by other | ||||
| 	XfrmInError int | ||||
| 	// No buffer is left | ||||
| 	XfrmInBufferError int | ||||
| 	// Header Error | ||||
| 	XfrmInHdrError int | ||||
| 	// No state found | ||||
| 	// i.e. either inbound SPI, address, or IPSEC protocol at SA is wrong | ||||
| 	XfrmInNoStates int | ||||
| 	// Transformation protocol specific error | ||||
| 	// e.g. SA Key is wrong | ||||
| 	XfrmInStateProtoError int | ||||
| 	// Transformation mode specific error | ||||
| 	XfrmInStateModeError int | ||||
| 	// Sequence error | ||||
| 	// e.g. sequence number is out of window | ||||
| 	XfrmInStateSeqError int | ||||
| 	// State is expired | ||||
| 	XfrmInStateExpired int | ||||
| 	// State has mismatch option | ||||
| 	// e.g. UDP encapsulation type is mismatched | ||||
| 	XfrmInStateMismatch int | ||||
| 	// State is invalid | ||||
| 	XfrmInStateInvalid int | ||||
| 	// No matching template for states | ||||
| 	// e.g. Inbound SAs are correct but SP rule is wrong | ||||
| 	XfrmInTmplMismatch int | ||||
| 	// No policy is found for states | ||||
| 	// e.g. Inbound SAs are correct but no SP is found | ||||
| 	XfrmInNoPols int | ||||
| 	// Policy discards | ||||
| 	XfrmInPolBlock int | ||||
| 	// Policy error | ||||
| 	XfrmInPolError int | ||||
| 	// All errors which are not matched by others | ||||
| 	XfrmOutError int | ||||
| 	// Bundle generation error | ||||
| 	XfrmOutBundleGenError int | ||||
| 	// Bundle check error | ||||
| 	XfrmOutBundleCheckError int | ||||
| 	// No state was found | ||||
| 	XfrmOutNoStates int | ||||
| 	// Transformation protocol specific error | ||||
| 	XfrmOutStateProtoError int | ||||
| 	// Transportation mode specific error | ||||
| 	XfrmOutStateModeError int | ||||
| 	// Sequence error | ||||
| 	// i.e sequence number overflow | ||||
| 	XfrmOutStateSeqError int | ||||
| 	// State is expired | ||||
| 	XfrmOutStateExpired int | ||||
| 	// Policy discads | ||||
| 	XfrmOutPolBlock int | ||||
| 	// Policy is dead | ||||
| 	XfrmOutPolDead int | ||||
| 	// Policy Error | ||||
| 	XfrmOutPolError     int | ||||
| 	XfrmFwdHdrError     int | ||||
| 	XfrmOutStateInvalid int | ||||
| 	XfrmAcquireError    int | ||||
| } | ||||
|  | ||||
| // NewXfrmStat reads the xfrm_stat statistics. | ||||
| func NewXfrmStat() (XfrmStat, error) { | ||||
| 	fs, err := NewFS(DefaultMountPoint) | ||||
| 	if err != nil { | ||||
| 		return XfrmStat{}, err | ||||
| 	} | ||||
|  | ||||
| 	return fs.NewXfrmStat() | ||||
| } | ||||
|  | ||||
| // NewXfrmStat reads the xfrm_stat statistics from the 'proc' filesystem. | ||||
| func (fs FS) NewXfrmStat() (XfrmStat, error) { | ||||
| 	file, err := os.Open(fs.Path("net/xfrm_stat")) | ||||
| 	if err != nil { | ||||
| 		return XfrmStat{}, err | ||||
| 	} | ||||
| 	defer file.Close() | ||||
|  | ||||
| 	var ( | ||||
| 		x = XfrmStat{} | ||||
| 		s = bufio.NewScanner(file) | ||||
| 	) | ||||
|  | ||||
| 	for s.Scan() { | ||||
| 		fields := strings.Fields(s.Text()) | ||||
|  | ||||
| 		if len(fields) != 2 { | ||||
| 			return XfrmStat{}, fmt.Errorf( | ||||
| 				"couldn't parse %s line %s", file.Name(), s.Text()) | ||||
| 		} | ||||
|  | ||||
| 		name := fields[0] | ||||
| 		value, err := strconv.Atoi(fields[1]) | ||||
| 		if err != nil { | ||||
| 			return XfrmStat{}, err | ||||
| 		} | ||||
|  | ||||
| 		switch name { | ||||
| 		case "XfrmInError": | ||||
| 			x.XfrmInError = value | ||||
| 		case "XfrmInBufferError": | ||||
| 			x.XfrmInBufferError = value | ||||
| 		case "XfrmInHdrError": | ||||
| 			x.XfrmInHdrError = value | ||||
| 		case "XfrmInNoStates": | ||||
| 			x.XfrmInNoStates = value | ||||
| 		case "XfrmInStateProtoError": | ||||
| 			x.XfrmInStateProtoError = value | ||||
| 		case "XfrmInStateModeError": | ||||
| 			x.XfrmInStateModeError = value | ||||
| 		case "XfrmInStateSeqError": | ||||
| 			x.XfrmInStateSeqError = value | ||||
| 		case "XfrmInStateExpired": | ||||
| 			x.XfrmInStateExpired = value | ||||
| 		case "XfrmInStateInvalid": | ||||
| 			x.XfrmInStateInvalid = value | ||||
| 		case "XfrmInTmplMismatch": | ||||
| 			x.XfrmInTmplMismatch = value | ||||
| 		case "XfrmInNoPols": | ||||
| 			x.XfrmInNoPols = value | ||||
| 		case "XfrmInPolBlock": | ||||
| 			x.XfrmInPolBlock = value | ||||
| 		case "XfrmInPolError": | ||||
| 			x.XfrmInPolError = value | ||||
| 		case "XfrmOutError": | ||||
| 			x.XfrmOutError = value | ||||
| 		case "XfrmInStateMismatch": | ||||
| 			x.XfrmInStateMismatch = value | ||||
| 		case "XfrmOutBundleGenError": | ||||
| 			x.XfrmOutBundleGenError = value | ||||
| 		case "XfrmOutBundleCheckError": | ||||
| 			x.XfrmOutBundleCheckError = value | ||||
| 		case "XfrmOutNoStates": | ||||
| 			x.XfrmOutNoStates = value | ||||
| 		case "XfrmOutStateProtoError": | ||||
| 			x.XfrmOutStateProtoError = value | ||||
| 		case "XfrmOutStateModeError": | ||||
| 			x.XfrmOutStateModeError = value | ||||
| 		case "XfrmOutStateSeqError": | ||||
| 			x.XfrmOutStateSeqError = value | ||||
| 		case "XfrmOutStateExpired": | ||||
| 			x.XfrmOutStateExpired = value | ||||
| 		case "XfrmOutPolBlock": | ||||
| 			x.XfrmOutPolBlock = value | ||||
| 		case "XfrmOutPolDead": | ||||
| 			x.XfrmOutPolDead = value | ||||
| 		case "XfrmOutPolError": | ||||
| 			x.XfrmOutPolError = value | ||||
| 		case "XfrmFwdHdrError": | ||||
| 			x.XfrmFwdHdrError = value | ||||
| 		case "XfrmOutStateInvalid": | ||||
| 			x.XfrmOutStateInvalid = value | ||||
| 		case "XfrmAcquireError": | ||||
| 			x.XfrmAcquireError = value | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return x, s.Err() | ||||
| } | ||||
							
								
								
									
										330
									
								
								vendor/github.com/prometheus/procfs/xfs/parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								vendor/github.com/prometheus/procfs/xfs/parse.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,330 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package xfs | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/prometheus/procfs/internal/util" | ||||
| ) | ||||
|  | ||||
| // ParseStats parses a Stats from an input io.Reader, using the format | ||||
| // found in /proc/fs/xfs/stat. | ||||
| func ParseStats(r io.Reader) (*Stats, error) { | ||||
| 	const ( | ||||
| 		// Fields parsed into stats structures. | ||||
| 		fieldExtentAlloc = "extent_alloc" | ||||
| 		fieldAbt         = "abt" | ||||
| 		fieldBlkMap      = "blk_map" | ||||
| 		fieldBmbt        = "bmbt" | ||||
| 		fieldDir         = "dir" | ||||
| 		fieldTrans       = "trans" | ||||
| 		fieldIg          = "ig" | ||||
| 		fieldLog         = "log" | ||||
| 		fieldRw          = "rw" | ||||
| 		fieldAttr        = "attr" | ||||
| 		fieldIcluster    = "icluster" | ||||
| 		fieldVnodes      = "vnodes" | ||||
| 		fieldBuf         = "buf" | ||||
| 		fieldXpc         = "xpc" | ||||
|  | ||||
| 		// Unimplemented at this time due to lack of documentation. | ||||
| 		fieldPushAil = "push_ail" | ||||
| 		fieldXstrat  = "xstrat" | ||||
| 		fieldAbtb2   = "abtb2" | ||||
| 		fieldAbtc2   = "abtc2" | ||||
| 		fieldBmbt2   = "bmbt2" | ||||
| 		fieldIbt2    = "ibt2" | ||||
| 		fieldFibt2   = "fibt2" | ||||
| 		fieldQm      = "qm" | ||||
| 		fieldDebug   = "debug" | ||||
| 	) | ||||
|  | ||||
| 	var xfss Stats | ||||
|  | ||||
| 	s := bufio.NewScanner(r) | ||||
| 	for s.Scan() { | ||||
| 		// Expect at least a string label and a single integer value, ex: | ||||
| 		//   - abt 0 | ||||
| 		//   - rw 1 2 | ||||
| 		ss := strings.Fields(string(s.Bytes())) | ||||
| 		if len(ss) < 2 { | ||||
| 			continue | ||||
| 		} | ||||
| 		label := ss[0] | ||||
|  | ||||
| 		// Extended precision counters are uint64 values. | ||||
| 		if label == fieldXpc { | ||||
| 			us, err := util.ParseUint64s(ss[1:]) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			xfss.ExtendedPrecision, err = extendedPrecisionStats(us) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// All other counters are uint32 values. | ||||
| 		us, err := util.ParseUint32s(ss[1:]) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		switch label { | ||||
| 		case fieldExtentAlloc: | ||||
| 			xfss.ExtentAllocation, err = extentAllocationStats(us) | ||||
| 		case fieldAbt: | ||||
| 			xfss.AllocationBTree, err = btreeStats(us) | ||||
| 		case fieldBlkMap: | ||||
| 			xfss.BlockMapping, err = blockMappingStats(us) | ||||
| 		case fieldBmbt: | ||||
| 			xfss.BlockMapBTree, err = btreeStats(us) | ||||
| 		case fieldDir: | ||||
| 			xfss.DirectoryOperation, err = directoryOperationStats(us) | ||||
| 		case fieldTrans: | ||||
| 			xfss.Transaction, err = transactionStats(us) | ||||
| 		case fieldIg: | ||||
| 			xfss.InodeOperation, err = inodeOperationStats(us) | ||||
| 		case fieldLog: | ||||
| 			xfss.LogOperation, err = logOperationStats(us) | ||||
| 		case fieldRw: | ||||
| 			xfss.ReadWrite, err = readWriteStats(us) | ||||
| 		case fieldAttr: | ||||
| 			xfss.AttributeOperation, err = attributeOperationStats(us) | ||||
| 		case fieldIcluster: | ||||
| 			xfss.InodeClustering, err = inodeClusteringStats(us) | ||||
| 		case fieldVnodes: | ||||
| 			xfss.Vnode, err = vnodeStats(us) | ||||
| 		case fieldBuf: | ||||
| 			xfss.Buffer, err = bufferStats(us) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &xfss, s.Err() | ||||
| } | ||||
|  | ||||
| // extentAllocationStats builds an ExtentAllocationStats from a slice of uint32s. | ||||
| func extentAllocationStats(us []uint32) (ExtentAllocationStats, error) { | ||||
| 	if l := len(us); l != 4 { | ||||
| 		return ExtentAllocationStats{}, fmt.Errorf("incorrect number of values for XFS extent allocation stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return ExtentAllocationStats{ | ||||
| 		ExtentsAllocated: us[0], | ||||
| 		BlocksAllocated:  us[1], | ||||
| 		ExtentsFreed:     us[2], | ||||
| 		BlocksFreed:      us[3], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // btreeStats builds a BTreeStats from a slice of uint32s. | ||||
| func btreeStats(us []uint32) (BTreeStats, error) { | ||||
| 	if l := len(us); l != 4 { | ||||
| 		return BTreeStats{}, fmt.Errorf("incorrect number of values for XFS btree stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return BTreeStats{ | ||||
| 		Lookups:         us[0], | ||||
| 		Compares:        us[1], | ||||
| 		RecordsInserted: us[2], | ||||
| 		RecordsDeleted:  us[3], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // BlockMappingStat builds a BlockMappingStats from a slice of uint32s. | ||||
| func blockMappingStats(us []uint32) (BlockMappingStats, error) { | ||||
| 	if l := len(us); l != 7 { | ||||
| 		return BlockMappingStats{}, fmt.Errorf("incorrect number of values for XFS block mapping stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return BlockMappingStats{ | ||||
| 		Reads:                us[0], | ||||
| 		Writes:               us[1], | ||||
| 		Unmaps:               us[2], | ||||
| 		ExtentListInsertions: us[3], | ||||
| 		ExtentListDeletions:  us[4], | ||||
| 		ExtentListLookups:    us[5], | ||||
| 		ExtentListCompares:   us[6], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // DirectoryOperationStats builds a DirectoryOperationStats from a slice of uint32s. | ||||
| func directoryOperationStats(us []uint32) (DirectoryOperationStats, error) { | ||||
| 	if l := len(us); l != 4 { | ||||
| 		return DirectoryOperationStats{}, fmt.Errorf("incorrect number of values for XFS directory operation stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return DirectoryOperationStats{ | ||||
| 		Lookups:  us[0], | ||||
| 		Creates:  us[1], | ||||
| 		Removes:  us[2], | ||||
| 		Getdents: us[3], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // TransactionStats builds a TransactionStats from a slice of uint32s. | ||||
| func transactionStats(us []uint32) (TransactionStats, error) { | ||||
| 	if l := len(us); l != 3 { | ||||
| 		return TransactionStats{}, fmt.Errorf("incorrect number of values for XFS transaction stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return TransactionStats{ | ||||
| 		Sync:  us[0], | ||||
| 		Async: us[1], | ||||
| 		Empty: us[2], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // InodeOperationStats builds an InodeOperationStats from a slice of uint32s. | ||||
| func inodeOperationStats(us []uint32) (InodeOperationStats, error) { | ||||
| 	if l := len(us); l != 7 { | ||||
| 		return InodeOperationStats{}, fmt.Errorf("incorrect number of values for XFS inode operation stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return InodeOperationStats{ | ||||
| 		Attempts:        us[0], | ||||
| 		Found:           us[1], | ||||
| 		Recycle:         us[2], | ||||
| 		Missed:          us[3], | ||||
| 		Duplicate:       us[4], | ||||
| 		Reclaims:        us[5], | ||||
| 		AttributeChange: us[6], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // LogOperationStats builds a LogOperationStats from a slice of uint32s. | ||||
| func logOperationStats(us []uint32) (LogOperationStats, error) { | ||||
| 	if l := len(us); l != 5 { | ||||
| 		return LogOperationStats{}, fmt.Errorf("incorrect number of values for XFS log operation stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return LogOperationStats{ | ||||
| 		Writes:            us[0], | ||||
| 		Blocks:            us[1], | ||||
| 		NoInternalBuffers: us[2], | ||||
| 		Force:             us[3], | ||||
| 		ForceSleep:        us[4], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // ReadWriteStats builds a ReadWriteStats from a slice of uint32s. | ||||
| func readWriteStats(us []uint32) (ReadWriteStats, error) { | ||||
| 	if l := len(us); l != 2 { | ||||
| 		return ReadWriteStats{}, fmt.Errorf("incorrect number of values for XFS read write stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return ReadWriteStats{ | ||||
| 		Read:  us[0], | ||||
| 		Write: us[1], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // AttributeOperationStats builds an AttributeOperationStats from a slice of uint32s. | ||||
| func attributeOperationStats(us []uint32) (AttributeOperationStats, error) { | ||||
| 	if l := len(us); l != 4 { | ||||
| 		return AttributeOperationStats{}, fmt.Errorf("incorrect number of values for XFS attribute operation stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return AttributeOperationStats{ | ||||
| 		Get:    us[0], | ||||
| 		Set:    us[1], | ||||
| 		Remove: us[2], | ||||
| 		List:   us[3], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // InodeClusteringStats builds an InodeClusteringStats from a slice of uint32s. | ||||
| func inodeClusteringStats(us []uint32) (InodeClusteringStats, error) { | ||||
| 	if l := len(us); l != 3 { | ||||
| 		return InodeClusteringStats{}, fmt.Errorf("incorrect number of values for XFS inode clustering stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return InodeClusteringStats{ | ||||
| 		Iflush:     us[0], | ||||
| 		Flush:      us[1], | ||||
| 		FlushInode: us[2], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // VnodeStats builds a VnodeStats from a slice of uint32s. | ||||
| func vnodeStats(us []uint32) (VnodeStats, error) { | ||||
| 	// The attribute "Free" appears to not be available on older XFS | ||||
| 	// stats versions.  Therefore, 7 or 8 elements may appear in | ||||
| 	// this slice. | ||||
| 	l := len(us) | ||||
| 	if l != 7 && l != 8 { | ||||
| 		return VnodeStats{}, fmt.Errorf("incorrect number of values for XFS vnode stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	s := VnodeStats{ | ||||
| 		Active:   us[0], | ||||
| 		Allocate: us[1], | ||||
| 		Get:      us[2], | ||||
| 		Hold:     us[3], | ||||
| 		Release:  us[4], | ||||
| 		Reclaim:  us[5], | ||||
| 		Remove:   us[6], | ||||
| 	} | ||||
|  | ||||
| 	// Skip adding free, unless it is present. The zero value will | ||||
| 	// be used in place of an actual count. | ||||
| 	if l == 7 { | ||||
| 		return s, nil | ||||
| 	} | ||||
|  | ||||
| 	s.Free = us[7] | ||||
| 	return s, nil | ||||
| } | ||||
|  | ||||
| // BufferStats builds a BufferStats from a slice of uint32s. | ||||
| func bufferStats(us []uint32) (BufferStats, error) { | ||||
| 	if l := len(us); l != 9 { | ||||
| 		return BufferStats{}, fmt.Errorf("incorrect number of values for XFS buffer stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return BufferStats{ | ||||
| 		Get:             us[0], | ||||
| 		Create:          us[1], | ||||
| 		GetLocked:       us[2], | ||||
| 		GetLockedWaited: us[3], | ||||
| 		BusyLocked:      us[4], | ||||
| 		MissLocked:      us[5], | ||||
| 		PageRetries:     us[6], | ||||
| 		PageFound:       us[7], | ||||
| 		GetRead:         us[8], | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // ExtendedPrecisionStats builds an ExtendedPrecisionStats from a slice of uint32s. | ||||
| func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) { | ||||
| 	if l := len(us); l != 3 { | ||||
| 		return ExtendedPrecisionStats{}, fmt.Errorf("incorrect number of values for XFS extended precision stats: %d", l) | ||||
| 	} | ||||
|  | ||||
| 	return ExtendedPrecisionStats{ | ||||
| 		FlushBytes: us[0], | ||||
| 		WriteBytes: us[1], | ||||
| 		ReadBytes:  us[2], | ||||
| 	}, nil | ||||
| } | ||||
							
								
								
									
										163
									
								
								vendor/github.com/prometheus/procfs/xfs/xfs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								vendor/github.com/prometheus/procfs/xfs/xfs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,163 @@ | ||||
| // Copyright 2017 The Prometheus Authors | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| // Package xfs provides access to statistics exposed by the XFS filesystem. | ||||
| package xfs | ||||
|  | ||||
| // Stats contains XFS filesystem runtime statistics, parsed from | ||||
| // /proc/fs/xfs/stat. | ||||
| // | ||||
| // The names and meanings of each statistic were taken from | ||||
| // http://xfs.org/index.php/Runtime_Stats and xfs_stats.h in the Linux | ||||
| // kernel source. Most counters are uint32s (same data types used in | ||||
| // xfs_stats.h), but some of the "extended precision stats" are uint64s. | ||||
| type Stats struct { | ||||
| 	// The name of the filesystem used to source these statistics. | ||||
| 	// If empty, this indicates aggregated statistics for all XFS | ||||
| 	// filesystems on the host. | ||||
| 	Name string | ||||
|  | ||||
| 	ExtentAllocation   ExtentAllocationStats | ||||
| 	AllocationBTree    BTreeStats | ||||
| 	BlockMapping       BlockMappingStats | ||||
| 	BlockMapBTree      BTreeStats | ||||
| 	DirectoryOperation DirectoryOperationStats | ||||
| 	Transaction        TransactionStats | ||||
| 	InodeOperation     InodeOperationStats | ||||
| 	LogOperation       LogOperationStats | ||||
| 	ReadWrite          ReadWriteStats | ||||
| 	AttributeOperation AttributeOperationStats | ||||
| 	InodeClustering    InodeClusteringStats | ||||
| 	Vnode              VnodeStats | ||||
| 	Buffer             BufferStats | ||||
| 	ExtendedPrecision  ExtendedPrecisionStats | ||||
| } | ||||
|  | ||||
| // ExtentAllocationStats contains statistics regarding XFS extent allocations. | ||||
| type ExtentAllocationStats struct { | ||||
| 	ExtentsAllocated uint32 | ||||
| 	BlocksAllocated  uint32 | ||||
| 	ExtentsFreed     uint32 | ||||
| 	BlocksFreed      uint32 | ||||
| } | ||||
|  | ||||
| // BTreeStats contains statistics regarding an XFS internal B-tree. | ||||
| type BTreeStats struct { | ||||
| 	Lookups         uint32 | ||||
| 	Compares        uint32 | ||||
| 	RecordsInserted uint32 | ||||
| 	RecordsDeleted  uint32 | ||||
| } | ||||
|  | ||||
| // BlockMappingStats contains statistics regarding XFS block maps. | ||||
| type BlockMappingStats struct { | ||||
| 	Reads                uint32 | ||||
| 	Writes               uint32 | ||||
| 	Unmaps               uint32 | ||||
| 	ExtentListInsertions uint32 | ||||
| 	ExtentListDeletions  uint32 | ||||
| 	ExtentListLookups    uint32 | ||||
| 	ExtentListCompares   uint32 | ||||
| } | ||||
|  | ||||
| // DirectoryOperationStats contains statistics regarding XFS directory entries. | ||||
| type DirectoryOperationStats struct { | ||||
| 	Lookups  uint32 | ||||
| 	Creates  uint32 | ||||
| 	Removes  uint32 | ||||
| 	Getdents uint32 | ||||
| } | ||||
|  | ||||
| // TransactionStats contains statistics regarding XFS metadata transactions. | ||||
| type TransactionStats struct { | ||||
| 	Sync  uint32 | ||||
| 	Async uint32 | ||||
| 	Empty uint32 | ||||
| } | ||||
|  | ||||
| // InodeOperationStats contains statistics regarding XFS inode operations. | ||||
| type InodeOperationStats struct { | ||||
| 	Attempts        uint32 | ||||
| 	Found           uint32 | ||||
| 	Recycle         uint32 | ||||
| 	Missed          uint32 | ||||
| 	Duplicate       uint32 | ||||
| 	Reclaims        uint32 | ||||
| 	AttributeChange uint32 | ||||
| } | ||||
|  | ||||
| // LogOperationStats contains statistics regarding the XFS log buffer. | ||||
| type LogOperationStats struct { | ||||
| 	Writes            uint32 | ||||
| 	Blocks            uint32 | ||||
| 	NoInternalBuffers uint32 | ||||
| 	Force             uint32 | ||||
| 	ForceSleep        uint32 | ||||
| } | ||||
|  | ||||
| // ReadWriteStats contains statistics regarding the number of read and write | ||||
| // system calls for XFS filesystems. | ||||
| type ReadWriteStats struct { | ||||
| 	Read  uint32 | ||||
| 	Write uint32 | ||||
| } | ||||
|  | ||||
| // AttributeOperationStats contains statistics regarding manipulation of | ||||
| // XFS extended file attributes. | ||||
| type AttributeOperationStats struct { | ||||
| 	Get    uint32 | ||||
| 	Set    uint32 | ||||
| 	Remove uint32 | ||||
| 	List   uint32 | ||||
| } | ||||
|  | ||||
| // InodeClusteringStats contains statistics regarding XFS inode clustering | ||||
| // operations. | ||||
| type InodeClusteringStats struct { | ||||
| 	Iflush     uint32 | ||||
| 	Flush      uint32 | ||||
| 	FlushInode uint32 | ||||
| } | ||||
|  | ||||
| // VnodeStats contains statistics regarding XFS vnode operations. | ||||
| type VnodeStats struct { | ||||
| 	Active   uint32 | ||||
| 	Allocate uint32 | ||||
| 	Get      uint32 | ||||
| 	Hold     uint32 | ||||
| 	Release  uint32 | ||||
| 	Reclaim  uint32 | ||||
| 	Remove   uint32 | ||||
| 	Free     uint32 | ||||
| } | ||||
|  | ||||
| // BufferStats contains statistics regarding XFS read/write I/O buffers. | ||||
| type BufferStats struct { | ||||
| 	Get             uint32 | ||||
| 	Create          uint32 | ||||
| 	GetLocked       uint32 | ||||
| 	GetLockedWaited uint32 | ||||
| 	BusyLocked      uint32 | ||||
| 	MissLocked      uint32 | ||||
| 	PageRetries     uint32 | ||||
| 	PageFound       uint32 | ||||
| 	GetRead         uint32 | ||||
| } | ||||
|  | ||||
| // ExtendedPrecisionStats contains high precision counters used to track the | ||||
| // total number of bytes read, written, or flushed, during XFS operations. | ||||
| type ExtendedPrecisionStats struct { | ||||
| 	FlushBytes uint64 | ||||
| 	WriteBytes uint64 | ||||
| 	ReadBytes  uint64 | ||||
| } | ||||
		Reference in New Issue
	
	Block a user