wrap.go 5.3 KB

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