gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/prometheus/common/expfmt/encode.go (about)

     1  // Copyright 2015 The Prometheus Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package expfmt
    15  
    16  import (
    17  	"fmt"
    18  	"io"
    19  
    20  	http "gitee.com/ks-custle/core-gm/gmhttp"
    21  	"gitee.com/ks-custle/core-gm/prometheus/common/internal/bitbucket.org/ww/goautoneg"
    22  	"github.com/golang/protobuf/proto" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
    23  	"github.com/matttproud/golang_protobuf_extensions/pbutil"
    24  
    25  	dto "github.com/prometheus/client_model/go"
    26  )
    27  
    28  // Encoder types encode metric families into an underlying wire protocol.
    29  type Encoder interface {
    30  	Encode(*dto.MetricFamily) error
    31  }
    32  
    33  // Closer is implemented by Encoders that need to be closed to finalize
    34  // encoding. (For example, OpenMetrics needs a final `# EOF` line.)
    35  //
    36  // Note that all Encoder implementations returned from this package implement
    37  // Closer, too, even if the Close call is a no-op. This happens in preparation
    38  // for adding a Close method to the Encoder interface directly in a (mildly
    39  // breaking) release in the future.
    40  type Closer interface {
    41  	Close() error
    42  }
    43  
    44  type encoderCloser struct {
    45  	encode func(*dto.MetricFamily) error
    46  	close  func() error
    47  }
    48  
    49  func (ec encoderCloser) Encode(v *dto.MetricFamily) error {
    50  	return ec.encode(v)
    51  }
    52  
    53  func (ec encoderCloser) Close() error {
    54  	return ec.close()
    55  }
    56  
    57  // Negotiate returns the Content-Type based on the given Accept header. If no
    58  // appropriate accepted type is found, FmtText is returned (which is the
    59  // Prometheus text format). This function will never negotiate FmtOpenMetrics,
    60  // as the support is still experimental. To include the option to negotiate
    61  // FmtOpenMetrics, use NegotiateOpenMetrics.
    62  func Negotiate(h http.Header) Format {
    63  	for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
    64  		ver := ac.Params["version"]
    65  		if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
    66  			switch ac.Params["encoding"] {
    67  			case "delimited":
    68  				return FmtProtoDelim
    69  			case "text":
    70  				return FmtProtoText
    71  			case "compact-text":
    72  				return FmtProtoCompact
    73  			}
    74  		}
    75  		if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
    76  			return FmtText
    77  		}
    78  	}
    79  	return FmtText
    80  }
    81  
    82  // NegotiateIncludingOpenMetrics works like Negotiate but includes
    83  // FmtOpenMetrics as an option for the result. Note that this function is
    84  // temporary and will disappear once FmtOpenMetrics is fully supported and as
    85  // such may be negotiated by the normal Negotiate function.
    86  func NegotiateIncludingOpenMetrics(h http.Header) Format {
    87  	for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
    88  		ver := ac.Params["version"]
    89  		if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
    90  			switch ac.Params["encoding"] {
    91  			case "delimited":
    92  				return FmtProtoDelim
    93  			case "text":
    94  				return FmtProtoText
    95  			case "compact-text":
    96  				return FmtProtoCompact
    97  			}
    98  		}
    99  		if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
   100  			return FmtText
   101  		}
   102  		if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion || ver == "") {
   103  			return FmtOpenMetrics
   104  		}
   105  	}
   106  	return FmtText
   107  }
   108  
   109  // NewEncoder returns a new encoder based on content type negotiation. All
   110  // Encoder implementations returned by NewEncoder also implement Closer, and
   111  // callers should always call the Close method. It is currently only required
   112  // for FmtOpenMetrics, but a future (breaking) release will add the Close method
   113  // to the Encoder interface directly. The current version of the Encoder
   114  // interface is kept for backwards compatibility.
   115  func NewEncoder(w io.Writer, format Format) Encoder {
   116  	switch format {
   117  	case FmtProtoDelim:
   118  		return encoderCloser{
   119  			encode: func(v *dto.MetricFamily) error {
   120  				_, err := pbutil.WriteDelimited(w, v)
   121  				return err
   122  			},
   123  			close: func() error { return nil },
   124  		}
   125  	case FmtProtoCompact:
   126  		return encoderCloser{
   127  			encode: func(v *dto.MetricFamily) error {
   128  				_, err := fmt.Fprintln(w, v.String())
   129  				return err
   130  			},
   131  			close: func() error { return nil },
   132  		}
   133  	case FmtProtoText:
   134  		return encoderCloser{
   135  			encode: func(v *dto.MetricFamily) error {
   136  				_, err := fmt.Fprintln(w, proto.MarshalTextString(v))
   137  				return err
   138  			},
   139  			close: func() error { return nil },
   140  		}
   141  	case FmtText:
   142  		return encoderCloser{
   143  			encode: func(v *dto.MetricFamily) error {
   144  				_, err := MetricFamilyToText(w, v)
   145  				return err
   146  			},
   147  			close: func() error { return nil },
   148  		}
   149  	case FmtOpenMetrics:
   150  		return encoderCloser{
   151  			encode: func(v *dto.MetricFamily) error {
   152  				_, err := MetricFamilyToOpenMetrics(w, v)
   153  				return err
   154  			},
   155  			close: func() error {
   156  				_, err := FinalizeOpenMetrics(w)
   157  				return err
   158  			},
   159  		}
   160  	}
   161  	panic(fmt.Errorf("expfmt.NewEncoder: unknown format %q", format))
   162  }