@@ -6,35 +6,34 @@ package exporter
66import (
77 "expvar"
88 "fmt"
9- "net/http"
10- "sort"
119 "strings"
1210
11+ "github.com/golang/glog"
1312 "github.com/google/mtail/internal/metrics"
13+ "github.com/google/mtail/internal/metrics/datum"
14+
15+ "github.com/prometheus/client_golang/prometheus"
1416)
1517
1618var (
1719 metricExportTotal = expvar .NewInt ("metric_export_total" )
1820)
1921
20- const (
21- prometheusFormat = "%s{%s} %s\n "
22- )
23-
2422func noHyphens (s string ) string {
2523 return strings .Replace (s , "-" , "_" , - 1 )
2624}
2725
28- // HandlePrometheusMetrics exports the metrics in a format readable by
29- // Prometheus via HTTP.
30- func (e * Exporter ) HandlePrometheusMetrics (w http.ResponseWriter , r * http.Request ) {
26+ // Describe implements the prometheus.Collector interface.
27+ func (e * Exporter ) Describe (c chan <- * prometheus.Desc ) {
28+ prometheus .DescribeByCollect (e , c )
29+ }
30+
31+ // Collect implements the prometheus.Collector interface.
32+ func (e * Exporter ) Collect (c chan <- prometheus.Metric ) {
3133 e .store .RLock ()
3234 defer e .store .RUnlock ()
3335
34- w .Header ().Add ("Content-type" , "text/plain; version=0.0.4" )
35-
3636 for _ , ml := range e .store .Metrics {
37- emittype := true
3837 lastSource := ""
3938 for _ , m := range ml {
4039 m .RLock ()
@@ -45,49 +44,57 @@ func (e *Exporter) HandlePrometheusMetrics(w http.ResponseWriter, r *http.Reques
4544 }
4645 metricExportTotal .Add (1 )
4746
48- if emittype {
49- fmt .Fprintf (w ,
50- "# TYPE %s %s\n " ,
51- noHyphens (m .Name ),
52- kindToPrometheusType (m .Kind ))
53- emittype = false
54- }
55-
56- lc := make (chan * metrics.LabelSet )
57- go m .EmitLabelSets (lc )
58- for l := range lc {
59- if m .Source != "" && m .Source != lastSource {
60- fmt .Fprintf (w , "# %s defined at %s\n " , noHyphens (m .Name ), m .Source )
61- // suppress redundant source comments
47+ lsc := make (chan * metrics.LabelSet )
48+ go m .EmitLabelSets (lsc )
49+ for ls := range lsc {
50+ if lastSource == "" {
6251 lastSource = m .Source
6352 }
64- line := metricToPrometheus (m , l , e .omitProgLabel )
65- fmt .Fprint (w , line )
53+ var keys []string
54+ var vals []string
55+ if ! e .omitProgLabel {
56+ keys = append (keys , "prog" )
57+ vals = append (vals , m .Program )
58+ }
59+ for k , v := range ls .Labels {
60+ keys = append (keys , k )
61+ vals = append (vals , v )
62+ }
63+ pM , err := prometheus .NewConstMetric (
64+ prometheus .NewDesc (noHyphens (m .Name ),
65+ fmt .Sprintf ("defined at %s" , lastSource ), keys , nil ),
66+ promTypeForKind (m .Kind ),
67+ promValueForDatum (ls .Datum ),
68+ vals ... )
69+ if err != nil {
70+ glog .Warning (err )
71+ continue
72+ }
73+ c <- prometheus .NewMetricWithTimestamp (ls .Datum .TimeUTC (), pM )
6674 }
6775 m .RUnlock ()
6876 }
6977 }
7078}
7179
72- func metricToPrometheus (m * metrics.Metric , l * metrics.LabelSet , omitProgLabel bool ) string {
73- s := make ([]string , 0 , len (l .Labels )+ 1 )
74- for k , v := range l .Labels {
75- // Prometheus quotes the value of each label=value pair.
76- s = append (s , fmt .Sprintf ("%s=%q" , k , v ))
77- }
78- sort .Strings (s )
79- if ! omitProgLabel {
80- s = append (s , fmt .Sprintf ("prog=\" %s\" " , m .Program ))
80+ func promTypeForKind (k metrics.Kind ) prometheus.ValueType {
81+ switch k {
82+ case metrics .Counter :
83+ return prometheus .CounterValue
84+ case metrics .Gauge :
85+ return prometheus .GaugeValue
86+ case metrics .Timer :
87+ return prometheus .GaugeValue
8188 }
82- return fmt .Sprintf (prometheusFormat ,
83- noHyphens (m .Name ),
84- strings .Join (s , "," ),
85- l .Datum .ValueString ())
89+ return prometheus .UntypedValue
8690}
8791
88- func kindToPrometheusType (kind metrics.Kind ) string {
89- if kind != metrics .Timer {
90- return strings .ToLower (kind .String ())
92+ func promValueForDatum (d datum.Datum ) float64 {
93+ switch n := d .(type ) {
94+ case * datum.IntDatum :
95+ return float64 (n .Get ())
96+ case * datum.FloatDatum :
97+ return n .Get ()
9198 }
92- return "gauge"
99+ return 0.
93100}
0 commit comments