Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 

163 Zeilen
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/golang/protobuf/proto" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
  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. // 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 || ver == "") {
  92. return FmtOpenMetrics
  93. }
  94. }
  95. return FmtText
  96. }
  97. // NewEncoder returns a new encoder based on content type negotiation. All
  98. // Encoder implementations returned by NewEncoder also implement Closer, and
  99. // callers should always call the Close method. It is currently only required
  100. // for FmtOpenMetrics, but a future (breaking) release will add the Close method
  101. // to the Encoder interface directly. The current version of the Encoder
  102. // interface is kept for backwards compatibility.
  103. func NewEncoder(w io.Writer, format Format) Encoder {
  104. switch format {
  105. case FmtProtoDelim:
  106. return encoderCloser{
  107. encode: func(v *dto.MetricFamily) error {
  108. _, err := pbutil.WriteDelimited(w, v)
  109. return err
  110. },
  111. close: func() error { return nil },
  112. }
  113. case FmtProtoCompact:
  114. return encoderCloser{
  115. encode: func(v *dto.MetricFamily) error {
  116. _, err := fmt.Fprintln(w, v.String())
  117. return err
  118. },
  119. close: func() error { return nil },
  120. }
  121. case FmtProtoText:
  122. return encoderCloser{
  123. encode: func(v *dto.MetricFamily) error {
  124. _, err := fmt.Fprintln(w, proto.MarshalTextString(v))
  125. return err
  126. },
  127. close: func() error { return nil },
  128. }
  129. case FmtText:
  130. return encoderCloser{
  131. encode: func(v *dto.MetricFamily) error {
  132. _, err := MetricFamilyToText(w, v)
  133. return err
  134. },
  135. close: func() error { return nil },
  136. }
  137. case FmtOpenMetrics:
  138. return encoderCloser{
  139. encode: func(v *dto.MetricFamily) error {
  140. _, err := MetricFamilyToOpenMetrics(w, v)
  141. return err
  142. },
  143. close: func() error {
  144. _, err := FinalizeOpenMetrics(w)
  145. return err
  146. },
  147. }
  148. }
  149. panic(fmt.Errorf("expfmt.NewEncoder: unknown format %q", format))
  150. }