Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / github.com / prometheus / client_golang / prometheus / expvar_collector.go
1 // Copyright 2014 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         "encoding/json"
18         "expvar"
19 )
20
21 type expvarCollector struct {
22         exports map[string]*Desc
23 }
24
25 // NewExpvarCollector returns a newly allocated expvar Collector that still has
26 // to be registered with a Prometheus registry.
27 //
28 // An expvar Collector collects metrics from the expvar interface. It provides a
29 // quick way to expose numeric values that are already exported via expvar as
30 // Prometheus metrics. Note that the data models of expvar and Prometheus are
31 // fundamentally different, and that the expvar Collector is inherently slower
32 // than native Prometheus metrics. Thus, the expvar Collector is probably great
33 // for experiments and prototying, but you should seriously consider a more
34 // direct implementation of Prometheus metrics for monitoring production
35 // systems.
36 //
37 // The exports map has the following meaning:
38 //
39 // The keys in the map correspond to expvar keys, i.e. for every expvar key you
40 // want to export as Prometheus metric, you need an entry in the exports
41 // map. The descriptor mapped to each key describes how to export the expvar
42 // value. It defines the name and the help string of the Prometheus metric
43 // proxying the expvar value. The type will always be Untyped.
44 //
45 // For descriptors without variable labels, the expvar value must be a number or
46 // a bool. The number is then directly exported as the Prometheus sample
47 // value. (For a bool, 'false' translates to 0 and 'true' to 1). Expvar values
48 // that are not numbers or bools are silently ignored.
49 //
50 // If the descriptor has one variable label, the expvar value must be an expvar
51 // map. The keys in the expvar map become the various values of the one
52 // Prometheus label. The values in the expvar map must be numbers or bools again
53 // as above.
54 //
55 // For descriptors with more than one variable label, the expvar must be a
56 // nested expvar map, i.e. where the values of the topmost map are maps again
57 // etc. until a depth is reached that corresponds to the number of labels. The
58 // leaves of that structure must be numbers or bools as above to serve as the
59 // sample values.
60 //
61 // Anything that does not fit into the scheme above is silently ignored.
62 func NewExpvarCollector(exports map[string]*Desc) Collector {
63         return &expvarCollector{
64                 exports: exports,
65         }
66 }
67
68 // Describe implements Collector.
69 func (e *expvarCollector) Describe(ch chan<- *Desc) {
70         for _, desc := range e.exports {
71                 ch <- desc
72         }
73 }
74
75 // Collect implements Collector.
76 func (e *expvarCollector) Collect(ch chan<- Metric) {
77         for name, desc := range e.exports {
78                 var m Metric
79                 expVar := expvar.Get(name)
80                 if expVar == nil {
81                         continue
82                 }
83                 var v interface{}
84                 labels := make([]string, len(desc.variableLabels))
85                 if err := json.Unmarshal([]byte(expVar.String()), &v); err != nil {
86                         ch <- NewInvalidMetric(desc, err)
87                         continue
88                 }
89                 var processValue func(v interface{}, i int)
90                 processValue = func(v interface{}, i int) {
91                         if i >= len(labels) {
92                                 copiedLabels := append(make([]string, 0, len(labels)), labels...)
93                                 switch v := v.(type) {
94                                 case float64:
95                                         m = MustNewConstMetric(desc, UntypedValue, v, copiedLabels...)
96                                 case bool:
97                                         if v {
98                                                 m = MustNewConstMetric(desc, UntypedValue, 1, copiedLabels...)
99                                         } else {
100                                                 m = MustNewConstMetric(desc, UntypedValue, 0, copiedLabels...)
101                                         }
102                                 default:
103                                         return
104                                 }
105                                 ch <- m
106                                 return
107                         }
108                         vm, ok := v.(map[string]interface{})
109                         if !ok {
110                                 return
111                         }
112                         for lv, val := range vm {
113                                 labels[i] = lv
114                                 processValue(val, i+1)
115                         }
116                 }
117                 processValue(v, 0)
118         }
119 }