...
1
2
3
4
5
6
7
8
9
10
11
12
13
14 package expfmt
15
16 import (
17 "fmt"
18 "io"
19 "net/http"
20
21 "google.golang.org/protobuf/encoding/protodelim"
22 "google.golang.org/protobuf/encoding/prototext"
23
24 "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg"
25 "github.com/prometheus/common/model"
26
27 dto "github.com/prometheus/client_model/go"
28 )
29
30
31 type Encoder interface {
32 Encode(*dto.MetricFamily) error
33 }
34
35
36
37
38
39
40
41
42 type Closer interface {
43 Close() error
44 }
45
46 type encoderCloser struct {
47 encode func(*dto.MetricFamily) error
48 close func() error
49 }
50
51 func (ec encoderCloser) Encode(v *dto.MetricFamily) error {
52 return ec.encode(v)
53 }
54
55 func (ec encoderCloser) Close() error {
56 return ec.close()
57 }
58
59
60
61
62
63
64 func Negotiate(h http.Header) Format {
65 escapingScheme := Format(fmt.Sprintf("; escaping=%s", Format(model.NameEscapingScheme.String())))
66 for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
67 if escapeParam := ac.Params[model.EscapingKey]; escapeParam != "" {
68 switch Format(escapeParam) {
69 case model.AllowUTF8, model.EscapeUnderscores, model.EscapeDots, model.EscapeValues:
70 escapingScheme = Format(fmt.Sprintf("; escaping=%s", escapeParam))
71 default:
72
73 }
74 }
75 ver := ac.Params["version"]
76 if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
77 switch ac.Params["encoding"] {
78 case "delimited":
79 return fmtProtoDelim + escapingScheme
80 case "text":
81 return fmtProtoText + escapingScheme
82 case "compact-text":
83 return fmtProtoCompact + escapingScheme
84 }
85 }
86 if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
87 return fmtText + escapingScheme
88 }
89 }
90 return fmtText + escapingScheme
91 }
92
93
94
95
96
97 func NegotiateIncludingOpenMetrics(h http.Header) Format {
98 escapingScheme := Format(fmt.Sprintf("; escaping=%s", Format(model.NameEscapingScheme.String())))
99 for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
100 if escapeParam := ac.Params[model.EscapingKey]; escapeParam != "" {
101 switch Format(escapeParam) {
102 case model.AllowUTF8, model.EscapeUnderscores, model.EscapeDots, model.EscapeValues:
103 escapingScheme = Format(fmt.Sprintf("; escaping=%s", escapeParam))
104 default:
105
106 }
107 }
108 ver := ac.Params["version"]
109 if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
110 switch ac.Params["encoding"] {
111 case "delimited":
112 return fmtProtoDelim + escapingScheme
113 case "text":
114 return fmtProtoText + escapingScheme
115 case "compact-text":
116 return fmtProtoCompact + escapingScheme
117 }
118 }
119 if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
120 return fmtText + escapingScheme
121 }
122 if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion_0_0_1 || ver == OpenMetricsVersion_1_0_0 || ver == "") {
123 switch ver {
124 case OpenMetricsVersion_1_0_0:
125 return fmtOpenMetrics_1_0_0 + escapingScheme
126 default:
127 return fmtOpenMetrics_0_0_1 + escapingScheme
128 }
129 }
130 }
131 return fmtText + escapingScheme
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 func NewEncoder(w io.Writer, format Format, options ...EncoderOption) Encoder {
149 escapingScheme := format.ToEscapingScheme()
150
151 switch format.FormatType() {
152 case TypeProtoDelim:
153 return encoderCloser{
154 encode: func(v *dto.MetricFamily) error {
155 _, err := protodelim.MarshalTo(w, v)
156 return err
157 },
158 close: func() error { return nil },
159 }
160 case TypeProtoCompact:
161 return encoderCloser{
162 encode: func(v *dto.MetricFamily) error {
163 _, err := fmt.Fprintln(w, model.EscapeMetricFamily(v, escapingScheme).String())
164 return err
165 },
166 close: func() error { return nil },
167 }
168 case TypeProtoText:
169 return encoderCloser{
170 encode: func(v *dto.MetricFamily) error {
171 _, err := fmt.Fprintln(w, prototext.Format(model.EscapeMetricFamily(v, escapingScheme)))
172 return err
173 },
174 close: func() error { return nil },
175 }
176 case TypeTextPlain:
177 return encoderCloser{
178 encode: func(v *dto.MetricFamily) error {
179 _, err := MetricFamilyToText(w, model.EscapeMetricFamily(v, escapingScheme))
180 return err
181 },
182 close: func() error { return nil },
183 }
184 case TypeOpenMetrics:
185 return encoderCloser{
186 encode: func(v *dto.MetricFamily) error {
187 _, err := MetricFamilyToOpenMetrics(w, model.EscapeMetricFamily(v, escapingScheme), options...)
188 return err
189 },
190 close: func() error {
191 _, err := FinalizeOpenMetrics(w)
192 return err
193 },
194 }
195 }
196 panic(fmt.Errorf("expfmt.NewEncoder: unknown format %q", format))
197 }
198
View as plain text