mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-28 08:07:48 -04:00 
			
		
		
		
	* update github.com/alecthomas/chroma v0.8.0 -> v0.8.1 * github.com/blevesearch/bleve v1.0.10 -> v1.0.12 * editorconfig-core-go v2.1.1 -> v2.3.7 * github.com/gliderlabs/ssh v0.2.2 -> v0.3.1 * migrate editorconfig.ParseBytes to Parse * github.com/shurcooL/vfsgen to 0d455de96546 * github.com/go-git/go-git/v5 v5.1.0 -> v5.2.0 * github.com/google/uuid v1.1.1 -> v1.1.2 * github.com/huandu/xstrings v1.3.0 -> v1.3.2 * github.com/klauspost/compress v1.10.11 -> v1.11.1 * github.com/markbates/goth v1.61.2 -> v1.65.0 * github.com/mattn/go-sqlite3 v1.14.0 -> v1.14.4 * github.com/mholt/archiver v3.3.0 -> v3.3.2 * github.com/microcosm-cc/bluemonday 4f7140c49acb -> v1.0.4 * github.com/minio/minio-go v7.0.4 -> v7.0.5 * github.com/olivere/elastic v7.0.9 -> v7.0.20 * github.com/urfave/cli v1.20.0 -> v1.22.4 * github.com/prometheus/client_golang v1.1.0 -> v1.8.0 * github.com/xanzy/go-gitlab v0.37.0 -> v0.38.1 * mvdan.cc/xurls v2.1.0 -> v2.2.0 Co-authored-by: Lauris BH <lauris@nix.lv>
		
			
				
	
	
		
			466 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			466 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| // 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"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| 	"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. bufio.Writer
 | |
| // 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 (
 | |
| 	initialNumBufSize = 24
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	bufPool = sync.Pool{
 | |
| 		New: func() interface{} {
 | |
| 			return bufio.NewWriter(ioutil.Discard)
 | |
| 		},
 | |
| 	}
 | |
| 	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
 | |
| 	// bufio.Writer from the sync.Pool.
 | |
| 	w, ok := out.(enhancedWriter)
 | |
| 	if !ok {
 | |
| 		b := bufPool.Get().(*bufio.Writer)
 | |
| 		b.Reset(out)
 | |
| 		w = b
 | |
| 		defer func() {
 | |
| 			bErr := b.Flush()
 | |
| 			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)
 | |
| 	}
 | |
| 	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
 | |
| }
 |