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 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} 89