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.
 
 

215 lines
6.6 KiB

  1. // Copyright 2018 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 prometheus
  14. import (
  15. "fmt"
  16. "sort"
  17. "github.com/prometheus/client_golang/prometheus/internal"
  18. dto "github.com/prometheus/client_model/go"
  19. "google.golang.org/protobuf/proto"
  20. )
  21. // WrapRegistererWith returns a Registerer wrapping the provided
  22. // Registerer. Collectors registered with the returned Registerer will be
  23. // registered with the wrapped Registerer in a modified way. The modified
  24. // Collector adds the provided Labels to all Metrics it collects (as
  25. // ConstLabels). The Metrics collected by the unmodified Collector must not
  26. // duplicate any of those labels. Wrapping a nil value is valid, resulting
  27. // in a no-op Registerer.
  28. //
  29. // WrapRegistererWith provides a way to add fixed labels to a subset of
  30. // Collectors. It should not be used to add fixed labels to all metrics
  31. // exposed. See also
  32. // https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels
  33. //
  34. // Conflicts between Collectors registered through the original Registerer with
  35. // Collectors registered through the wrapping Registerer will still be
  36. // detected. Any AlreadyRegisteredError returned by the Register method of
  37. // either Registerer will contain the ExistingCollector in the form it was
  38. // provided to the respective registry.
  39. //
  40. // The Collector example demonstrates a use of WrapRegistererWith.
  41. func WrapRegistererWith(labels Labels, reg Registerer) Registerer {
  42. return &wrappingRegisterer{
  43. wrappedRegisterer: reg,
  44. labels: labels,
  45. }
  46. }
  47. // WrapRegistererWithPrefix returns a Registerer wrapping the provided
  48. // Registerer. Collectors registered with the returned Registerer will be
  49. // registered with the wrapped Registerer in a modified way. The modified
  50. // Collector adds the provided prefix to the name of all Metrics it collects.
  51. // Wrapping a nil value is valid, resulting in a no-op Registerer.
  52. //
  53. // WrapRegistererWithPrefix is useful to have one place to prefix all metrics of
  54. // a sub-system. To make this work, register metrics of the sub-system with the
  55. // wrapping Registerer returned by WrapRegistererWithPrefix. It is rarely useful
  56. // to use the same prefix for all metrics exposed. In particular, do not prefix
  57. // metric names that are standardized across applications, as that would break
  58. // horizontal monitoring, for example the metrics provided by the Go collector
  59. // (see NewGoCollector) and the process collector (see NewProcessCollector). (In
  60. // fact, those metrics are already prefixed with “go_” or “process_”,
  61. // respectively.)
  62. //
  63. // Conflicts between Collectors registered through the original Registerer with
  64. // Collectors registered through the wrapping Registerer will still be
  65. // detected. Any AlreadyRegisteredError returned by the Register method of
  66. // either Registerer will contain the ExistingCollector in the form it was
  67. // provided to the respective registry.
  68. func WrapRegistererWithPrefix(prefix string, reg Registerer) Registerer {
  69. return &wrappingRegisterer{
  70. wrappedRegisterer: reg,
  71. prefix: prefix,
  72. }
  73. }
  74. type wrappingRegisterer struct {
  75. wrappedRegisterer Registerer
  76. prefix string
  77. labels Labels
  78. }
  79. func (r *wrappingRegisterer) Register(c Collector) error {
  80. if r.wrappedRegisterer == nil {
  81. return nil
  82. }
  83. return r.wrappedRegisterer.Register(&wrappingCollector{
  84. wrappedCollector: c,
  85. prefix: r.prefix,
  86. labels: r.labels,
  87. })
  88. }
  89. func (r *wrappingRegisterer) MustRegister(cs ...Collector) {
  90. if r.wrappedRegisterer == nil {
  91. return
  92. }
  93. for _, c := range cs {
  94. if err := r.Register(c); err != nil {
  95. panic(err)
  96. }
  97. }
  98. }
  99. func (r *wrappingRegisterer) Unregister(c Collector) bool {
  100. if r.wrappedRegisterer == nil {
  101. return false
  102. }
  103. return r.wrappedRegisterer.Unregister(&wrappingCollector{
  104. wrappedCollector: c,
  105. prefix: r.prefix,
  106. labels: r.labels,
  107. })
  108. }
  109. type wrappingCollector struct {
  110. wrappedCollector Collector
  111. prefix string
  112. labels Labels
  113. }
  114. func (c *wrappingCollector) Collect(ch chan<- Metric) {
  115. wrappedCh := make(chan Metric)
  116. go func() {
  117. c.wrappedCollector.Collect(wrappedCh)
  118. close(wrappedCh)
  119. }()
  120. for m := range wrappedCh {
  121. ch <- &wrappingMetric{
  122. wrappedMetric: m,
  123. prefix: c.prefix,
  124. labels: c.labels,
  125. }
  126. }
  127. }
  128. func (c *wrappingCollector) Describe(ch chan<- *Desc) {
  129. wrappedCh := make(chan *Desc)
  130. go func() {
  131. c.wrappedCollector.Describe(wrappedCh)
  132. close(wrappedCh)
  133. }()
  134. for desc := range wrappedCh {
  135. ch <- wrapDesc(desc, c.prefix, c.labels)
  136. }
  137. }
  138. func (c *wrappingCollector) unwrapRecursively() Collector {
  139. switch wc := c.wrappedCollector.(type) {
  140. case *wrappingCollector:
  141. return wc.unwrapRecursively()
  142. default:
  143. return wc
  144. }
  145. }
  146. type wrappingMetric struct {
  147. wrappedMetric Metric
  148. prefix string
  149. labels Labels
  150. }
  151. func (m *wrappingMetric) Desc() *Desc {
  152. return wrapDesc(m.wrappedMetric.Desc(), m.prefix, m.labels)
  153. }
  154. func (m *wrappingMetric) Write(out *dto.Metric) error {
  155. if err := m.wrappedMetric.Write(out); err != nil {
  156. return err
  157. }
  158. if len(m.labels) == 0 {
  159. // No wrapping labels.
  160. return nil
  161. }
  162. for ln, lv := range m.labels {
  163. out.Label = append(out.Label, &dto.LabelPair{
  164. Name: proto.String(ln),
  165. Value: proto.String(lv),
  166. })
  167. }
  168. sort.Sort(internal.LabelPairSorter(out.Label))
  169. return nil
  170. }
  171. func wrapDesc(desc *Desc, prefix string, labels Labels) *Desc {
  172. constLabels := Labels{}
  173. for _, lp := range desc.constLabelPairs {
  174. constLabels[*lp.Name] = *lp.Value
  175. }
  176. for ln, lv := range labels {
  177. if _, alreadyUsed := constLabels[ln]; alreadyUsed {
  178. return &Desc{
  179. fqName: desc.fqName,
  180. help: desc.help,
  181. variableLabels: desc.variableLabels,
  182. constLabelPairs: desc.constLabelPairs,
  183. err: fmt.Errorf("attempted wrapping with already existing label name %q", ln),
  184. }
  185. }
  186. constLabels[ln] = lv
  187. }
  188. // NewDesc will do remaining validations.
  189. newDesc := V2.NewDesc(prefix+desc.fqName, desc.help, desc.variableLabels, constLabels)
  190. // Propagate errors if there was any. This will override any errer
  191. // created by NewDesc above, i.e. earlier errors get precedence.
  192. if desc.err != nil {
  193. newDesc.err = desc.err
  194. }
  195. return newDesc
  196. }