mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-28 05:49:57 +00:00
TUN-8456: Update quic-go to 0.45 and collect mtu and congestion control metrics
This commit is contained in:

committed by
Chung-Ting Huang

parent
cb6e5999e1
commit
0b62d45738
66
vendor/github.com/prometheus/common/expfmt/decode.go
generated
vendored
66
vendor/github.com/prometheus/common/expfmt/decode.go
generated
vendored
@@ -14,6 +14,7 @@
|
||||
package expfmt
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@@ -21,8 +22,8 @@ import (
|
||||
"net/http"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"google.golang.org/protobuf/encoding/protodelim"
|
||||
|
||||
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
@@ -44,7 +45,7 @@ func ResponseFormat(h http.Header) Format {
|
||||
|
||||
mediatype, params, err := mime.ParseMediaType(ct)
|
||||
if err != nil {
|
||||
return FmtUnknown
|
||||
return fmtUnknown
|
||||
}
|
||||
|
||||
const textType = "text/plain"
|
||||
@@ -52,28 +53,28 @@ func ResponseFormat(h http.Header) Format {
|
||||
switch mediatype {
|
||||
case ProtoType:
|
||||
if p, ok := params["proto"]; ok && p != ProtoProtocol {
|
||||
return FmtUnknown
|
||||
return fmtUnknown
|
||||
}
|
||||
if e, ok := params["encoding"]; ok && e != "delimited" {
|
||||
return FmtUnknown
|
||||
return fmtUnknown
|
||||
}
|
||||
return FmtProtoDelim
|
||||
return fmtProtoDelim
|
||||
|
||||
case textType:
|
||||
if v, ok := params["version"]; ok && v != TextVersion {
|
||||
return FmtUnknown
|
||||
return fmtUnknown
|
||||
}
|
||||
return FmtText
|
||||
return fmtText
|
||||
}
|
||||
|
||||
return FmtUnknown
|
||||
return fmtUnknown
|
||||
}
|
||||
|
||||
// NewDecoder returns a new decoder based on the given input format.
|
||||
// If the input format does not imply otherwise, a text format decoder is returned.
|
||||
func NewDecoder(r io.Reader, format Format) Decoder {
|
||||
switch format {
|
||||
case FmtProtoDelim:
|
||||
switch format.FormatType() {
|
||||
case TypeProtoDelim:
|
||||
return &protoDecoder{r: r}
|
||||
}
|
||||
return &textDecoder{r: r}
|
||||
@@ -86,8 +87,10 @@ type protoDecoder struct {
|
||||
|
||||
// Decode implements the Decoder interface.
|
||||
func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
|
||||
_, err := pbutil.ReadDelimited(d.r, v)
|
||||
if err != nil {
|
||||
opts := protodelim.UnmarshalOptions{
|
||||
MaxSize: -1,
|
||||
}
|
||||
if err := opts.UnmarshalFrom(bufio.NewReader(d.r), v); err != nil {
|
||||
return err
|
||||
}
|
||||
if !model.IsValidMetricName(model.LabelValue(v.GetName())) {
|
||||
@@ -115,32 +118,31 @@ func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
|
||||
// textDecoder implements the Decoder interface for the text protocol.
|
||||
type textDecoder struct {
|
||||
r io.Reader
|
||||
p TextParser
|
||||
fams []*dto.MetricFamily
|
||||
fams map[string]*dto.MetricFamily
|
||||
err error
|
||||
}
|
||||
|
||||
// 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)
|
||||
if d.err == nil {
|
||||
// Read all metrics in one shot.
|
||||
var p TextParser
|
||||
d.fams, d.err = p.TextToMetricFamilies(d.r)
|
||||
// If we don't get an error, store io.EOF for the end.
|
||||
if d.err == nil {
|
||||
d.err = io.EOF
|
||||
}
|
||||
}
|
||||
|
||||
*v = *d.fams[0]
|
||||
d.fams = d.fams[1:]
|
||||
|
||||
return nil
|
||||
// Pick off one MetricFamily per Decode until there's nothing left.
|
||||
for key, fam := range d.fams {
|
||||
v.Name = fam.Name
|
||||
v.Help = fam.Help
|
||||
v.Type = fam.Type
|
||||
v.Metric = fam.Metric
|
||||
delete(d.fams, key)
|
||||
return nil
|
||||
}
|
||||
return d.err
|
||||
}
|
||||
|
||||
// SampleDecoder wraps a Decoder to extract samples from the metric families
|
||||
|
79
vendor/github.com/prometheus/common/expfmt/encode.go
generated
vendored
79
vendor/github.com/prometheus/common/expfmt/encode.go
generated
vendored
@@ -18,9 +18,11 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/proto" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"github.com/matttproud/golang_protobuf_extensions/pbutil"
|
||||
"google.golang.org/protobuf/encoding/protodelim"
|
||||
"google.golang.org/protobuf/encoding/prototext"
|
||||
|
||||
"github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
@@ -60,23 +62,32 @@ func (ec encoderCloser) Close() error {
|
||||
// as the support is still experimental. To include the option to negotiate
|
||||
// FmtOpenMetrics, use NegotiateOpenMetrics.
|
||||
func Negotiate(h http.Header) Format {
|
||||
escapingScheme := Format(fmt.Sprintf("; escaping=%s", Format(model.NameEscapingScheme.String())))
|
||||
for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
|
||||
if escapeParam := ac.Params[model.EscapingKey]; escapeParam != "" {
|
||||
switch Format(escapeParam) {
|
||||
case model.AllowUTF8, model.EscapeUnderscores, model.EscapeDots, model.EscapeValues:
|
||||
escapingScheme = Format(fmt.Sprintf("; escaping=%s", escapeParam))
|
||||
default:
|
||||
// If the escaping parameter is unknown, ignore it.
|
||||
}
|
||||
}
|
||||
ver := ac.Params["version"]
|
||||
if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
|
||||
switch ac.Params["encoding"] {
|
||||
case "delimited":
|
||||
return FmtProtoDelim
|
||||
return fmtProtoDelim + escapingScheme
|
||||
case "text":
|
||||
return FmtProtoText
|
||||
return fmtProtoText + escapingScheme
|
||||
case "compact-text":
|
||||
return FmtProtoCompact
|
||||
return fmtProtoCompact + escapingScheme
|
||||
}
|
||||
}
|
||||
if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
|
||||
return FmtText
|
||||
return fmtText + escapingScheme
|
||||
}
|
||||
}
|
||||
return FmtText
|
||||
return fmtText + escapingScheme
|
||||
}
|
||||
|
||||
// NegotiateIncludingOpenMetrics works like Negotiate but includes
|
||||
@@ -84,26 +95,40 @@ func Negotiate(h http.Header) Format {
|
||||
// temporary and will disappear once FmtOpenMetrics is fully supported and as
|
||||
// such may be negotiated by the normal Negotiate function.
|
||||
func NegotiateIncludingOpenMetrics(h http.Header) Format {
|
||||
escapingScheme := Format(fmt.Sprintf("; escaping=%s", Format(model.NameEscapingScheme.String())))
|
||||
for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
|
||||
if escapeParam := ac.Params[model.EscapingKey]; escapeParam != "" {
|
||||
switch Format(escapeParam) {
|
||||
case model.AllowUTF8, model.EscapeUnderscores, model.EscapeDots, model.EscapeValues:
|
||||
escapingScheme = Format(fmt.Sprintf("; escaping=%s", escapeParam))
|
||||
default:
|
||||
// If the escaping parameter is unknown, ignore it.
|
||||
}
|
||||
}
|
||||
ver := ac.Params["version"]
|
||||
if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
|
||||
switch ac.Params["encoding"] {
|
||||
case "delimited":
|
||||
return FmtProtoDelim
|
||||
return fmtProtoDelim + escapingScheme
|
||||
case "text":
|
||||
return FmtProtoText
|
||||
return fmtProtoText + escapingScheme
|
||||
case "compact-text":
|
||||
return FmtProtoCompact
|
||||
return fmtProtoCompact + escapingScheme
|
||||
}
|
||||
}
|
||||
if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
|
||||
return FmtText
|
||||
return fmtText + escapingScheme
|
||||
}
|
||||
if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion || ver == "") {
|
||||
return FmtOpenMetrics
|
||||
if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion_0_0_1 || ver == OpenMetricsVersion_1_0_0 || ver == "") {
|
||||
switch ver {
|
||||
case OpenMetricsVersion_1_0_0:
|
||||
return fmtOpenMetrics_1_0_0 + escapingScheme
|
||||
default:
|
||||
return fmtOpenMetrics_0_0_1 + escapingScheme
|
||||
}
|
||||
}
|
||||
}
|
||||
return FmtText
|
||||
return fmtText + escapingScheme
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder based on content type negotiation. All
|
||||
@@ -112,44 +137,48 @@ func NegotiateIncludingOpenMetrics(h http.Header) Format {
|
||||
// for FmtOpenMetrics, but a future (breaking) release will add the Close method
|
||||
// to the Encoder interface directly. The current version of the Encoder
|
||||
// interface is kept for backwards compatibility.
|
||||
// In cases where the Format does not allow for UTF-8 names, the global
|
||||
// NameEscapingScheme will be applied.
|
||||
func NewEncoder(w io.Writer, format Format) Encoder {
|
||||
switch format {
|
||||
case FmtProtoDelim:
|
||||
escapingScheme := format.ToEscapingScheme()
|
||||
|
||||
switch format.FormatType() {
|
||||
case TypeProtoDelim:
|
||||
return encoderCloser{
|
||||
encode: func(v *dto.MetricFamily) error {
|
||||
_, err := pbutil.WriteDelimited(w, v)
|
||||
_, err := protodelim.MarshalTo(w, v)
|
||||
return err
|
||||
},
|
||||
close: func() error { return nil },
|
||||
}
|
||||
case FmtProtoCompact:
|
||||
case TypeProtoCompact:
|
||||
return encoderCloser{
|
||||
encode: func(v *dto.MetricFamily) error {
|
||||
_, err := fmt.Fprintln(w, v.String())
|
||||
_, err := fmt.Fprintln(w, model.EscapeMetricFamily(v, escapingScheme).String())
|
||||
return err
|
||||
},
|
||||
close: func() error { return nil },
|
||||
}
|
||||
case FmtProtoText:
|
||||
case TypeProtoText:
|
||||
return encoderCloser{
|
||||
encode: func(v *dto.MetricFamily) error {
|
||||
_, err := fmt.Fprintln(w, proto.MarshalTextString(v))
|
||||
_, err := fmt.Fprintln(w, prototext.Format(model.EscapeMetricFamily(v, escapingScheme)))
|
||||
return err
|
||||
},
|
||||
close: func() error { return nil },
|
||||
}
|
||||
case FmtText:
|
||||
case TypeTextPlain:
|
||||
return encoderCloser{
|
||||
encode: func(v *dto.MetricFamily) error {
|
||||
_, err := MetricFamilyToText(w, v)
|
||||
_, err := MetricFamilyToText(w, model.EscapeMetricFamily(v, escapingScheme))
|
||||
return err
|
||||
},
|
||||
close: func() error { return nil },
|
||||
}
|
||||
case FmtOpenMetrics:
|
||||
case TypeOpenMetrics:
|
||||
return encoderCloser{
|
||||
encode: func(v *dto.MetricFamily) error {
|
||||
_, err := MetricFamilyToOpenMetrics(w, v)
|
||||
_, err := MetricFamilyToOpenMetrics(w, model.EscapeMetricFamily(v, escapingScheme))
|
||||
return err
|
||||
},
|
||||
close: func() error {
|
||||
|
154
vendor/github.com/prometheus/common/expfmt/expfmt.go
generated
vendored
154
vendor/github.com/prometheus/common/expfmt/expfmt.go
generated
vendored
@@ -14,28 +14,154 @@
|
||||
// Package expfmt contains tools for reading and writing Prometheus metrics.
|
||||
package expfmt
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
// 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.
|
||||
// Constants to assemble the Content-Type values for the different wire
|
||||
// protocols. The Content-Type strings here are all for the legacy exposition
|
||||
// formats, where valid characters for metric names and label names are limited.
|
||||
// Support for arbitrary UTF-8 characters in those names is already partially
|
||||
// implemented in this module (see model.ValidationScheme), but to actually use
|
||||
// it on the wire, new content-type strings will have to be agreed upon and
|
||||
// added here.
|
||||
const (
|
||||
TextVersion = "0.0.4"
|
||||
ProtoType = `application/vnd.google.protobuf`
|
||||
ProtoProtocol = `io.prometheus.client.MetricFamily`
|
||||
ProtoFmt = ProtoType + "; proto=" + ProtoProtocol + ";"
|
||||
OpenMetricsType = `application/openmetrics-text`
|
||||
OpenMetricsVersion = "0.0.1"
|
||||
TextVersion = "0.0.4"
|
||||
ProtoType = `application/vnd.google.protobuf`
|
||||
ProtoProtocol = `io.prometheus.client.MetricFamily`
|
||||
protoFmt = ProtoType + "; proto=" + ProtoProtocol + ";"
|
||||
OpenMetricsType = `application/openmetrics-text`
|
||||
OpenMetricsVersion_0_0_1 = "0.0.1"
|
||||
OpenMetricsVersion_1_0_0 = "1.0.0"
|
||||
|
||||
// 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`
|
||||
FmtOpenMetrics Format = OpenMetricsType + `; version=` + OpenMetricsVersion + `; charset=utf-8`
|
||||
// The Content-Type values for the different wire protocols. Note that these
|
||||
// values are now unexported. If code was relying on comparisons to these
|
||||
// constants, instead use FormatType().
|
||||
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`
|
||||
fmtOpenMetrics_1_0_0 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_1_0_0 + `; charset=utf-8`
|
||||
fmtOpenMetrics_0_0_1 Format = OpenMetricsType + `; version=` + OpenMetricsVersion_0_0_1 + `; charset=utf-8`
|
||||
)
|
||||
|
||||
const (
|
||||
hdrContentType = "Content-Type"
|
||||
hdrAccept = "Accept"
|
||||
)
|
||||
|
||||
// FormatType is a Go enum representing the overall category for the given
|
||||
// Format. As the number of Format permutations increases, doing basic string
|
||||
// comparisons are not feasible, so this enum captures the most useful
|
||||
// high-level attribute of the Format string.
|
||||
type FormatType int
|
||||
|
||||
const (
|
||||
TypeUnknown = iota
|
||||
TypeProtoCompact
|
||||
TypeProtoDelim
|
||||
TypeProtoText
|
||||
TypeTextPlain
|
||||
TypeOpenMetrics
|
||||
)
|
||||
|
||||
// NewFormat generates a new Format from the type provided. Mostly used for
|
||||
// tests, most Formats should be generated as part of content negotiation in
|
||||
// encode.go.
|
||||
func NewFormat(t FormatType) Format {
|
||||
switch t {
|
||||
case TypeProtoCompact:
|
||||
return fmtProtoCompact
|
||||
case TypeProtoDelim:
|
||||
return fmtProtoDelim
|
||||
case TypeProtoText:
|
||||
return fmtProtoText
|
||||
case TypeTextPlain:
|
||||
return fmtText
|
||||
case TypeOpenMetrics:
|
||||
return fmtOpenMetrics_1_0_0
|
||||
default:
|
||||
return fmtUnknown
|
||||
}
|
||||
}
|
||||
|
||||
// FormatType deduces an overall FormatType for the given format.
|
||||
func (f Format) FormatType() FormatType {
|
||||
toks := strings.Split(string(f), ";")
|
||||
if len(toks) < 2 {
|
||||
return TypeUnknown
|
||||
}
|
||||
|
||||
params := make(map[string]string)
|
||||
for i, t := range toks {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
args := strings.Split(t, "=")
|
||||
if len(args) != 2 {
|
||||
continue
|
||||
}
|
||||
params[strings.TrimSpace(args[0])] = strings.TrimSpace(args[1])
|
||||
}
|
||||
|
||||
switch strings.TrimSpace(toks[0]) {
|
||||
case ProtoType:
|
||||
if params["proto"] != ProtoProtocol {
|
||||
return TypeUnknown
|
||||
}
|
||||
switch params["encoding"] {
|
||||
case "delimited":
|
||||
return TypeProtoDelim
|
||||
case "text":
|
||||
return TypeProtoText
|
||||
case "compact-text":
|
||||
return TypeProtoCompact
|
||||
default:
|
||||
return TypeUnknown
|
||||
}
|
||||
case OpenMetricsType:
|
||||
if params["charset"] != "utf-8" {
|
||||
return TypeUnknown
|
||||
}
|
||||
return TypeOpenMetrics
|
||||
case "text/plain":
|
||||
v, ok := params["version"]
|
||||
if !ok {
|
||||
return TypeTextPlain
|
||||
}
|
||||
if v == TextVersion {
|
||||
return TypeTextPlain
|
||||
}
|
||||
return TypeUnknown
|
||||
default:
|
||||
return TypeUnknown
|
||||
}
|
||||
}
|
||||
|
||||
// ToEscapingScheme returns an EscapingScheme depending on the Format. Iff the
|
||||
// Format contains a escaping=allow-utf-8 term, it will select NoEscaping. If a valid
|
||||
// "escaping" term exists, that will be used. Otherwise, the global default will
|
||||
// be returned.
|
||||
func (format Format) ToEscapingScheme() model.EscapingScheme {
|
||||
for _, p := range strings.Split(string(format), ";") {
|
||||
toks := strings.Split(p, "=")
|
||||
if len(toks) != 2 {
|
||||
continue
|
||||
}
|
||||
key, value := strings.TrimSpace(toks[0]), strings.TrimSpace(toks[1])
|
||||
if key == model.EscapingKey {
|
||||
scheme, err := model.ToEscapingScheme(value)
|
||||
if err != nil {
|
||||
return model.NameEscapingScheme
|
||||
}
|
||||
return scheme
|
||||
}
|
||||
}
|
||||
return model.NameEscapingScheme
|
||||
}
|
||||
|
4
vendor/github.com/prometheus/common/expfmt/fuzz.go
generated
vendored
4
vendor/github.com/prometheus/common/expfmt/fuzz.go
generated
vendored
@@ -21,8 +21,8 @@ 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
|
||||
// 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 {
|
||||
|
107
vendor/github.com/prometheus/common/expfmt/openmetrics_create.go
generated
vendored
107
vendor/github.com/prometheus/common/expfmt/openmetrics_create.go
generated
vendored
@@ -35,6 +35,18 @@ import (
|
||||
// sanity checks. If the input contains duplicate metrics or invalid metric or
|
||||
// label names, the conversion will result in invalid text format output.
|
||||
//
|
||||
// If metric names conform to the legacy validation pattern, they will be placed
|
||||
// outside the brackets in the traditional way, like `foo{}`. If the metric name
|
||||
// fails the legacy validation check, it will be placed quoted inside the
|
||||
// brackets: `{"foo"}`. As stated above, the input is assumed to be santized and
|
||||
// no error will be thrown in this case.
|
||||
//
|
||||
// Similar to metric names, if label names conform to the legacy validation
|
||||
// pattern, they will be unquoted as normal, like `foo{bar="baz"}`. If the label
|
||||
// name fails the legacy validation check, it will be quoted:
|
||||
// `foo{"bar"="baz"}`. As stated above, the input is assumed to be santized and
|
||||
// no error will be thrown in this case.
|
||||
//
|
||||
// This function fulfills the type 'expfmt.encoder'.
|
||||
//
|
||||
// Note that OpenMetrics requires a final `# EOF` line. Since this function acts
|
||||
@@ -46,20 +58,20 @@ import (
|
||||
// missing features and peculiarities to avoid complications when switching from
|
||||
// Prometheus to OpenMetrics or vice versa:
|
||||
//
|
||||
// - Counters are expected to have the `_total` suffix in their metric name. In
|
||||
// the output, the suffix will be truncated from the `# TYPE` and `# HELP`
|
||||
// line. A counter with a missing `_total` suffix is not an error. However,
|
||||
// its type will be set to `unknown` in that case to avoid invalid OpenMetrics
|
||||
// output.
|
||||
// - Counters are expected to have the `_total` suffix in their metric name. In
|
||||
// the output, the suffix will be truncated from the `# TYPE` and `# HELP`
|
||||
// line. A counter with a missing `_total` suffix is not an error. However,
|
||||
// its type will be set to `unknown` in that case to avoid invalid OpenMetrics
|
||||
// output.
|
||||
//
|
||||
// - No support for the following (optional) features: `# UNIT` line, `_created`
|
||||
// line, info type, stateset type, gaugehistogram type.
|
||||
// - No support for the following (optional) features: `# UNIT` line, `_created`
|
||||
// line, info type, stateset type, gaugehistogram type.
|
||||
//
|
||||
// - The size of exemplar labels is not checked (i.e. it's possible to create
|
||||
// exemplars that are larger than allowed by the OpenMetrics specification).
|
||||
// - The size of exemplar labels is not checked (i.e. it's possible to create
|
||||
// exemplars that are larger than allowed by the OpenMetrics specification).
|
||||
//
|
||||
// - The value of Counters is not checked. (OpenMetrics doesn't allow counters
|
||||
// with a `NaN` value.)
|
||||
// - The value of Counters is not checked. (OpenMetrics doesn't allow counters
|
||||
// with a `NaN` value.)
|
||||
func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int, err error) {
|
||||
name := in.GetName()
|
||||
if name == "" {
|
||||
@@ -98,7 +110,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, err = w.WriteString(shortName)
|
||||
n, err = writeName(w, shortName)
|
||||
written += n
|
||||
if err != nil {
|
||||
return
|
||||
@@ -124,7 +136,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, err = w.WriteString(shortName)
|
||||
n, err = writeName(w, shortName)
|
||||
written += n
|
||||
if err != nil {
|
||||
return
|
||||
@@ -303,21 +315,9 @@ func writeOpenMetricsSample(
|
||||
floatValue float64, intValue uint64, useIntValue bool,
|
||||
exemplar *dto.Exemplar,
|
||||
) (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 = writeOpenMetricsLabelPairs(
|
||||
w, metric.Label, additionalLabelName, additionalLabelValue,
|
||||
written := 0
|
||||
n, err := writeOpenMetricsNameAndLabelPairs(
|
||||
w, name+suffix, metric.Label, additionalLabelName, additionalLabelValue,
|
||||
)
|
||||
written += n
|
||||
if err != nil {
|
||||
@@ -365,27 +365,58 @@ func writeOpenMetricsSample(
|
||||
return written, nil
|
||||
}
|
||||
|
||||
// writeOpenMetricsLabelPairs works like writeOpenMetrics but formats the float
|
||||
// in OpenMetrics style.
|
||||
func writeOpenMetricsLabelPairs(
|
||||
// writeOpenMetricsNameAndLabelPairs works like writeOpenMetricsSample but
|
||||
// formats the float in OpenMetrics style.
|
||||
func writeOpenMetricsNameAndLabelPairs(
|
||||
w enhancedWriter,
|
||||
name string,
|
||||
in []*dto.LabelPair,
|
||||
additionalLabelName string, additionalLabelValue float64,
|
||||
) (int, error) {
|
||||
if len(in) == 0 && additionalLabelName == "" {
|
||||
return 0, nil
|
||||
}
|
||||
var (
|
||||
written int
|
||||
separator byte = '{'
|
||||
written int
|
||||
separator byte = '{'
|
||||
metricInsideBraces = false
|
||||
)
|
||||
|
||||
if name != "" {
|
||||
// If the name does not pass the legacy validity check, we must put the
|
||||
// metric name inside the braces, quoted.
|
||||
if !model.IsValidLegacyMetricName(model.LabelValue(name)) {
|
||||
metricInsideBraces = true
|
||||
err := w.WriteByte(separator)
|
||||
written++
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
separator = ','
|
||||
}
|
||||
|
||||
n, err := writeName(w, name)
|
||||
written += n
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(in) == 0 && additionalLabelName == "" {
|
||||
if metricInsideBraces {
|
||||
err := w.WriteByte('}')
|
||||
written++
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
}
|
||||
return written, nil
|
||||
}
|
||||
|
||||
for _, lp := range in {
|
||||
err := w.WriteByte(separator)
|
||||
written++
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
n, err := w.WriteString(lp.GetName())
|
||||
n, err := writeName(w, lp.GetName())
|
||||
written += n
|
||||
if err != nil {
|
||||
return written, err
|
||||
@@ -451,7 +482,7 @@ func writeExemplar(w enhancedWriter, e *dto.Exemplar) (int, error) {
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
n, err = writeOpenMetricsLabelPairs(w, e.Label, "", 0)
|
||||
n, err = writeOpenMetricsNameAndLabelPairs(w, "", e.Label, "", 0)
|
||||
written += n
|
||||
if err != nil {
|
||||
return written, err
|
||||
|
121
vendor/github.com/prometheus/common/expfmt/text_create.go
generated
vendored
121
vendor/github.com/prometheus/common/expfmt/text_create.go
generated
vendored
@@ -17,7 +17,6 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -44,7 +43,7 @@ const (
|
||||
var (
|
||||
bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return bufio.NewWriter(ioutil.Discard)
|
||||
return bufio.NewWriter(io.Discard)
|
||||
},
|
||||
}
|
||||
numBufPool = sync.Pool{
|
||||
@@ -63,6 +62,18 @@ var (
|
||||
// contains duplicate metrics or invalid metric or label names, the conversion
|
||||
// will result in invalid text format output.
|
||||
//
|
||||
// If metric names conform to the legacy validation pattern, they will be placed
|
||||
// outside the brackets in the traditional way, like `foo{}`. If the metric name
|
||||
// fails the legacy validation check, it will be placed quoted inside the
|
||||
// brackets: `{"foo"}`. As stated above, the input is assumed to be santized and
|
||||
// no error will be thrown in this case.
|
||||
//
|
||||
// Similar to metric names, if label names conform to the legacy validation
|
||||
// pattern, they will be unquoted as normal, like `foo{bar="baz"}`. If the label
|
||||
// name fails the legacy validation check, it will be quoted:
|
||||
// `foo{"bar"="baz"}`. As stated above, the input is assumed to be santized and
|
||||
// no error will be thrown in this case.
|
||||
//
|
||||
// This method fulfills the type 'prometheus.encoder'.
|
||||
func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err error) {
|
||||
// Fail-fast checks.
|
||||
@@ -99,7 +110,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, err = w.WriteString(name)
|
||||
n, err = writeName(w, name)
|
||||
written += n
|
||||
if err != nil {
|
||||
return
|
||||
@@ -125,7 +136,7 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (written int, err e
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, err = w.WriteString(name)
|
||||
n, err = writeName(w, name)
|
||||
written += n
|
||||
if err != nil {
|
||||
return
|
||||
@@ -281,21 +292,9 @@ func writeSample(
|
||||
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 := 0
|
||||
n, err := writeNameAndLabelPairs(
|
||||
w, name+suffix, metric.Label, additionalLabelName, additionalLabelValue,
|
||||
)
|
||||
written += n
|
||||
if err != nil {
|
||||
@@ -331,32 +330,64 @@ func writeSample(
|
||||
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(
|
||||
// writeNameAndLabelPairs converts a slice of LabelPair proto messages plus the
|
||||
// explicitly given metric name and 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. If the metric name is not
|
||||
// legacy-valid, it will be put inside the brackets as well. Legacy-invalid
|
||||
// label names will also be quoted.
|
||||
func writeNameAndLabelPairs(
|
||||
w enhancedWriter,
|
||||
name string,
|
||||
in []*dto.LabelPair,
|
||||
additionalLabelName string, additionalLabelValue float64,
|
||||
) (int, error) {
|
||||
if len(in) == 0 && additionalLabelName == "" {
|
||||
return 0, nil
|
||||
}
|
||||
var (
|
||||
written int
|
||||
separator byte = '{'
|
||||
written int
|
||||
separator byte = '{'
|
||||
metricInsideBraces = false
|
||||
)
|
||||
|
||||
if name != "" {
|
||||
// If the name does not pass the legacy validity check, we must put the
|
||||
// metric name inside the braces.
|
||||
if !model.IsValidLegacyMetricName(model.LabelValue(name)) {
|
||||
metricInsideBraces = true
|
||||
err := w.WriteByte(separator)
|
||||
written++
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
separator = ','
|
||||
}
|
||||
n, err := writeName(w, name)
|
||||
written += n
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(in) == 0 && additionalLabelName == "" {
|
||||
if metricInsideBraces {
|
||||
err := w.WriteByte('}')
|
||||
written++
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
}
|
||||
return written, nil
|
||||
}
|
||||
|
||||
for _, lp := range in {
|
||||
err := w.WriteByte(separator)
|
||||
written++
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
n, err := w.WriteString(lp.GetName())
|
||||
n, err := writeName(w, lp.GetName())
|
||||
written += n
|
||||
if err != nil {
|
||||
return written, err
|
||||
@@ -463,3 +494,27 @@ func writeInt(w enhancedWriter, i int64) (int, error) {
|
||||
numBufPool.Put(bp)
|
||||
return written, err
|
||||
}
|
||||
|
||||
// writeName writes a string as-is if it complies with the legacy naming
|
||||
// scheme, or escapes it in double quotes if not.
|
||||
func writeName(w enhancedWriter, name string) (int, error) {
|
||||
if model.IsValidLegacyMetricName(model.LabelValue(name)) {
|
||||
return w.WriteString(name)
|
||||
}
|
||||
var written int
|
||||
var err error
|
||||
err = w.WriteByte('"')
|
||||
written++
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
var n int
|
||||
n, err = writeEscapedString(w, name, true)
|
||||
written += n
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
err = w.WriteByte('"')
|
||||
written++
|
||||
return written, err
|
||||
}
|
||||
|
16
vendor/github.com/prometheus/common/expfmt/text_parse.go
generated
vendored
16
vendor/github.com/prometheus/common/expfmt/text_parse.go
generated
vendored
@@ -16,6 +16,7 @@ package expfmt
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@@ -24,7 +25,8 @@ import (
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
|
||||
"github.com/golang/protobuf/proto" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
@@ -112,7 +114,7 @@ func (p *TextParser) TextToMetricFamilies(in io.Reader) (map[string]*dto.MetricF
|
||||
// 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 {
|
||||
if p.err != nil && errors.Is(p.err, io.EOF) {
|
||||
p.parseError("unexpected end of input stream")
|
||||
}
|
||||
return p.metricFamiliesByName, p.err
|
||||
@@ -142,9 +144,13 @@ func (p *TextParser) reset(in io.Reader) {
|
||||
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
|
||||
// This is the only place that we expect to see io.EOF,
|
||||
// which is not an error but the signal that we are done.
|
||||
// Any other error that happens to align with the start of
|
||||
// a line is still an error.
|
||||
if errors.Is(p.err, io.EOF) {
|
||||
p.err = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
switch p.currentByte {
|
||||
|
22
vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go
generated
vendored
22
vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go
generated
vendored
@@ -11,18 +11,18 @@ 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 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.
|
||||
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.
|
||||
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
|
||||
@@ -35,8 +35,6 @@ 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
|
||||
|
||||
|
4
vendor/github.com/prometheus/common/model/alert.go
generated
vendored
4
vendor/github.com/prometheus/common/model/alert.go
generated
vendored
@@ -90,13 +90,13 @@ func (a *Alert) Validate() error {
|
||||
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)
|
||||
return fmt.Errorf("invalid label set: %w", 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 fmt.Errorf("invalid annotations: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
22
vendor/github.com/prometheus/common/model/labels.go
generated
vendored
22
vendor/github.com/prometheus/common/model/labels.go
generated
vendored
@@ -97,17 +97,25 @@ var LabelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
|
||||
// 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.
|
||||
// IsValid returns true iff name matches the pattern of LabelNameRE for legacy
|
||||
// names, and iff it's valid UTF-8 if NameValidationScheme is set to
|
||||
// UTF8Validation. For the legacy matching, it 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
|
||||
switch NameValidationScheme {
|
||||
case LegacyValidation:
|
||||
for i, b := range ln {
|
||||
if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case UTF8Validation:
|
||||
return utf8.ValidString(string(ln))
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid name validation scheme requested: %d", NameValidationScheme))
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -164,7 +172,7 @@ func (l LabelNames) String() string {
|
||||
// A LabelValue is an associated value for a LabelName.
|
||||
type LabelValue string
|
||||
|
||||
// IsValid returns true iff the string is a valid UTF8.
|
||||
// IsValid returns true iff the string is a valid UTF-8.
|
||||
func (lv LabelValue) IsValid() bool {
|
||||
return utf8.ValidString(string(lv))
|
||||
}
|
||||
|
28
vendor/github.com/prometheus/common/model/metadata.go
generated
vendored
Normal file
28
vendor/github.com/prometheus/common/model/metadata.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2023 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
|
||||
|
||||
// MetricType represents metric type values.
|
||||
type MetricType string
|
||||
|
||||
const (
|
||||
MetricTypeCounter = MetricType("counter")
|
||||
MetricTypeGauge = MetricType("gauge")
|
||||
MetricTypeHistogram = MetricType("histogram")
|
||||
MetricTypeGaugeHistogram = MetricType("gaugehistogram")
|
||||
MetricTypeSummary = MetricType("summary")
|
||||
MetricTypeInfo = MetricType("info")
|
||||
MetricTypeStateset = MetricType("stateset")
|
||||
MetricTypeUnknown = MetricType("unknown")
|
||||
)
|
368
vendor/github.com/prometheus/common/model/metric.go
generated
vendored
368
vendor/github.com/prometheus/common/model/metric.go
generated
vendored
@@ -18,15 +18,84 @@ import (
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
// 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_:]*$`)
|
||||
// NameValidationScheme determines the method of name validation to be used by
|
||||
// all calls to IsValidMetricName() and LabelName IsValid(). Setting UTF-8 mode
|
||||
// in isolation from other components that don't support UTF-8 may result in
|
||||
// bugs or other undefined behavior. This value is intended to be set by
|
||||
// UTF-8-aware binaries as part of their startup. To avoid need for locking,
|
||||
// this value should be set once, ideally in an init(), before multiple
|
||||
// goroutines are started.
|
||||
NameValidationScheme = LegacyValidation
|
||||
|
||||
// NameEscapingScheme defines the default way that names will be
|
||||
// escaped when presented to systems that do not support UTF-8 names. If the
|
||||
// Content-Type "escaping" term is specified, that will override this value.
|
||||
NameEscapingScheme = ValueEncodingEscaping
|
||||
)
|
||||
|
||||
// ValidationScheme is a Go enum for determining how metric and label names will
|
||||
// be validated by this library.
|
||||
type ValidationScheme int
|
||||
|
||||
const (
|
||||
// LegacyValidation is a setting that requirets that metric and label names
|
||||
// conform to the original Prometheus character requirements described by
|
||||
// MetricNameRE and LabelNameRE.
|
||||
LegacyValidation ValidationScheme = iota
|
||||
|
||||
// UTF8Validation only requires that metric and label names be valid UTF-8
|
||||
// strings.
|
||||
UTF8Validation
|
||||
)
|
||||
|
||||
type EscapingScheme int
|
||||
|
||||
const (
|
||||
// NoEscaping indicates that a name will not be escaped. Unescaped names that
|
||||
// do not conform to the legacy validity check will use a new exposition
|
||||
// format syntax that will be officially standardized in future versions.
|
||||
NoEscaping EscapingScheme = iota
|
||||
|
||||
// UnderscoreEscaping replaces all legacy-invalid characters with underscores.
|
||||
UnderscoreEscaping
|
||||
|
||||
// DotsEscaping is similar to UnderscoreEscaping, except that dots are
|
||||
// converted to `_dot_` and pre-existing underscores are converted to `__`.
|
||||
DotsEscaping
|
||||
|
||||
// ValueEncodingEscaping prepends the name with `U__` and replaces all invalid
|
||||
// characters with the unicode value, surrounded by underscores. Single
|
||||
// underscores are replaced with double underscores.
|
||||
ValueEncodingEscaping
|
||||
)
|
||||
|
||||
const (
|
||||
// EscapingKey is the key in an Accept or Content-Type header that defines how
|
||||
// metric and label names that do not conform to the legacy character
|
||||
// requirements should be escaped when being scraped by a legacy prometheus
|
||||
// system. If a system does not explicitly pass an escaping parameter in the
|
||||
// Accept header, the default NameEscapingScheme will be used.
|
||||
EscapingKey = "escaping"
|
||||
|
||||
// Possible values for Escaping Key:
|
||||
AllowUTF8 = "allow-utf-8" // No escaping required.
|
||||
EscapeUnderscores = "underscores"
|
||||
EscapeDots = "dots"
|
||||
EscapeValues = "values"
|
||||
)
|
||||
|
||||
// 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.
|
||||
var 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
|
||||
@@ -86,17 +155,302 @@ func (m Metric) FastFingerprint() Fingerprint {
|
||||
return LabelSet(m).FastFingerprint()
|
||||
}
|
||||
|
||||
// IsValidMetricName returns true iff name matches the pattern of MetricNameRE.
|
||||
// IsValidMetricName returns true iff name matches the pattern of MetricNameRE
|
||||
// for legacy names, and iff it's valid UTF-8 if the UTF8Validation scheme is
|
||||
// selected.
|
||||
func IsValidMetricName(n LabelValue) bool {
|
||||
switch NameValidationScheme {
|
||||
case LegacyValidation:
|
||||
return IsValidLegacyMetricName(n)
|
||||
case UTF8Validation:
|
||||
if len(n) == 0 {
|
||||
return false
|
||||
}
|
||||
return utf8.ValidString(string(n))
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid name validation scheme requested: %d", NameValidationScheme))
|
||||
}
|
||||
}
|
||||
|
||||
// IsValidLegacyMetricName is similar to IsValidMetricName but always uses the
|
||||
// legacy validation scheme regardless of the value of NameValidationScheme.
|
||||
// This function, however, does not use MetricNameRE for the check but a much
|
||||
// faster hardcoded implementation.
|
||||
func IsValidMetricName(n LabelValue) bool {
|
||||
func IsValidLegacyMetricName(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)) {
|
||||
if !isValidLegacyRune(b, i) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// EscapeMetricFamily escapes the given metric names and labels with the given
|
||||
// escaping scheme. Returns a new object that uses the same pointers to fields
|
||||
// when possible and creates new escaped versions so as not to mutate the
|
||||
// input.
|
||||
func EscapeMetricFamily(v *dto.MetricFamily, scheme EscapingScheme) *dto.MetricFamily {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if scheme == NoEscaping {
|
||||
return v
|
||||
}
|
||||
|
||||
out := &dto.MetricFamily{
|
||||
Help: v.Help,
|
||||
Type: v.Type,
|
||||
}
|
||||
|
||||
// If the name is nil, copy as-is, don't try to escape.
|
||||
if v.Name == nil || IsValidLegacyMetricName(LabelValue(v.GetName())) {
|
||||
out.Name = v.Name
|
||||
} else {
|
||||
out.Name = proto.String(EscapeName(v.GetName(), scheme))
|
||||
}
|
||||
for _, m := range v.Metric {
|
||||
if !metricNeedsEscaping(m) {
|
||||
out.Metric = append(out.Metric, m)
|
||||
continue
|
||||
}
|
||||
|
||||
escaped := &dto.Metric{
|
||||
Gauge: m.Gauge,
|
||||
Counter: m.Counter,
|
||||
Summary: m.Summary,
|
||||
Untyped: m.Untyped,
|
||||
Histogram: m.Histogram,
|
||||
TimestampMs: m.TimestampMs,
|
||||
}
|
||||
|
||||
for _, l := range m.Label {
|
||||
if l.GetName() == MetricNameLabel {
|
||||
if l.Value == nil || IsValidLegacyMetricName(LabelValue(l.GetValue())) {
|
||||
escaped.Label = append(escaped.Label, l)
|
||||
continue
|
||||
}
|
||||
escaped.Label = append(escaped.Label, &dto.LabelPair{
|
||||
Name: proto.String(MetricNameLabel),
|
||||
Value: proto.String(EscapeName(l.GetValue(), scheme)),
|
||||
})
|
||||
continue
|
||||
}
|
||||
if l.Name == nil || IsValidLegacyMetricName(LabelValue(l.GetName())) {
|
||||
escaped.Label = append(escaped.Label, l)
|
||||
continue
|
||||
}
|
||||
escaped.Label = append(escaped.Label, &dto.LabelPair{
|
||||
Name: proto.String(EscapeName(l.GetName(), scheme)),
|
||||
Value: l.Value,
|
||||
})
|
||||
}
|
||||
out.Metric = append(out.Metric, escaped)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func metricNeedsEscaping(m *dto.Metric) bool {
|
||||
for _, l := range m.Label {
|
||||
if l.GetName() == MetricNameLabel && !IsValidLegacyMetricName(LabelValue(l.GetValue())) {
|
||||
return true
|
||||
}
|
||||
if !IsValidLegacyMetricName(LabelValue(l.GetName())) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const (
|
||||
lowerhex = "0123456789abcdef"
|
||||
)
|
||||
|
||||
// EscapeName escapes the incoming name according to the provided escaping
|
||||
// scheme. Depending on the rules of escaping, this may cause no change in the
|
||||
// string that is returned. (Especially NoEscaping, which by definition is a
|
||||
// noop). This function does not do any validation of the name.
|
||||
func EscapeName(name string, scheme EscapingScheme) string {
|
||||
if len(name) == 0 {
|
||||
return name
|
||||
}
|
||||
var escaped strings.Builder
|
||||
switch scheme {
|
||||
case NoEscaping:
|
||||
return name
|
||||
case UnderscoreEscaping:
|
||||
if IsValidLegacyMetricName(LabelValue(name)) {
|
||||
return name
|
||||
}
|
||||
for i, b := range name {
|
||||
if isValidLegacyRune(b, i) {
|
||||
escaped.WriteRune(b)
|
||||
} else {
|
||||
escaped.WriteRune('_')
|
||||
}
|
||||
}
|
||||
return escaped.String()
|
||||
case DotsEscaping:
|
||||
// Do not early return for legacy valid names, we still escape underscores.
|
||||
for i, b := range name {
|
||||
if b == '_' {
|
||||
escaped.WriteString("__")
|
||||
} else if b == '.' {
|
||||
escaped.WriteString("_dot_")
|
||||
} else if isValidLegacyRune(b, i) {
|
||||
escaped.WriteRune(b)
|
||||
} else {
|
||||
escaped.WriteRune('_')
|
||||
}
|
||||
}
|
||||
return escaped.String()
|
||||
case ValueEncodingEscaping:
|
||||
if IsValidLegacyMetricName(LabelValue(name)) {
|
||||
return name
|
||||
}
|
||||
escaped.WriteString("U__")
|
||||
for i, b := range name {
|
||||
if isValidLegacyRune(b, i) {
|
||||
escaped.WriteRune(b)
|
||||
} else if !utf8.ValidRune(b) {
|
||||
escaped.WriteString("_FFFD_")
|
||||
} else if b < 0x100 {
|
||||
escaped.WriteRune('_')
|
||||
for s := 4; s >= 0; s -= 4 {
|
||||
escaped.WriteByte(lowerhex[b>>uint(s)&0xF])
|
||||
}
|
||||
escaped.WriteRune('_')
|
||||
} else if b < 0x10000 {
|
||||
escaped.WriteRune('_')
|
||||
for s := 12; s >= 0; s -= 4 {
|
||||
escaped.WriteByte(lowerhex[b>>uint(s)&0xF])
|
||||
}
|
||||
escaped.WriteRune('_')
|
||||
}
|
||||
}
|
||||
return escaped.String()
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid escaping scheme %d", scheme))
|
||||
}
|
||||
}
|
||||
|
||||
// lower function taken from strconv.atoi
|
||||
func lower(c byte) byte {
|
||||
return c | ('x' - 'X')
|
||||
}
|
||||
|
||||
// UnescapeName unescapes the incoming name according to the provided escaping
|
||||
// scheme if possible. Some schemes are partially or totally non-roundtripable.
|
||||
// If any error is enountered, returns the original input.
|
||||
func UnescapeName(name string, scheme EscapingScheme) string {
|
||||
if len(name) == 0 {
|
||||
return name
|
||||
}
|
||||
switch scheme {
|
||||
case NoEscaping:
|
||||
return name
|
||||
case UnderscoreEscaping:
|
||||
// It is not possible to unescape from underscore replacement.
|
||||
return name
|
||||
case DotsEscaping:
|
||||
name = strings.ReplaceAll(name, "_dot_", ".")
|
||||
name = strings.ReplaceAll(name, "__", "_")
|
||||
return name
|
||||
case ValueEncodingEscaping:
|
||||
escapedName, found := strings.CutPrefix(name, "U__")
|
||||
if !found {
|
||||
return name
|
||||
}
|
||||
|
||||
var unescaped strings.Builder
|
||||
TOP:
|
||||
for i := 0; i < len(escapedName); i++ {
|
||||
// All non-underscores are treated normally.
|
||||
if escapedName[i] != '_' {
|
||||
unescaped.WriteByte(escapedName[i])
|
||||
continue
|
||||
}
|
||||
i++
|
||||
if i >= len(escapedName) {
|
||||
return name
|
||||
}
|
||||
// A double underscore is a single underscore.
|
||||
if escapedName[i] == '_' {
|
||||
unescaped.WriteByte('_')
|
||||
continue
|
||||
}
|
||||
// We think we are in a UTF-8 code, process it.
|
||||
var utf8Val uint
|
||||
for j := 0; i < len(escapedName); j++ {
|
||||
// This is too many characters for a utf8 value.
|
||||
if j > 4 {
|
||||
return name
|
||||
}
|
||||
// Found a closing underscore, convert to a rune, check validity, and append.
|
||||
if escapedName[i] == '_' {
|
||||
utf8Rune := rune(utf8Val)
|
||||
if !utf8.ValidRune(utf8Rune) {
|
||||
return name
|
||||
}
|
||||
unescaped.WriteRune(utf8Rune)
|
||||
continue TOP
|
||||
}
|
||||
r := lower(escapedName[i])
|
||||
utf8Val *= 16
|
||||
if r >= '0' && r <= '9' {
|
||||
utf8Val += uint(r) - '0'
|
||||
} else if r >= 'a' && r <= 'f' {
|
||||
utf8Val += uint(r) - 'a' + 10
|
||||
} else {
|
||||
return name
|
||||
}
|
||||
i++
|
||||
}
|
||||
// Didn't find closing underscore, invalid.
|
||||
return name
|
||||
}
|
||||
return unescaped.String()
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid escaping scheme %d", scheme))
|
||||
}
|
||||
}
|
||||
|
||||
func isValidLegacyRune(b rune, i int) bool {
|
||||
return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || b == ':' || (b >= '0' && b <= '9' && i > 0)
|
||||
}
|
||||
|
||||
func (e EscapingScheme) String() string {
|
||||
switch e {
|
||||
case NoEscaping:
|
||||
return AllowUTF8
|
||||
case UnderscoreEscaping:
|
||||
return EscapeUnderscores
|
||||
case DotsEscaping:
|
||||
return EscapeDots
|
||||
case ValueEncodingEscaping:
|
||||
return EscapeValues
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown format scheme %d", e))
|
||||
}
|
||||
}
|
||||
|
||||
func ToEscapingScheme(s string) (EscapingScheme, error) {
|
||||
if s == "" {
|
||||
return NoEscaping, fmt.Errorf("got empty string instead of escaping scheme")
|
||||
}
|
||||
switch s {
|
||||
case AllowUTF8:
|
||||
return NoEscaping, nil
|
||||
case EscapeUnderscores:
|
||||
return UnderscoreEscaping, nil
|
||||
case EscapeDots:
|
||||
return DotsEscaping, nil
|
||||
case EscapeValues:
|
||||
return ValueEncodingEscaping, nil
|
||||
default:
|
||||
return NoEscaping, fmt.Errorf("unknown format scheme " + s)
|
||||
}
|
||||
}
|
||||
|
6
vendor/github.com/prometheus/common/model/signature.go
generated
vendored
6
vendor/github.com/prometheus/common/model/signature.go
generated
vendored
@@ -22,10 +22,8 @@ import (
|
||||
// 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()
|
||||
)
|
||||
// cache the signature of an empty label set.
|
||||
var 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
|
||||
|
2
vendor/github.com/prometheus/common/model/silence.go
generated
vendored
2
vendor/github.com/prometheus/common/model/silence.go
generated
vendored
@@ -81,7 +81,7 @@ func (s *Silence) Validate() error {
|
||||
}
|
||||
for _, m := range s.Matchers {
|
||||
if err := m.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid matcher: %s", err)
|
||||
return fmt.Errorf("invalid matcher: %w", err)
|
||||
}
|
||||
}
|
||||
if s.StartsAt.IsZero() {
|
||||
|
89
vendor/github.com/prometheus/common/model/time.go
generated
vendored
89
vendor/github.com/prometheus/common/model/time.go
generated
vendored
@@ -18,7 +18,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -183,54 +182,78 @@ func (d *Duration) Type() string {
|
||||
return "duration"
|
||||
}
|
||||
|
||||
var durationRE = regexp.MustCompile("^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$")
|
||||
func isdigit(c byte) bool { return c >= '0' && c <= '9' }
|
||||
|
||||
// Units are required to go in order from biggest to smallest.
|
||||
// This guards against confusion from "1m1d" being 1 minute + 1 day, not 1 month + 1 day.
|
||||
var unitMap = map[string]struct {
|
||||
pos int
|
||||
mult uint64
|
||||
}{
|
||||
"ms": {7, uint64(time.Millisecond)},
|
||||
"s": {6, uint64(time.Second)},
|
||||
"m": {5, uint64(time.Minute)},
|
||||
"h": {4, uint64(time.Hour)},
|
||||
"d": {3, uint64(24 * time.Hour)},
|
||||
"w": {2, uint64(7 * 24 * time.Hour)},
|
||||
"y": {1, uint64(365 * 24 * time.Hour)},
|
||||
}
|
||||
|
||||
// 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) {
|
||||
switch durationStr {
|
||||
func ParseDuration(s string) (Duration, error) {
|
||||
switch s {
|
||||
case "0":
|
||||
// Allow 0 without a unit.
|
||||
return 0, nil
|
||||
case "":
|
||||
return 0, errors.New("empty duration string")
|
||||
}
|
||||
matches := durationRE.FindStringSubmatch(durationStr)
|
||||
if matches == nil {
|
||||
return 0, fmt.Errorf("not a valid duration string: %q", durationStr)
|
||||
}
|
||||
var dur time.Duration
|
||||
|
||||
// Parse the match at pos `pos` in the regex and use `mult` to turn that
|
||||
// into ms, then add that value to the total parsed duration.
|
||||
var overflowErr error
|
||||
m := func(pos int, mult time.Duration) {
|
||||
if matches[pos] == "" {
|
||||
return
|
||||
orig := s
|
||||
var dur uint64
|
||||
lastUnitPos := 0
|
||||
|
||||
for s != "" {
|
||||
if !isdigit(s[0]) {
|
||||
return 0, fmt.Errorf("not a valid duration string: %q", orig)
|
||||
}
|
||||
n, _ := strconv.Atoi(matches[pos])
|
||||
// Consume [0-9]*
|
||||
i := 0
|
||||
for ; i < len(s) && isdigit(s[i]); i++ {
|
||||
}
|
||||
v, err := strconv.ParseUint(s[:i], 10, 0)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("not a valid duration string: %q", orig)
|
||||
}
|
||||
s = s[i:]
|
||||
|
||||
// Consume unit.
|
||||
for i = 0; i < len(s) && !isdigit(s[i]); i++ {
|
||||
}
|
||||
if i == 0 {
|
||||
return 0, fmt.Errorf("not a valid duration string: %q", orig)
|
||||
}
|
||||
u := s[:i]
|
||||
s = s[i:]
|
||||
unit, ok := unitMap[u]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("unknown unit %q in duration %q", u, orig)
|
||||
}
|
||||
if unit.pos <= lastUnitPos { // Units must go in order from biggest to smallest.
|
||||
return 0, fmt.Errorf("not a valid duration string: %q", orig)
|
||||
}
|
||||
lastUnitPos = unit.pos
|
||||
// Check if the provided duration overflows time.Duration (> ~ 290years).
|
||||
if n > int((1<<63-1)/mult/time.Millisecond) {
|
||||
overflowErr = errors.New("duration out of range")
|
||||
if v > 1<<63/unit.mult {
|
||||
return 0, errors.New("duration out of range")
|
||||
}
|
||||
d := time.Duration(n) * time.Millisecond
|
||||
dur += d * mult
|
||||
|
||||
if dur < 0 {
|
||||
overflowErr = errors.New("duration out of range")
|
||||
dur += v * unit.mult
|
||||
if dur > 1<<63-1 {
|
||||
return 0, errors.New("duration out of range")
|
||||
}
|
||||
}
|
||||
|
||||
m(2, 1000*60*60*24*365) // y
|
||||
m(4, 1000*60*60*24*7) // w
|
||||
m(6, 1000*60*60*24) // d
|
||||
m(8, 1000*60*60) // h
|
||||
m(10, 1000*60) // m
|
||||
m(12, 1000) // s
|
||||
m(14, 1) // ms
|
||||
|
||||
return Duration(dur), overflowErr
|
||||
return Duration(dur), nil
|
||||
}
|
||||
|
||||
func (d Duration) String() string {
|
||||
|
262
vendor/github.com/prometheus/common/model/value.go
generated
vendored
262
vendor/github.com/prometheus/common/model/value.go
generated
vendored
@@ -16,104 +16,26 @@ 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.
|
||||
var ZeroSample = Sample{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.
|
||||
// Sample is a sample pair associated with a metric. A single sample must either
|
||||
// define Value or Histogram but not both. Histogram == nil implies the Value
|
||||
// field is used, otherwise it should be ignored.
|
||||
type Sample struct {
|
||||
Metric Metric `json:"metric"`
|
||||
Value SampleValue `json:"value"`
|
||||
Timestamp Time `json:"timestamp"`
|
||||
Metric Metric `json:"metric"`
|
||||
Value SampleValue `json:"value"`
|
||||
Timestamp Time `json:"timestamp"`
|
||||
Histogram *SampleHistogram `json:"histogram"`
|
||||
}
|
||||
|
||||
// Equal compares first the metrics, then the timestamp, then the value. The
|
||||
@@ -129,11 +51,19 @@ func (s *Sample) Equal(o *Sample) bool {
|
||||
if !s.Timestamp.Equal(o.Timestamp) {
|
||||
return false
|
||||
}
|
||||
|
||||
if s.Histogram != nil {
|
||||
return s.Histogram.Equal(o.Histogram)
|
||||
}
|
||||
return s.Value.Equal(o.Value)
|
||||
}
|
||||
|
||||
func (s Sample) String() string {
|
||||
if s.Histogram != nil {
|
||||
return fmt.Sprintf("%s => %s", s.Metric, SampleHistogramPair{
|
||||
Timestamp: s.Timestamp,
|
||||
Histogram: s.Histogram,
|
||||
})
|
||||
}
|
||||
return fmt.Sprintf("%s => %s", s.Metric, SamplePair{
|
||||
Timestamp: s.Timestamp,
|
||||
Value: s.Value,
|
||||
@@ -142,6 +72,19 @@ func (s Sample) String() string {
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (s Sample) MarshalJSON() ([]byte, error) {
|
||||
if s.Histogram != nil {
|
||||
v := struct {
|
||||
Metric Metric `json:"metric"`
|
||||
Histogram SampleHistogramPair `json:"histogram"`
|
||||
}{
|
||||
Metric: s.Metric,
|
||||
Histogram: SampleHistogramPair{
|
||||
Timestamp: s.Timestamp,
|
||||
Histogram: s.Histogram,
|
||||
},
|
||||
}
|
||||
return json.Marshal(&v)
|
||||
}
|
||||
v := struct {
|
||||
Metric Metric `json:"metric"`
|
||||
Value SamplePair `json:"value"`
|
||||
@@ -152,21 +95,25 @@ func (s Sample) MarshalJSON() ([]byte, error) {
|
||||
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 Metric `json:"metric"`
|
||||
Value SamplePair `json:"value"`
|
||||
Histogram SampleHistogramPair `json:"histogram"`
|
||||
}{
|
||||
Metric: s.Metric,
|
||||
Value: SamplePair{
|
||||
Timestamp: s.Timestamp,
|
||||
Value: s.Value,
|
||||
},
|
||||
Histogram: SampleHistogramPair{
|
||||
Timestamp: s.Timestamp,
|
||||
Histogram: s.Histogram,
|
||||
},
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
@@ -174,8 +121,13 @@ func (s *Sample) UnmarshalJSON(b []byte) error {
|
||||
}
|
||||
|
||||
s.Metric = v.Metric
|
||||
s.Timestamp = v.Value.Timestamp
|
||||
s.Value = v.Value.Value
|
||||
if v.Histogram.Histogram != nil {
|
||||
s.Timestamp = v.Histogram.Timestamp
|
||||
s.Histogram = v.Histogram.Histogram
|
||||
} else {
|
||||
s.Timestamp = v.Value.Timestamp
|
||||
s.Value = v.Value.Value
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -221,80 +173,76 @@ func (s Samples) Equal(o Samples) bool {
|
||||
|
||||
// SampleStream is a stream of Values belonging to an attached COWMetric.
|
||||
type SampleStream struct {
|
||||
Metric Metric `json:"metric"`
|
||||
Values []SamplePair `json:"values"`
|
||||
Metric Metric `json:"metric"`
|
||||
Values []SamplePair `json:"values"`
|
||||
Histograms []SampleHistogramPair `json:"histograms"`
|
||||
}
|
||||
|
||||
func (ss SampleStream) String() string {
|
||||
vals := make([]string, len(ss.Values))
|
||||
valuesLength := len(ss.Values)
|
||||
vals := make([]string, valuesLength+len(ss.Histograms))
|
||||
for i, v := range ss.Values {
|
||||
vals[i] = v.String()
|
||||
}
|
||||
for i, v := range ss.Histograms {
|
||||
vals[i+valuesLength] = 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 (ss SampleStream) MarshalJSON() ([]byte, error) {
|
||||
if len(ss.Histograms) > 0 && len(ss.Values) > 0 {
|
||||
v := struct {
|
||||
Metric Metric `json:"metric"`
|
||||
Values []SamplePair `json:"values"`
|
||||
Histograms []SampleHistogramPair `json:"histograms"`
|
||||
}{
|
||||
Metric: ss.Metric,
|
||||
Values: ss.Values,
|
||||
Histograms: ss.Histograms,
|
||||
}
|
||||
return json.Marshal(&v)
|
||||
} else if len(ss.Histograms) > 0 {
|
||||
v := struct {
|
||||
Metric Metric `json:"metric"`
|
||||
Histograms []SampleHistogramPair `json:"histograms"`
|
||||
}{
|
||||
Metric: ss.Metric,
|
||||
Histograms: ss.Histograms,
|
||||
}
|
||||
return json.Marshal(&v)
|
||||
} else {
|
||||
v := struct {
|
||||
Metric Metric `json:"metric"`
|
||||
Values []SamplePair `json:"values"`
|
||||
}{
|
||||
Metric: ss.Metric,
|
||||
Values: ss.Values,
|
||||
}
|
||||
return json.Marshal(&v)
|
||||
}
|
||||
}
|
||||
|
||||
func (Matrix) Type() ValueType { return ValMatrix }
|
||||
func (Vector) Type() ValueType { return ValVector }
|
||||
func (*Scalar) Type() ValueType { return ValScalar }
|
||||
func (*String) Type() ValueType { return ValString }
|
||||
func (ss *SampleStream) UnmarshalJSON(b []byte) error {
|
||||
v := struct {
|
||||
Metric Metric `json:"metric"`
|
||||
Values []SamplePair `json:"values"`
|
||||
Histograms []SampleHistogramPair `json:"histograms"`
|
||||
}{
|
||||
Metric: ss.Metric,
|
||||
Values: ss.Values,
|
||||
Histograms: ss.Histograms,
|
||||
}
|
||||
|
||||
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 {
|
||||
if err := json.Unmarshal(b, &v); 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")
|
||||
ss.Metric = v.Metric
|
||||
ss.Values = v.Values
|
||||
ss.Histograms = v.Histograms
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Scalar is a scalar value evaluated at the set timestamp.
|
||||
@@ -324,7 +272,7 @@ func (s *Scalar) UnmarshalJSON(b []byte) error {
|
||||
|
||||
value, err := strconv.ParseFloat(f, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing sample value: %s", err)
|
||||
return fmt.Errorf("error parsing sample value: %w", err)
|
||||
}
|
||||
s.Value = SampleValue(value)
|
||||
return nil
|
||||
|
98
vendor/github.com/prometheus/common/model/value_float.go
generated
vendored
Normal file
98
vendor/github.com/prometheus/common/model/value_float.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
// 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"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// 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.
|
||||
var ZeroSamplePair = SamplePair{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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
178
vendor/github.com/prometheus/common/model/value_histogram.go
generated
vendored
Normal file
178
vendor/github.com/prometheus/common/model/value_histogram.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
// 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"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type FloatString float64
|
||||
|
||||
func (v FloatString) String() string {
|
||||
return strconv.FormatFloat(float64(v), 'f', -1, 64)
|
||||
}
|
||||
|
||||
func (v FloatString) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.String())
|
||||
}
|
||||
|
||||
func (v *FloatString) UnmarshalJSON(b []byte) error {
|
||||
if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
|
||||
return fmt.Errorf("float value must be a quoted string")
|
||||
}
|
||||
f, err := strconv.ParseFloat(string(b[1:len(b)-1]), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = FloatString(f)
|
||||
return nil
|
||||
}
|
||||
|
||||
type HistogramBucket struct {
|
||||
Boundaries int32
|
||||
Lower FloatString
|
||||
Upper FloatString
|
||||
Count FloatString
|
||||
}
|
||||
|
||||
func (s HistogramBucket) MarshalJSON() ([]byte, error) {
|
||||
b, err := json.Marshal(s.Boundaries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l, err := json.Marshal(s.Lower)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u, err := json.Marshal(s.Upper)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := json.Marshal(s.Count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(fmt.Sprintf("[%s,%s,%s,%s]", b, l, u, c)), nil
|
||||
}
|
||||
|
||||
func (s *HistogramBucket) UnmarshalJSON(buf []byte) error {
|
||||
tmp := []interface{}{&s.Boundaries, &s.Lower, &s.Upper, &s.Count}
|
||||
wantLen := len(tmp)
|
||||
if err := json.Unmarshal(buf, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
if gotLen := len(tmp); gotLen != wantLen {
|
||||
return fmt.Errorf("wrong number of fields: %d != %d", gotLen, wantLen)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *HistogramBucket) Equal(o *HistogramBucket) bool {
|
||||
return s == o || (s.Boundaries == o.Boundaries && s.Lower == o.Lower && s.Upper == o.Upper && s.Count == o.Count)
|
||||
}
|
||||
|
||||
func (b HistogramBucket) String() string {
|
||||
var sb strings.Builder
|
||||
lowerInclusive := b.Boundaries == 1 || b.Boundaries == 3
|
||||
upperInclusive := b.Boundaries == 0 || b.Boundaries == 3
|
||||
if lowerInclusive {
|
||||
sb.WriteRune('[')
|
||||
} else {
|
||||
sb.WriteRune('(')
|
||||
}
|
||||
fmt.Fprintf(&sb, "%g,%g", b.Lower, b.Upper)
|
||||
if upperInclusive {
|
||||
sb.WriteRune(']')
|
||||
} else {
|
||||
sb.WriteRune(')')
|
||||
}
|
||||
fmt.Fprintf(&sb, ":%v", b.Count)
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
type HistogramBuckets []*HistogramBucket
|
||||
|
||||
func (s HistogramBuckets) Equal(o HistogramBuckets) bool {
|
||||
if len(s) != len(o) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, bucket := range s {
|
||||
if !bucket.Equal(o[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type SampleHistogram struct {
|
||||
Count FloatString `json:"count"`
|
||||
Sum FloatString `json:"sum"`
|
||||
Buckets HistogramBuckets `json:"buckets"`
|
||||
}
|
||||
|
||||
func (s SampleHistogram) String() string {
|
||||
return fmt.Sprintf("Count: %f, Sum: %f, Buckets: %v", s.Count, s.Sum, s.Buckets)
|
||||
}
|
||||
|
||||
func (s *SampleHistogram) Equal(o *SampleHistogram) bool {
|
||||
return s == o || (s.Count == o.Count && s.Sum == o.Sum && s.Buckets.Equal(o.Buckets))
|
||||
}
|
||||
|
||||
type SampleHistogramPair struct {
|
||||
Timestamp Time
|
||||
// Histogram should never be nil, it's only stored as pointer for efficiency.
|
||||
Histogram *SampleHistogram
|
||||
}
|
||||
|
||||
func (s SampleHistogramPair) MarshalJSON() ([]byte, error) {
|
||||
if s.Histogram == nil {
|
||||
return nil, fmt.Errorf("histogram is nil")
|
||||
}
|
||||
t, err := json.Marshal(s.Timestamp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v, err := json.Marshal(s.Histogram)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(fmt.Sprintf("[%s,%s]", t, v)), nil
|
||||
}
|
||||
|
||||
func (s *SampleHistogramPair) UnmarshalJSON(buf []byte) error {
|
||||
tmp := []interface{}{&s.Timestamp, &s.Histogram}
|
||||
wantLen := len(tmp)
|
||||
if err := json.Unmarshal(buf, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
if gotLen := len(tmp); gotLen != wantLen {
|
||||
return fmt.Errorf("wrong number of fields: %d != %d", gotLen, wantLen)
|
||||
}
|
||||
if s.Histogram == nil {
|
||||
return fmt.Errorf("histogram is null")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s SampleHistogramPair) String() string {
|
||||
return fmt.Sprintf("%s @[%s]", s.Histogram, s.Timestamp)
|
||||
}
|
||||
|
||||
func (s *SampleHistogramPair) Equal(o *SampleHistogramPair) bool {
|
||||
return s == o || (s.Histogram.Equal(o.Histogram) && s.Timestamp.Equal(o.Timestamp))
|
||||
}
|
83
vendor/github.com/prometheus/common/model/value_type.go
generated
vendored
Normal file
83
vendor/github.com/prometheus/common/model/value_type.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
// 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")
|
||||
}
|
Reference in New Issue
Block a user