encode.go 2.5 KB

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