2015-09-26 15:36:40 +00:00
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2013-05-07 14:40:10 +00:00
package main
import (
2014-06-04 13:09:33 +00:00
"fmt"
2014-02-18 11:35:11 +00:00
"net/http"
2015-03-05 16:02:17 +00:00
_ "net/http/pprof"
2015-05-12 15:04:08 +00:00
"sort"
2014-06-04 11:12:34 +00:00
"strings"
2014-02-18 11:35:11 +00:00
"sync"
"time"
2014-02-07 16:09:39 +00:00
2014-02-18 11:35:11 +00:00
"github.com/prometheus/client_golang/prometheus"
2017-01-05 18:30:48 +00:00
"github.com/prometheus/client_golang/prometheus/promhttp"
2015-10-30 20:20:06 +00:00
"github.com/prometheus/common/log"
2016-04-30 17:58:17 +00:00
"github.com/prometheus/common/version"
2014-02-18 11:35:11 +00:00
"github.com/prometheus/node_exporter/collector"
2017-08-12 13:07:24 +00:00
"gopkg.in/alecthomas/kingpin.v2"
2013-05-07 14:40:10 +00:00
)
2016-02-05 01:24:16 +00:00
const (
2017-07-26 13:20:28 +00:00
defaultCollectors = "arp,bcache,conntrack,cpu,diskstats,entropy,edac,exec,filefd,filesystem,hwmon,infiniband,ipvs,loadavg,mdadm,meminfo,netdev,netstat,sockstat,stat,textfile,time,uname,vmstat,wifi,xfs,zfs"
2016-02-05 01:24:16 +00:00
)
2014-06-26 17:20:36 +00:00
2013-05-07 14:40:10 +00:00
var (
2017-03-16 17:21:00 +00:00
scrapeDurationDesc = prometheus . NewDesc (
prometheus . BuildFQName ( collector . Namespace , "scrape" , "collector_duration_seconds" ) ,
"node_exporter: Duration of a collector scrape." ,
[ ] string { "collector" } ,
nil ,
)
scrapeSuccessDesc = prometheus . NewDesc (
prometheus . BuildFQName ( collector . Namespace , "scrape" , "collector_success" ) ,
"node_exporter: Whether a collector succeeded." ,
[ ] string { "collector" } ,
nil ,
2014-06-26 17:20:36 +00:00
)
2013-05-07 14:40:10 +00:00
)
2015-10-16 19:17:44 +00:00
// NodeCollector implements the prometheus.Collector interface.
2014-10-29 14:16:43 +00:00
type NodeCollector struct {
collectors map [ string ] collector . Collector
}
2015-10-16 19:17:44 +00:00
// Describe implements the prometheus.Collector interface.
2014-10-29 14:16:43 +00:00
func ( n NodeCollector ) Describe ( ch chan <- * prometheus . Desc ) {
2017-03-16 17:21:00 +00:00
ch <- scrapeDurationDesc
ch <- scrapeSuccessDesc
2014-10-29 14:16:43 +00:00
}
2015-10-16 19:17:44 +00:00
// Collect implements the prometheus.Collector interface.
2014-10-29 14:16:43 +00:00
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 ) {
2015-10-16 19:17:44 +00:00
execute ( name , c , ch )
2014-10-29 14:16:43 +00:00
wg . Done ( )
} ( name , c )
}
wg . Wait ( )
}
2015-11-13 07:42:10 +00:00
func filterAvailableCollectors ( collectors string ) string {
2017-02-28 16:44:53 +00:00
var availableCollectors [ ] string
2015-11-13 07:42:10 +00:00
for _ , c := range strings . Split ( collectors , "," ) {
_ , ok := collector . Factories [ c ]
if ok {
availableCollectors = append ( availableCollectors , c )
}
}
return strings . Join ( availableCollectors , "," )
}
2015-10-16 19:17:44 +00:00
func execute ( name string , c collector . Collector , ch chan <- prometheus . Metric ) {
2014-10-29 14:16:43 +00:00
begin := time . Now ( )
err := c . Update ( ch )
duration := time . Since ( begin )
2017-03-16 17:21:00 +00:00
var success float64
2014-10-29 14:16:43 +00:00
if err != nil {
2015-06-22 11:32:08 +00:00
log . Errorf ( "ERROR: %s collector failed after %fs: %s" , name , duration . Seconds ( ) , err )
2017-03-16 17:21:00 +00:00
success = 0
2014-10-29 14:16:43 +00:00
} else {
2015-06-22 11:32:08 +00:00
log . Debugf ( "OK: %s collector succeeded after %fs." , name , duration . Seconds ( ) )
2017-03-16 17:21:00 +00:00
success = 1
2014-10-29 14:16:43 +00:00
}
2017-03-16 17:21:00 +00:00
ch <- prometheus . MustNewConstMetric ( scrapeDurationDesc , prometheus . GaugeValue , duration . Seconds ( ) , name )
ch <- prometheus . MustNewConstMetric ( scrapeSuccessDesc , prometheus . GaugeValue , success , name )
2014-10-29 14:16:43 +00:00
}
2016-02-05 01:24:16 +00:00
func loadCollectors ( list string ) ( map [ string ] collector . Collector , error ) {
2014-10-29 14:16:43 +00:00
collectors := map [ string ] collector . Collector { }
2016-02-05 01:24:16 +00:00
for _ , name := range strings . Split ( list , "," ) {
2014-10-29 14:16:43 +00:00
fn , ok := collector . Factories [ name ]
if ! ok {
2014-11-24 22:15:13 +00:00
return nil , fmt . Errorf ( "collector '%s' not available" , name )
2014-10-29 14:16:43 +00:00
}
2015-05-20 18:04:49 +00:00
c , err := fn ( )
2014-10-29 14:16:43 +00:00
if err != nil {
return nil , err
}
collectors [ name ] = c
}
return collectors , nil
}
2016-04-30 17:58:17 +00:00
func init ( ) {
prometheus . MustRegister ( version . NewCollector ( "node_exporter" ) )
}
2013-05-07 14:40:10 +00:00
func main ( ) {
2016-02-05 01:24:16 +00:00
var (
2017-08-12 13:07:24 +00:00
listenAddress = kingpin . Flag ( "web.listen-address" , "Address on which to expose metrics and web interface." ) . Default ( ":9100" ) . String ( )
metricsPath = kingpin . Flag ( "web.telemetry-path" , "Path under which to expose metrics." ) . Default ( "/metrics" ) . String ( )
enabledCollectors = kingpin . Flag ( "collectors.enabled" , "Comma-separated list of collectors to use." ) . Default ( filterAvailableCollectors ( defaultCollectors ) ) . String ( )
printCollectors = kingpin . Flag ( "collectors.print" , "If true, print available collectors and exit." ) . Bool ( )
2016-02-05 01:24:16 +00:00
)
2015-04-16 03:51:09 +00:00
2017-08-12 13:07:24 +00:00
log . AddFlags ( kingpin . CommandLine )
kingpin . Version ( version . Print ( "node_exporter" ) )
kingpin . HelpFlag . Short ( 'h' )
kingpin . Parse ( )
2016-04-30 17:58:17 +00:00
log . Infoln ( "Starting node_exporter" , version . Info ( ) )
log . Infoln ( "Build context" , version . BuildContext ( ) )
2014-06-04 13:09:33 +00:00
if * printCollectors {
2015-05-12 15:04:08 +00:00
collectorNames := make ( sort . StringSlice , 0 , len ( collector . Factories ) )
2015-10-16 19:17:44 +00:00
for n := range collector . Factories {
2015-05-12 15:04:08 +00:00
collectorNames = append ( collectorNames , n )
}
collectorNames . Sort ( )
fmt . Printf ( "Available collectors:\n" )
for _ , n := range collectorNames {
2014-06-04 13:09:33 +00:00
fmt . Printf ( " - %s\n" , n )
}
return
}
2016-02-05 01:24:16 +00:00
collectors , err := loadCollectors ( * enabledCollectors )
2013-05-07 14:40:10 +00:00
if err != nil {
2015-05-28 19:21:44 +00:00
log . Fatalf ( "Couldn't load collectors: %s" , err )
2013-05-07 14:40:10 +00:00
}
2014-02-18 11:35:11 +00:00
2015-05-28 19:21:44 +00:00
log . Infof ( "Enabled collectors:" )
2015-10-16 19:17:44 +00:00
for n := range collectors {
2015-05-28 19:21:44 +00:00
log . Infof ( " - %s" , n )
2014-02-07 16:09:39 +00:00
}
2014-02-18 11:35:11 +00:00
2017-03-14 02:55:19 +00:00
if err := prometheus . Register ( NodeCollector { collectors : collectors } ) ; err != nil {
log . Fatalf ( "Couldn't register collector: %s" , err )
}
2017-01-05 18:30:48 +00:00
handler := promhttp . HandlerFor ( prometheus . DefaultGatherer ,
2017-03-14 02:55:19 +00:00
promhttp . HandlerOpts {
ErrorLog : log . NewErrorLogger ( ) ,
ErrorHandling : promhttp . ContinueOnError ,
} )
2014-10-29 14:16:43 +00:00
2017-03-14 02:55:19 +00:00
// TODO(ts): Remove deprecated and problematic InstrumentHandler usage.
2017-01-05 18:30:48 +00:00
http . Handle ( * metricsPath , prometheus . InstrumentHandler ( "prometheus" , handler ) )
2015-03-05 16:02:17 +00:00
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 > ` ) )
} )
2015-04-16 03:51:09 +00:00
2016-04-30 17:58:17 +00:00
log . Infoln ( "Listening on" , * listenAddress )
2015-03-05 16:02:17 +00:00
err = http . ListenAndServe ( * listenAddress , nil )
if err != nil {
2015-05-28 19:21:44 +00:00
log . Fatal ( err )
2015-03-05 16:02:17 +00:00
}
2014-02-18 11:35:11 +00:00
}