You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

166 lines
5.1 KiB

  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/matttproud/golang_protobuf_extensions/pbutil"
  19. "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg"
  20. "google.golang.org/protobuf/encoding/prototext"
  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. // Closer is implemented by Encoders that need to be closed to finalize
  28. // encoding. (For example, OpenMetrics needs a final `# EOF` line.)
  29. //
  30. // Note that all Encoder implementations returned from this package implement
  31. // Closer, too, even if the Close call is a no-op. This happens in preparation
  32. // for adding a Close method to the Encoder interface directly in a (mildly
  33. // breaking) release in the future.
  34. type Closer interface {
  35. Close() error
  36. }
  37. type encoderCloser struct {
  38. encode func(*dto.MetricFamily) error
  39. close func() error
  40. }
  41. func (ec encoderCloser) Encode(v *dto.MetricFamily) error {
  42. return ec.encode(v)
  43. }
  44. func (ec encoderCloser) Close() error {
  45. return ec.close()
  46. }
  47. // Negotiate returns the Content-Type based on the given Accept header. If no
  48. // appropriate accepted type is found, FmtText is returned (which is the
  49. // Prometheus text format). This function will never negotiate FmtOpenMetrics,
  50. // as the support is still experimental. To include the option to negotiate
  51. // FmtOpenMetrics, use NegotiateOpenMetrics.
  52. func Negotiate(h http.Header) Format {
  53. for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
  54. ver := ac.Params["version"]
  55. if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
  56. switch ac.Params["encoding"] {
  57. case "delimited":
  58. return FmtProtoDelim
  59. case "text":
  60. return FmtProtoText
  61. case "compact-text":
  62. return FmtProtoCompact
  63. }
  64. }
  65. if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
  66. return FmtText
  67. }
  68. }
  69. return FmtText
  70. }
  71. // NegotiateIncludingOpenMetrics works like Negotiate but includes
  72. // FmtOpenMetrics as an option for the result. Note that this function is
  73. // temporary and will disappear once FmtOpenMetrics is fully supported and as
  74. // such may be negotiated by the normal Negotiate function.
  75. func NegotiateIncludingOpenMetrics(h http.Header) Format {
  76. for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
  77. ver := ac.Params["version"]
  78. if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
  79. switch ac.Params["encoding"] {
  80. case "delimited":
  81. return FmtProtoDelim
  82. case "text":
  83. return FmtProtoText
  84. case "compact-text":
  85. return FmtProtoCompact
  86. }
  87. }
  88. if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
  89. return FmtText
  90. }
  91. if ac.Type+"/"+ac.SubType == OpenMetricsType && (ver == OpenMetricsVersion_0_0_1 || ver == OpenMetricsVersion_1_0_0 || ver == "") {
  92. if ver == OpenMetricsVersion_1_0_0 {
  93. return FmtOpenMetrics_1_0_0
  94. }
  95. return FmtOpenMetrics_0_0_1
  96. }
  97. }
  98. return FmtText
  99. }
  100. // NewEncoder returns a new encoder based on content type negotiation. All
  101. // Encoder implementations returned by NewEncoder also implement Closer, and
  102. // callers should always call the Close method. It is currently only required
  103. // for FmtOpenMetrics, but a future (breaking) release will add the Close method
  104. // to the Encoder interface directly. The current version of the Encoder
  105. // interface is kept for backwards compatibility.
  106. func NewEncoder(w io.Writer, format Format) Encoder {
  107. switch format {
  108. case FmtProtoDelim:
  109. return encoderCloser{
  110. encode: func(v *dto.MetricFamily) error {
  111. _, err := pbutil.WriteDelimited(w, v)
  112. return err
  113. },
  114. close: func() error { return nil },
  115. }
  116. case FmtProtoCompact:
  117. return encoderCloser{
  118. encode: func(v *dto.MetricFamily) error {
  119. _, err := fmt.Fprintln(w, v.String())
  120. return err
  121. },
  122. close: func() error { return nil },
  123. }
  124. case FmtProtoText:
  125. return encoderCloser{
  126. encode: func(v *dto.MetricFamily) error {
  127. _, err := fmt.Fprintln(w, prototext.Format(v))
  128. return err
  129. },
  130. close: func() error { return nil },
  131. }
  132. case FmtText:
  133. return encoderCloser{
  134. encode: func(v *dto.MetricFamily) error {
  135. _, err := MetricFamilyToText(w, v)
  136. return err
  137. },
  138. close: func() error { return nil },
  139. }
  140. case FmtOpenMetrics_0_0_1, FmtOpenMetrics_1_0_0:
  141. return encoderCloser{
  142. encode: func(v *dto.MetricFamily) error {
  143. _, err := MetricFamilyToOpenMetrics(w, v)
  144. return err
  145. },
  146. close: func() error {
  147. _, err := FinalizeOpenMetrics(w)
  148. return err
  149. },
  150. }
  151. }
  152. panic(fmt.Errorf("expfmt.NewEncoder: unknown format %q", format))
  153. }