blob: 11839ed65ce379ae46aa8e6c1d513cf334d95b0c [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001// 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
14package expfmt
15
16import (
17 "fmt"
18 "io"
19 "net/http"
20
21 "github.com/golang/protobuf/proto"
22 "github.com/matttproud/golang_protobuf_extensions/pbutil"
23 "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg"
24
25 dto "github.com/prometheus/client_model/go"
26)
27
28// Encoder types encode metric families into an underlying wire protocol.
29type Encoder interface {
30 Encode(*dto.MetricFamily) error
31}
32
33type encoder func(*dto.MetricFamily) error
34
35func (e encoder) Encode(v *dto.MetricFamily) error {
36 return e(v)
37}
38
39// Negotiate returns the Content-Type based on the given Accept header.
40// If no appropriate accepted type is found, FmtText is returned.
41func Negotiate(h http.Header) Format {
42 for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
43 // Check for protocol buffer
44 if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
45 switch ac.Params["encoding"] {
46 case "delimited":
47 return FmtProtoDelim
48 case "text":
49 return FmtProtoText
50 case "compact-text":
51 return FmtProtoCompact
52 }
53 }
54 // Check for text format.
55 ver := ac.Params["version"]
56 if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
57 return FmtText
58 }
59 }
60 return FmtText
61}
62
63// NewEncoder returns a new encoder based on content type negotiation.
64func NewEncoder(w io.Writer, format Format) Encoder {
65 switch format {
66 case FmtProtoDelim:
67 return encoder(func(v *dto.MetricFamily) error {
68 _, err := pbutil.WriteDelimited(w, v)
69 return err
70 })
71 case FmtProtoCompact:
72 return encoder(func(v *dto.MetricFamily) error {
73 _, err := fmt.Fprintln(w, v.String())
74 return err
75 })
76 case FmtProtoText:
77 return encoder(func(v *dto.MetricFamily) error {
78 _, err := fmt.Fprintln(w, proto.MarshalTextString(v))
79 return err
80 })
81 case FmtText:
82 return encoder(func(v *dto.MetricFamily) error {
83 _, err := MetricFamilyToText(w, v)
84 return err
85 })
86 }
87 panic("expfmt.NewEncoder: unknown format")
88}