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 }