func init() { // NOTE(stevvooe): Setup registry metrics structure to report to expvar. // Ideally, we do more metrics through logging but we need some nice // realtime metrics for queue state for now. registry := expvar.Get("registry") if registry == nil { registry = expvar.NewMap("registry") } var notifications expvar.Map notifications.Init() notifications.Set("endpoints", expvar.Func(func() interface{} { endpoints.mu.Lock() defer endpoints.mu.Unlock() var names []interface{} for _, v := range endpoints.registered { var epjson struct { Name string `json:"name"` URL string `json:"url"` EndpointConfig Metrics EndpointMetrics } epjson.Name = v.Name() epjson.URL = v.URL() epjson.EndpointConfig = v.EndpointConfig v.ReadMetrics(&epjson.Metrics) names = append(names, epjson) } return names })) registry.(*expvar.Map).Set("notifications", ¬ifications) }
// TODO: maybe we should use Func() and just keep a stats structure. // But that would require locking and nngh nngh. func setupExpvars() { var m expvar.Map m.Init() m.Set("notls", expvar.Func(notls.Stats)) m.Set("yakkers", expvar.Func(yakkers.Stats)) stats.Set("sizes", &m) stats.Set("dnsbl_hits", expvar.Func(dblcounts.Stats)) stats.Set("sbl_hits", expvar.Func(sblcounts.Stats)) // BUG: must remember to do this for all counters so they have // an initial value. var evts expvar.Map evts.Init() evts.Set("connections", &events.connections) evts.Set("tls_errors", &events.tlserrs) evts.Set("yakkers", &events.yakkers) evts.Set("notls_conns", &events.notlscnt) evts.Set("rules_errors", &events.ruleserr) evts.Set("yakker_adds", &events.yakads) evts.Set("rsetdrops", &events.rsetdrops) evts.Set("abandons", &events.abandons) evts.Set("refuseds", &events.refuseds) stats.Set("events", &evts) var mailevts expvar.Map var goodevts expvar.Map var cmds expvar.Map mailevts.Init() goodevts.Init() cmds.Init() // Maybe these should track refused commands? Not sure. cmds.Set("ehlo", &events.ehlo) cmds.Set("mailfrom", &events.mailfrom) cmds.Set("rcptto", &events.rcptto) cmds.Set("data", &events.data) mailevts.Set("commands", &cmds) // These are counts of *accepted* commands. // TODO: maybe revise how things are counted? Dunno. goodevts.Set("ehlo", &events.ehloAccept) goodevts.Set("mailfrom", &events.mailfromAccept) goodevts.Set("rcptto", &events.rcpttoAccept) goodevts.Set("data", &events.dataAccept) goodevts.Set("messages", &events.messages) mailevts.Set("accepted", &goodevts) mailevts.Set("ehlo_tlson", &events.tlson) mailevts.Set("quits", &events.quits) mailevts.Set("aborts", &events.aborts) mailevts.Set("rsets", &events.rsets) stats.Set("smtpcounts", &mailevts) // constants stats.Add("pid", int64(os.Getpid())) var stime expvar.String stime.Set(time.Now().String()) stats.Set("startTime", &stime) var conntime expvar.String times.Init() // We're going to have connections, so we set this now. times.Set("connection", &conntime) stats.Set("last", ×) }
func ExampleExpvarCollector() { expvarCollector := prometheus.NewExpvarCollector(map[string]*prometheus.Desc{ "memstats": prometheus.NewDesc( "expvar_memstats", "All numeric memstats as one metric family. Not a good role-model, actually... ;-)", []string{"type"}, nil, ), "lone-int": prometheus.NewDesc( "expvar_lone_int", "Just an expvar int as an example.", nil, nil, ), "http-request-map": prometheus.NewDesc( "expvar_http_request_total", "How many http requests processed, partitioned by status code and http method.", []string{"code", "method"}, nil, ), }) prometheus.MustRegister(expvarCollector) // The Prometheus part is done here. But to show that this example is // doing anything, we have to manually export something via expvar. In // real-life use-cases, some library would already have exported via // expvar what we want to re-export as Prometheus metrics. expvar.NewInt("lone-int").Set(42) expvarMap := expvar.NewMap("http-request-map") var ( expvarMap1, expvarMap2 expvar.Map expvarInt11, expvarInt12, expvarInt21, expvarInt22 expvar.Int ) expvarMap1.Init() expvarMap2.Init() expvarInt11.Set(3) expvarInt12.Set(13) expvarInt21.Set(11) expvarInt22.Set(212) expvarMap1.Set("POST", &expvarInt11) expvarMap1.Set("GET", &expvarInt12) expvarMap2.Set("POST", &expvarInt21) expvarMap2.Set("GET", &expvarInt22) expvarMap.Set("404", &expvarMap1) expvarMap.Set("200", &expvarMap2) // Results in the following expvar map: // "http-request-count": {"200": {"POST": 11, "GET": 212}, "404": {"POST": 3, "GET": 13}} // Let's see what the scrape would yield, but exclude the memstats metrics. metricStrings := []string{} metric := dto.Metric{} metricChan := make(chan prometheus.Metric) go func() { expvarCollector.Collect(metricChan) close(metricChan) }() for m := range metricChan { if strings.Index(m.Desc().String(), "expvar_memstats") == -1 { metric.Reset() m.Write(&metric) metricStrings = append(metricStrings, metric.String()) } } sort.Strings(metricStrings) for _, s := range metricStrings { fmt.Println(strings.TrimRight(s, " ")) } // Output: // label:<name:"code" value:"200" > label:<name:"method" value:"GET" > untyped:<value:212 > // label:<name:"code" value:"200" > label:<name:"method" value:"POST" > untyped:<value:11 > // label:<name:"code" value:"404" > label:<name:"method" value:"GET" > untyped:<value:13 > // label:<name:"code" value:"404" > label:<name:"method" value:"POST" > untyped:<value:3 > // untyped:<value:42 > }