init
This commit is contained in:
		
							
								
								
									
										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") | ||||
| } | ||||
		Reference in New Issue
	
	Block a user