Commit 75530cee authored by ale's avatar ale

Fix metrics export

Actually register the right prometheus Handler. Also make the server
wait for a metrics collection cycle to complete before starting the
HTTP server, so we never serve missing metrics.
parent 28473d5d
Pipeline #390 passed with stages
in 50 seconds
......@@ -5,7 +5,6 @@ import (
"bytes"
"flag"
"io"
"io/ioutil"
"log"
"net"
"net/http"
......@@ -24,7 +23,17 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var addr = flag.String("addr", ":3909", "address to listen on")
var (
addr = flag.String("addr", ":3909", "address to listen on")
updateInterval = flag.Duration("interval", 10*time.Second, "update interval")
doDebug = flag.Bool("debug", false, "log debug messages")
)
func debug(s string, args ...interface{}) {
if *doDebug {
log.Printf(s, args...)
}
}
func splitServiceName(path string) (string, string) {
slice, name := filepath.Split(path)
......@@ -82,13 +91,13 @@ func parseBlkioMapFile(path string) (map[string]int64, error) {
return result, scanner.Err()
}
func parseSingleValueFile(path string) (int64, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return 0, err
}
return strconv.ParseInt(string(data), 10, 64)
}
// func parseSingleValueFile(path string) (int64, error) {
// data, err := ioutil.ReadFile(path)
// if err != nil {
// return 0, err
// }
// return strconv.ParseInt(string(data), 10, 64)
// }
func cgroupStatPath(cgroupPath, collector, path string) string {
return filepath.Join("/sys/fs/cgroup", collector, cgroupPath, path)
......@@ -285,13 +294,13 @@ func walkCGroups() ([]prometheus.Metric, error) {
}
func walkCGroup(path string) ([]prometheus.Metric, error) {
log.Printf("found service %s", path)
debug("found service %s", path)
var metrics []prometheus.Metric
for _, s := range subsystems {
m, err := s.parse(path)
if err != nil {
log.Printf("service %s, subsystem %v: error: %v", path, s, err)
debug("service %s, subsystem %v: error: %v", path, s, err)
continue
}
metrics = append(metrics, m...)
......@@ -306,6 +315,17 @@ func walkCGroup(path string) ([]prometheus.Metric, error) {
type collector struct {
mx sync.Mutex
metrics []prometheus.Metric
readyCh chan bool
}
func newCollector() *collector {
return &collector{
readyCh: make(chan bool),
}
}
func (c *collector) WaitReady() {
<-c.readyCh
}
func (c *collector) Describe(ch chan<- *prometheus.Desc) {
......@@ -314,22 +334,30 @@ func (c *collector) Describe(ch chan<- *prometheus.Desc) {
}
}
func (c *collector) update(metrics []prometheus.Metric) {
c.mx.Lock()
c.metrics = metrics
c.mx.Unlock()
}
func (c *collector) Collect(ch chan<- prometheus.Metric) {
c.mx.Lock()
defer c.mx.Unlock()
count := 0
for _, m := range c.metrics {
ch <- m
count++
}
debug("collected %d metrics", count)
c.mx.Unlock()
}
func (c *collector) update(metrics []prometheus.Metric) {
c.mx.Lock()
c.metrics = metrics
c.mx.Unlock()
}
func (c *collector) loop(ctx context.Context) {
ticker := time.NewTicker(60 * time.Second)
if m, err := walkCGroups(); err == nil {
c.update(m)
}
close(c.readyCh)
ticker := time.NewTicker(*updateInterval)
defer ticker.Stop()
for {
select {
......@@ -347,10 +375,25 @@ func main() {
log.SetFlags(0)
flag.Parse()
c := newCollector()
reg := prometheus.NewRegistry()
reg.MustRegister(c)
// Create a cancelable Context and cancel it when we receive a
// termination signal. This will stop the metrics updater.
ctx, cancel := context.WithCancel(context.Background())
// Run the update loop in a goroutine.
go c.loop(ctx)
// Only start the HTTP server if we have collected the first
// round of metrics.
c.WaitReady()
// Create a very simple HTTP server that only exposes the
// Prometheus metrics handler.
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
mux.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
io.WriteString(w, `<html>
......@@ -375,10 +418,6 @@ func main() {
MaxHeaderBytes: 1 << 20,
}
// Create a cancelable Context and cancel it when we receive a
// termination signal. This will stop the metrics updater.
ctx, cancel := context.WithCancel(context.Background())
sigCh := make(chan os.Signal, 1)
go func() {
<-sigCh
......@@ -387,12 +426,5 @@ func main() {
}()
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
// Run the update loop in a goroutine.
c := &collector{}
go c.loop(ctx)
reg := prometheus.NewRegistry()
reg.MustRegister(c)
log.Fatal(srv.Serve(l))
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment