decode.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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. package expfmt
  14. import (
  15. "bufio"
  16. "fmt"
  17. "io"
  18. "math"
  19. "mime"
  20. "net/http"
  21. dto "github.com/prometheus/client_model/go"
  22. "google.golang.org/protobuf/encoding/protodelim"
  23. "github.com/prometheus/common/model"
  24. )
  25. // Decoder types decode an input stream into metric families.
  26. type Decoder interface {
  27. Decode(*dto.MetricFamily) error
  28. }
  29. // DecodeOptions contains options used by the Decoder and in sample extraction.
  30. type DecodeOptions struct {
  31. // Timestamp is added to each value from the stream that has no explicit timestamp set.
  32. Timestamp model.Time
  33. }
  34. // ResponseFormat extracts the correct format from a HTTP response header.
  35. // If no matching format can be found FormatUnknown is returned.
  36. func ResponseFormat(h http.Header) Format {
  37. ct := h.Get(hdrContentType)
  38. mediatype, params, err := mime.ParseMediaType(ct)
  39. if err != nil {
  40. return fmtUnknown
  41. }
  42. const textType = "text/plain"
  43. switch mediatype {
  44. case ProtoType:
  45. if p, ok := params["proto"]; ok && p != ProtoProtocol {
  46. return fmtUnknown
  47. }
  48. if e, ok := params["encoding"]; ok && e != "delimited" {
  49. return fmtUnknown
  50. }
  51. return fmtProtoDelim
  52. case textType:
  53. if v, ok := params["version"]; ok && v != TextVersion {
  54. return fmtUnknown
  55. }
  56. return fmtText
  57. }
  58. return fmtUnknown
  59. }
  60. // NewDecoder returns a new decoder based on the given input format.
  61. // If the input format does not imply otherwise, a text format decoder is returned.
  62. func NewDecoder(r io.Reader, format Format) Decoder {
  63. switch format.FormatType() {
  64. case TypeProtoDelim:
  65. return &protoDecoder{r: r}
  66. }
  67. return &textDecoder{r: r}
  68. }
  69. // protoDecoder implements the Decoder interface for protocol buffers.
  70. type protoDecoder struct {
  71. r io.Reader
  72. }
  73. // Decode implements the Decoder interface.
  74. func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
  75. opts := protodelim.UnmarshalOptions{
  76. MaxSize: -1,
  77. }
  78. if err := opts.UnmarshalFrom(bufio.NewReader(d.r), v); err != nil {
  79. return err
  80. }
  81. if !model.IsValidMetricName(model.LabelValue(v.GetName())) {
  82. return fmt.Errorf("invalid metric name %q", v.GetName())
  83. }
  84. for _, m := range v.GetMetric() {
  85. if m == nil {
  86. continue
  87. }
  88. for _, l := range m.GetLabel() {
  89. if l == nil {
  90. continue
  91. }
  92. if !model.LabelValue(l.GetValue()).IsValid() {
  93. return fmt.Errorf("invalid label value %q", l.GetValue())
  94. }
  95. if !model.LabelName(l.GetName()).IsValid() {
  96. return fmt.Errorf("invalid label name %q", l.GetName())
  97. }
  98. }
  99. }
  100. return nil
  101. }
  102. // textDecoder implements the Decoder interface for the text protocol.
  103. type textDecoder struct {
  104. r io.Reader
  105. fams map[string]*dto.MetricFamily
  106. err error
  107. }
  108. // Decode implements the Decoder interface.
  109. func (d *textDecoder) Decode(v *dto.MetricFamily) error {
  110. if d.err == nil {
  111. // Read all metrics in one shot.
  112. var p TextParser
  113. d.fams, d.err = p.TextToMetricFamilies(d.r)
  114. // If we don't get an error, store io.EOF for the end.
  115. if d.err == nil {
  116. d.err = io.EOF
  117. }
  118. }
  119. // Pick off one MetricFamily per Decode until there's nothing left.
  120. for key, fam := range d.fams {
  121. v.Name = fam.Name
  122. v.Help = fam.Help
  123. v.Type = fam.Type
  124. v.Metric = fam.Metric
  125. delete(d.fams, key)
  126. return nil
  127. }
  128. return d.err
  129. }
  130. // SampleDecoder wraps a Decoder to extract samples from the metric families
  131. // decoded by the wrapped Decoder.
  132. type SampleDecoder struct {
  133. Dec Decoder
  134. Opts *DecodeOptions
  135. f dto.MetricFamily
  136. }
  137. // Decode calls the Decode method of the wrapped Decoder and then extracts the
  138. // samples from the decoded MetricFamily into the provided model.Vector.
  139. func (sd *SampleDecoder) Decode(s *model.Vector) error {
  140. err := sd.Dec.Decode(&sd.f)
  141. if err != nil {
  142. return err
  143. }
  144. *s, err = extractSamples(&sd.f, sd.Opts)
  145. return err
  146. }
  147. // ExtractSamples builds a slice of samples from the provided metric
  148. // families. If an error occurs during sample extraction, it continues to
  149. // extract from the remaining metric families. The returned error is the last
  150. // error that has occurred.
  151. func ExtractSamples(o *DecodeOptions, fams ...*dto.MetricFamily) (model.Vector, error) {
  152. var (
  153. all model.Vector
  154. lastErr error
  155. )
  156. for _, f := range fams {
  157. some, err := extractSamples(f, o)
  158. if err != nil {
  159. lastErr = err
  160. continue
  161. }
  162. all = append(all, some...)
  163. }
  164. return all, lastErr
  165. }
  166. func extractSamples(f *dto.MetricFamily, o *DecodeOptions) (model.Vector, error) {
  167. switch f.GetType() {
  168. case dto.MetricType_COUNTER:
  169. return extractCounter(o, f), nil
  170. case dto.MetricType_GAUGE:
  171. return extractGauge(o, f), nil
  172. case dto.MetricType_SUMMARY:
  173. return extractSummary(o, f), nil
  174. case dto.MetricType_UNTYPED:
  175. return extractUntyped(o, f), nil
  176. case dto.MetricType_HISTOGRAM:
  177. return extractHistogram(o, f), nil
  178. }
  179. return nil, fmt.Errorf("expfmt.extractSamples: unknown metric family type %v", f.GetType())
  180. }
  181. func extractCounter(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
  182. samples := make(model.Vector, 0, len(f.Metric))
  183. for _, m := range f.Metric {
  184. if m.Counter == nil {
  185. continue
  186. }
  187. lset := make(model.LabelSet, len(m.Label)+1)
  188. for _, p := range m.Label {
  189. lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
  190. }
  191. lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
  192. smpl := &model.Sample{
  193. Metric: model.Metric(lset),
  194. Value: model.SampleValue(m.Counter.GetValue()),
  195. }
  196. if m.TimestampMs != nil {
  197. smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
  198. } else {
  199. smpl.Timestamp = o.Timestamp
  200. }
  201. samples = append(samples, smpl)
  202. }
  203. return samples
  204. }
  205. func extractGauge(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
  206. samples := make(model.Vector, 0, len(f.Metric))
  207. for _, m := range f.Metric {
  208. if m.Gauge == nil {
  209. continue
  210. }
  211. lset := make(model.LabelSet, len(m.Label)+1)
  212. for _, p := range m.Label {
  213. lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
  214. }
  215. lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
  216. smpl := &model.Sample{
  217. Metric: model.Metric(lset),
  218. Value: model.SampleValue(m.Gauge.GetValue()),
  219. }
  220. if m.TimestampMs != nil {
  221. smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
  222. } else {
  223. smpl.Timestamp = o.Timestamp
  224. }
  225. samples = append(samples, smpl)
  226. }
  227. return samples
  228. }
  229. func extractUntyped(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
  230. samples := make(model.Vector, 0, len(f.Metric))
  231. for _, m := range f.Metric {
  232. if m.Untyped == nil {
  233. continue
  234. }
  235. lset := make(model.LabelSet, len(m.Label)+1)
  236. for _, p := range m.Label {
  237. lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
  238. }
  239. lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
  240. smpl := &model.Sample{
  241. Metric: model.Metric(lset),
  242. Value: model.SampleValue(m.Untyped.GetValue()),
  243. }
  244. if m.TimestampMs != nil {
  245. smpl.Timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
  246. } else {
  247. smpl.Timestamp = o.Timestamp
  248. }
  249. samples = append(samples, smpl)
  250. }
  251. return samples
  252. }
  253. func extractSummary(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
  254. samples := make(model.Vector, 0, len(f.Metric))
  255. for _, m := range f.Metric {
  256. if m.Summary == nil {
  257. continue
  258. }
  259. timestamp := o.Timestamp
  260. if m.TimestampMs != nil {
  261. timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
  262. }
  263. for _, q := range m.Summary.Quantile {
  264. lset := make(model.LabelSet, len(m.Label)+2)
  265. for _, p := range m.Label {
  266. lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
  267. }
  268. // BUG(matt): Update other names to "quantile".
  269. lset[model.LabelName(model.QuantileLabel)] = model.LabelValue(fmt.Sprint(q.GetQuantile()))
  270. lset[model.MetricNameLabel] = model.LabelValue(f.GetName())
  271. samples = append(samples, &model.Sample{
  272. Metric: model.Metric(lset),
  273. Value: model.SampleValue(q.GetValue()),
  274. Timestamp: timestamp,
  275. })
  276. }
  277. lset := make(model.LabelSet, len(m.Label)+1)
  278. for _, p := range m.Label {
  279. lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
  280. }
  281. lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
  282. samples = append(samples, &model.Sample{
  283. Metric: model.Metric(lset),
  284. Value: model.SampleValue(m.Summary.GetSampleSum()),
  285. Timestamp: timestamp,
  286. })
  287. lset = make(model.LabelSet, len(m.Label)+1)
  288. for _, p := range m.Label {
  289. lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
  290. }
  291. lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
  292. samples = append(samples, &model.Sample{
  293. Metric: model.Metric(lset),
  294. Value: model.SampleValue(m.Summary.GetSampleCount()),
  295. Timestamp: timestamp,
  296. })
  297. }
  298. return samples
  299. }
  300. func extractHistogram(o *DecodeOptions, f *dto.MetricFamily) model.Vector {
  301. samples := make(model.Vector, 0, len(f.Metric))
  302. for _, m := range f.Metric {
  303. if m.Histogram == nil {
  304. continue
  305. }
  306. timestamp := o.Timestamp
  307. if m.TimestampMs != nil {
  308. timestamp = model.TimeFromUnixNano(*m.TimestampMs * 1000000)
  309. }
  310. infSeen := false
  311. for _, q := range m.Histogram.Bucket {
  312. lset := make(model.LabelSet, len(m.Label)+2)
  313. for _, p := range m.Label {
  314. lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
  315. }
  316. lset[model.LabelName(model.BucketLabel)] = model.LabelValue(fmt.Sprint(q.GetUpperBound()))
  317. lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
  318. if math.IsInf(q.GetUpperBound(), +1) {
  319. infSeen = true
  320. }
  321. samples = append(samples, &model.Sample{
  322. Metric: model.Metric(lset),
  323. Value: model.SampleValue(q.GetCumulativeCount()),
  324. Timestamp: timestamp,
  325. })
  326. }
  327. lset := make(model.LabelSet, len(m.Label)+1)
  328. for _, p := range m.Label {
  329. lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
  330. }
  331. lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_sum")
  332. samples = append(samples, &model.Sample{
  333. Metric: model.Metric(lset),
  334. Value: model.SampleValue(m.Histogram.GetSampleSum()),
  335. Timestamp: timestamp,
  336. })
  337. lset = make(model.LabelSet, len(m.Label)+1)
  338. for _, p := range m.Label {
  339. lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
  340. }
  341. lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_count")
  342. count := &model.Sample{
  343. Metric: model.Metric(lset),
  344. Value: model.SampleValue(m.Histogram.GetSampleCount()),
  345. Timestamp: timestamp,
  346. }
  347. samples = append(samples, count)
  348. if !infSeen {
  349. // Append an infinity bucket sample.
  350. lset := make(model.LabelSet, len(m.Label)+2)
  351. for _, p := range m.Label {
  352. lset[model.LabelName(p.GetName())] = model.LabelValue(p.GetValue())
  353. }
  354. lset[model.LabelName(model.BucketLabel)] = model.LabelValue("+Inf")
  355. lset[model.MetricNameLabel] = model.LabelValue(f.GetName() + "_bucket")
  356. samples = append(samples, &model.Sample{
  357. Metric: model.Metric(lset),
  358. Value: count.Value,
  359. Timestamp: timestamp,
  360. })
  361. }
  362. }
  363. return samples
  364. }