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 (
	
	
	
	
	
	
	
	

	

	dto 
)
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{} {
			 := make([]byte, 0, initialNumBufSize)
			return &
		},
	}
)
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'.
Fail-fast checks.
	if len(.Metric) == 0 {
		return 0, fmt.Errorf("MetricFamily has no metrics: %s", )
	}
	 := .GetName()
	if  == "" {
		return 0, fmt.Errorf("MetricFamily has no name: %s", )
	}
Try the interface upgrade. If it doesn't work, we'll use a bufio.Writer from the sync.Pool.
	,  := .(enhancedWriter)
	if ! {
		 := bufPool.Get().(*bufio.Writer)
		.Reset()
		 = 
		defer func() {
			 := .Flush()
			if  == nil {
				 = 
			}
			bufPool.Put()
		}()
	}

	var  int
Comments, first HELP, then TYPE.
	if .Help != nil {
		,  = .WriteString("# HELP ")
		 += 
		if  != nil {
			return
		}
		,  = .WriteString()
		 += 
		if  != nil {
			return
		}
		 = .WriteByte(' ')
		++
		if  != nil {
			return
		}
		,  = writeEscapedString(, *.Help, false)
		 += 
		if  != nil {
			return
		}
		 = .WriteByte('\n')
		++
		if  != nil {
			return
		}
	}
	,  = .WriteString("# TYPE ")
	 += 
	if  != nil {
		return
	}
	,  = .WriteString()
	 += 
	if  != nil {
		return
	}
	 := .GetType()
	switch  {
	case dto.MetricType_COUNTER:
		,  = .WriteString(" counter\n")
	case dto.MetricType_GAUGE:
		,  = .WriteString(" gauge\n")
	case dto.MetricType_SUMMARY:
		,  = .WriteString(" summary\n")
	case dto.MetricType_UNTYPED:
		,  = .WriteString(" untyped\n")
	case dto.MetricType_HISTOGRAM:
		,  = .WriteString(" histogram\n")
	default:
		return , fmt.Errorf("unknown metric type %s", .String())
	}
	 += 
	if  != nil {
		return
	}
Finally the samples, one line for each.
	for ,  := range .Metric {
		switch  {
		case dto.MetricType_COUNTER:
			if .Counter == nil {
				return , fmt.Errorf(
					"expected counter in metric %s %s", , ,
				)
			}
			,  = writeSample(
				, , "", , "", 0,
				.Counter.GetValue(),
			)
		case dto.MetricType_GAUGE:
			if .Gauge == nil {
				return , fmt.Errorf(
					"expected gauge in metric %s %s", , ,
				)
			}
			,  = writeSample(
				, , "", , "", 0,
				.Gauge.GetValue(),
			)
		case dto.MetricType_UNTYPED:
			if .Untyped == nil {
				return , fmt.Errorf(
					"expected untyped in metric %s %s", , ,
				)
			}
			,  = writeSample(
				, , "", , "", 0,
				.Untyped.GetValue(),
			)
		case dto.MetricType_SUMMARY:
			if .Summary == nil {
				return , fmt.Errorf(
					"expected summary in metric %s %s", , ,
				)
			}
			for ,  := range .Summary.Quantile {
				,  = writeSample(
					, , "", ,
					model.QuantileLabel, .GetQuantile(),
					.GetValue(),
				)
				 += 
				if  != nil {
					return
				}
			}
			,  = writeSample(
				, , "_sum", , "", 0,
				.Summary.GetSampleSum(),
			)
			 += 
			if  != nil {
				return
			}
			,  = writeSample(
				, , "_count", , "", 0,
				float64(.Summary.GetSampleCount()),
			)
		case dto.MetricType_HISTOGRAM:
			if .Histogram == nil {
				return , fmt.Errorf(
					"expected histogram in metric %s %s", , ,
				)
			}
			 := false
			for ,  := range .Histogram.Bucket {
				,  = writeSample(
					, , "_bucket", ,
					model.BucketLabel, .GetUpperBound(),
					float64(.GetCumulativeCount()),
				)
				 += 
				if  != nil {
					return
				}
				if math.IsInf(.GetUpperBound(), +1) {
					 = true
				}
			}
			if ! {
				,  = writeSample(
					, , "_bucket", ,
					model.BucketLabel, math.Inf(+1),
					float64(.Histogram.GetSampleCount()),
				)
				 += 
				if  != nil {
					return
				}
			}
			,  = writeSample(
				, , "_sum", , "", 0,
				.Histogram.GetSampleSum(),
			)
			 += 
			if  != nil {
				return
			}
			,  = writeSample(
				, , "_count", , "", 0,
				float64(.Histogram.GetSampleCount()),
			)
		default:
			return , fmt.Errorf(
				"unexpected type in metric %s %s", , ,
			)
		}
		 += 
		if  != 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 (
	 enhancedWriter,
	,  string,
	 *dto.Metric,
	 string,  float64,
	 float64,
) (int, error) {
	var  int
	,  := .WriteString()
	 += 
	if  != nil {
		return , 
	}
	if  != "" {
		,  = .WriteString()
		 += 
		if  != nil {
			return , 
		}
	}
	,  = writeLabelPairs(
		, .Label, , ,
	)
	 += 
	if  != nil {
		return , 
	}
	 = .WriteByte(' ')
	++
	if  != nil {
		return , 
	}
	,  = writeFloat(, )
	 += 
	if  != nil {
		return , 
	}
	if .TimestampMs != nil {
		 = .WriteByte(' ')
		++
		if  != nil {
			return , 
		}
		,  = writeInt(, *.TimestampMs)
		 += 
		if  != nil {
			return , 
		}
	}
	 = .WriteByte('\n')
	++
	if  != nil {
		return , 
	}
	return , 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 (
	 enhancedWriter,
	 []*dto.LabelPair,
	 string,  float64,
) (int, error) {
	if len() == 0 &&  == "" {
		return 0, nil
	}
	var (
		   int
		 byte = '{'
	)
	for ,  := range  {
		 := .WriteByte()
		++
		if  != nil {
			return , 
		}
		,  := .WriteString(.GetName())
		 += 
		if  != nil {
			return , 
		}
		,  = .WriteString(`="`)
		 += 
		if  != nil {
			return , 
		}
		,  = writeEscapedString(, .GetValue(), true)
		 += 
		if  != nil {
			return , 
		}
		 = .WriteByte('"')
		++
		if  != nil {
			return , 
		}
		 = ','
	}
	if  != "" {
		 := .WriteByte()
		++
		if  != nil {
			return , 
		}
		,  := .WriteString()
		 += 
		if  != nil {
			return , 
		}
		,  = .WriteString(`="`)
		 += 
		if  != nil {
			return , 
		}
		,  = writeFloat(, )
		 += 
		if  != nil {
			return , 
		}
		 = .WriteByte('"')
		++
		if  != nil {
			return , 
		}
	}
	 := .WriteByte('}')
	++
	if  != nil {
		return , 
	}
	return , 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 ( enhancedWriter,  string,  bool) (int, error) {
	if  {
		return quotedEscaper.WriteString(, )
	} else {
		return escaper.WriteString(, )
	}
}
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 ( enhancedWriter,  float64) (int, error) {
	switch {
	case  == 1:
		return 1, .WriteByte('1')
	case  == 0:
		return 1, .WriteByte('0')
	case  == -1:
		return .WriteString("-1")
	case math.IsNaN():
		return .WriteString("NaN")
	case math.IsInf(, +1):
		return .WriteString("+Inf")
	case math.IsInf(, -1):
		return .WriteString("-Inf")
	default:
		 := numBufPool.Get().(*[]byte)
		* = strconv.AppendFloat((*)[:0], , 'g', -1, 64)
		,  := .Write(*)
		numBufPool.Put()
		return , 
	}
}
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 ( enhancedWriter,  int64) (int, error) {
	 := numBufPool.Get().(*[]byte)
	* = strconv.AppendInt((*)[:0], , 10)
	,  := .Write(*)
	numBufPool.Put()
	return ,