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