mirror of
https://github.com/prometheus/node_exporter.git
synced 2024-11-23 20:36:21 +01:00
7569c6ce23
Fixed file-nr update function Fixed file-nr test case Fixed file-nr test case again Fixed file-nr separator to tab Updated file-nr to filenr. Updated file-nr to filenr. Fixed file-nr test cases, added comments Remove reporting the second value from file-nr as it will alwasy be zero in linux 2.6 and greator Renaming file-nr to filefd Updated build constraint Updates and code cleanup for filefd. Updated enabledCollectors with the correct name for filefd Fixed filefd test wording
182 lines
4.8 KiB
Go
182 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"net/http"
|
|
_ "net/http/pprof"
|
|
"os"
|
|
"os/signal"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/log"
|
|
|
|
"github.com/prometheus/node_exporter/collector"
|
|
)
|
|
|
|
const subsystem = "exporter"
|
|
|
|
var (
|
|
// set at build time
|
|
Version = "0.0.0.dev"
|
|
|
|
memProfile = flag.String("debug.memprofile-file", "", "Write memory profile to this file upon receipt of SIGUSR1.")
|
|
listenAddress = flag.String("web.listen-address", ":9100", "Address on which to expose metrics and web interface.")
|
|
metricsPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
|
|
enabledCollectors = flag.String("collectors.enabled", "diskstats,filesystem,loadavg,meminfo,stat,textfile,time,netdev,netstat,sockstat,filefd", "Comma-separated list of collectors to use.")
|
|
printCollectors = flag.Bool("collectors.print", false, "If true, print available collectors and exit.")
|
|
authUser = flag.String("auth.user", "", "Username for basic auth.")
|
|
authPass = flag.String("auth.pass", "", "Password for basic auth.")
|
|
|
|
collectorLabelNames = []string{"collector", "result"}
|
|
|
|
scrapeDurations = prometheus.NewSummaryVec(
|
|
prometheus.SummaryOpts{
|
|
Namespace: collector.Namespace,
|
|
Subsystem: subsystem,
|
|
Name: "scrape_duration_seconds",
|
|
Help: "node_exporter: Duration of a scrape job.",
|
|
},
|
|
collectorLabelNames,
|
|
)
|
|
)
|
|
|
|
// Implements Collector.
|
|
type NodeCollector struct {
|
|
collectors map[string]collector.Collector
|
|
}
|
|
|
|
// Implements Collector.
|
|
func (n NodeCollector) Describe(ch chan<- *prometheus.Desc) {
|
|
scrapeDurations.Describe(ch)
|
|
}
|
|
|
|
// Implements Collector.
|
|
func (n NodeCollector) Collect(ch chan<- prometheus.Metric) {
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(len(n.collectors))
|
|
for name, c := range n.collectors {
|
|
go func(name string, c collector.Collector) {
|
|
Execute(name, c, ch)
|
|
wg.Done()
|
|
}(name, c)
|
|
}
|
|
wg.Wait()
|
|
scrapeDurations.Collect(ch)
|
|
}
|
|
|
|
type basicAuthHandler struct {
|
|
handler http.HandlerFunc
|
|
user string
|
|
password string
|
|
}
|
|
|
|
func (h *basicAuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
user, password, ok := r.BasicAuth()
|
|
if !ok || password != h.password || user != h.user {
|
|
w.Header().Set("WWW-Authenticate", "Basic realm=\"metrics\"")
|
|
http.Error(w, "Invalid username or password", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
h.handler(w, r)
|
|
return
|
|
}
|
|
|
|
func Execute(name string, c collector.Collector, ch chan<- prometheus.Metric) {
|
|
begin := time.Now()
|
|
err := c.Update(ch)
|
|
duration := time.Since(begin)
|
|
var result string
|
|
|
|
if err != nil {
|
|
log.Errorf("ERROR: %s collector failed after %fs: %s", name, duration.Seconds(), err)
|
|
result = "error"
|
|
} else {
|
|
log.Debugf("OK: %s collector succeeded after %fs.", name, duration.Seconds())
|
|
result = "success"
|
|
}
|
|
scrapeDurations.WithLabelValues(name, result).Observe(duration.Seconds())
|
|
}
|
|
|
|
func loadCollectors() (map[string]collector.Collector, error) {
|
|
collectors := map[string]collector.Collector{}
|
|
for _, name := range strings.Split(*enabledCollectors, ",") {
|
|
fn, ok := collector.Factories[name]
|
|
if !ok {
|
|
return nil, fmt.Errorf("collector '%s' not available", name)
|
|
}
|
|
c, err := fn()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
collectors[name] = c
|
|
}
|
|
return collectors, nil
|
|
}
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
if *printCollectors {
|
|
collectorNames := make(sort.StringSlice, 0, len(collector.Factories))
|
|
for n, _ := range collector.Factories {
|
|
collectorNames = append(collectorNames, n)
|
|
}
|
|
collectorNames.Sort()
|
|
fmt.Printf("Available collectors:\n")
|
|
for _, n := range collectorNames {
|
|
fmt.Printf(" - %s\n", n)
|
|
}
|
|
return
|
|
}
|
|
collectors, err := loadCollectors()
|
|
if err != nil {
|
|
log.Fatalf("Couldn't load collectors: %s", err)
|
|
}
|
|
|
|
log.Infof("Enabled collectors:")
|
|
for n, _ := range collectors {
|
|
log.Infof(" - %s", n)
|
|
}
|
|
|
|
nodeCollector := NodeCollector{collectors: collectors}
|
|
prometheus.MustRegister(nodeCollector)
|
|
|
|
sigUsr1 := make(chan os.Signal)
|
|
signal.Notify(sigUsr1, syscall.SIGUSR1)
|
|
|
|
handler := prometheus.Handler()
|
|
if *authUser != "" || *authPass != "" {
|
|
if *authUser == "" || *authPass == "" {
|
|
log.Fatal("You need to specify -auth.user and -auth.pass to enable basic auth")
|
|
}
|
|
handler = &basicAuthHandler{
|
|
handler: prometheus.Handler().ServeHTTP,
|
|
user: *authUser,
|
|
password: *authPass,
|
|
}
|
|
}
|
|
|
|
http.Handle(*metricsPath, handler)
|
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte(`<html>
|
|
<head><title>Node Exporter</title></head>
|
|
<body>
|
|
<h1>Node Exporter</h1>
|
|
<p><a href="` + *metricsPath + `">Metrics</a></p>
|
|
</body>
|
|
</html>`))
|
|
})
|
|
|
|
log.Infof("Starting node_exporter v%s at %s", Version, *listenAddress)
|
|
err = http.ListenAndServe(*listenAddress, nil)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|