blob: 18a99d5faaa5b1ab812c4a16e679b9675a2928d7 [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001// 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
14package prometheus
15
16import (
17 "encoding/json"
18 "expvar"
19)
20
21type 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.
62func NewExpvarCollector(exports map[string]*Desc) Collector {
63 return &expvarCollector{
64 exports: exports,
65 }
66}
67
68// Describe implements Collector.
69func (e *expvarCollector) Describe(ch chan<- *Desc) {
70 for _, desc := range e.exports {
71 ch <- desc
72 }
73}
74
75// Collect implements Collector.
76func (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}