2015-09-26 08:36:40 -07: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 07:40:10 -07:00
package main
import (
2014-06-04 06:09:33 -07:00
"fmt"
2014-02-18 03:35:11 -08:00
"net/http"
2015-03-05 08:02:17 -08:00
_ "net/http/pprof"
2015-05-12 08:04:08 -07:00
"sort"
2014-06-04 04:12:34 -07:00
"strings"
2014-02-18 03:35:11 -08:00
"sync"
"time"
2014-02-07 08:09:39 -08:00
2014-02-18 03:35:11 -08:00
"github.com/prometheus/client_golang/prometheus"
2017-01-05 10:30:48 -08:00
"github.com/prometheus/client_golang/prometheus/promhttp"
2015-10-30 13:20:06 -07:00
"github.com/prometheus/common/log"
2016-04-30 10:58:17 -07:00
"github.com/prometheus/common/version"
2014-02-18 03:35:11 -08:00
"github.com/prometheus/node_exporter/collector"
2017-08-12 06:07:24 -07:00
"gopkg.in/alecthomas/kingpin.v2"
2013-05-07 07:40:10 -07:00
)
2016-02-04 17:24:16 -08:00
const (
2017-07-26 06:20:28 -07: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-04 17:24:16 -08:00
)
2014-06-26 10:20:36 -07:00
2013-05-07 07:40:10 -07:00
var (
2017-03-16 10:21:00 -07: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 10:20:36 -07:00
)
2013-05-07 07:40:10 -07:00
)
2015-10-16 12:17:44 -07:00
// NodeCollector implements the prometheus.Collector interface.
2014-10-29 07:16:43 -07:00
type NodeCollector struct {
collectors map [ string ] collector . Collector
}
2015-10-16 12:17:44 -07:00
// Describe implements the prometheus.Collector interface.
2014-10-29 07:16:43 -07:00
func ( n NodeCollector ) Describe ( ch chan <- * prometheus . Desc ) {
2017-03-16 10:21:00 -07:00
ch <- scrapeDurationDesc
ch <- scrapeSuccessDesc
2014-10-29 07:16:43 -07:00
}
2015-10-16 12:17:44 -07:00
// Collect implements the prometheus.Collector interface.
2014-10-29 07:16:43 -07: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 12:17:44 -07:00
execute ( name , c , ch )
2014-10-29 07:16:43 -07:00
wg . Done ( )
} ( name , c )
}
wg . Wait ( )
}
2015-11-12 23:42:10 -08:00
func filterAvailableCollectors ( collectors string ) string {
2017-02-28 08:44:53 -08:00
var availableCollectors [ ] string
2015-11-12 23:42:10 -08:00
for _ , c := range strings . Split ( collectors , "," ) {
_ , ok := collector . Factories [ c ]
if ok {
availableCollectors = append ( availableCollectors , c )
}
}
return strings . Join ( availableCollectors , "," )
}
2015-10-16 12:17:44 -07:00
func execute ( name string , c collector . Collector , ch chan <- prometheus . Metric ) {
2014-10-29 07:16:43 -07:00
begin := time . Now ( )
err := c . Update ( ch )
duration := time . Since ( begin )
2017-03-16 10:21:00 -07:00
var success float64
2014-10-29 07:16:43 -07:00
if err != nil {
2015-06-22 04:32:08 -07:00
log . Errorf ( "ERROR: %s collector failed after %fs: %s" , name , duration . Seconds ( ) , err )
2017-03-16 10:21:00 -07:00
success = 0
2014-10-29 07:16:43 -07:00
} else {
2015-06-22 04:32:08 -07:00
log . Debugf ( "OK: %s collector succeeded after %fs." , name , duration . Seconds ( ) )
2017-03-16 10:21:00 -07:00
success = 1
2014-10-29 07:16:43 -07:00
}
2017-03-16 10:21:00 -07:00
ch <- prometheus . MustNewConstMetric ( scrapeDurationDesc , prometheus . GaugeValue , duration . Seconds ( ) , name )
ch <- prometheus . MustNewConstMetric ( scrapeSuccessDesc , prometheus . GaugeValue , success , name )
2014-10-29 07:16:43 -07:00
}
2016-02-04 17:24:16 -08:00
func loadCollectors ( list string ) ( map [ string ] collector . Collector , error ) {
2014-10-29 07:16:43 -07:00
collectors := map [ string ] collector . Collector { }
2016-02-04 17:24:16 -08:00
for _ , name := range strings . Split ( list , "," ) {
2014-10-29 07:16:43 -07:00
fn , ok := collector . Factories [ name ]
if ! ok {
2014-11-24 14:15:13 -08:00
return nil , fmt . Errorf ( "collector '%s' not available" , name )
2014-10-29 07:16:43 -07:00
}
2015-05-20 11:04:49 -07:00
c , err := fn ( )
2014-10-29 07:16:43 -07:00
if err != nil {
return nil , err
}
collectors [ name ] = c
}
return collectors , nil
}
2016-04-30 10:58:17 -07:00
func init ( ) {
prometheus . MustRegister ( version . NewCollector ( "node_exporter" ) )
}
2013-05-07 07:40:10 -07:00
func main ( ) {
2016-02-04 17:24:16 -08:00
var (
2017-08-12 06:07:24 -07: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-04 17:24:16 -08:00
)
2015-04-15 20:51:09 -07:00
2017-08-12 06:07:24 -07:00
log . AddFlags ( kingpin . CommandLine )
kingpin . Version ( version . Print ( "node_exporter" ) )
kingpin . HelpFlag . Short ( 'h' )
kingpin . Parse ( )
2016-04-30 10:58:17 -07:00
log . Infoln ( "Starting node_exporter" , version . Info ( ) )
log . Infoln ( "Build context" , version . BuildContext ( ) )
2014-06-04 06:09:33 -07:00
if * printCollectors {
2015-05-12 08:04:08 -07:00
collectorNames := make ( sort . StringSlice , 0 , len ( collector . Factories ) )
2015-10-16 12:17:44 -07:00
for n := range collector . Factories {
2015-05-12 08:04:08 -07:00
collectorNames = append ( collectorNames , n )
}
collectorNames . Sort ( )
fmt . Printf ( "Available collectors:\n" )
for _ , n := range collectorNames {
2014-06-04 06:09:33 -07:00
fmt . Printf ( " - %s\n" , n )
}
return
}
2016-02-04 17:24:16 -08:00
collectors , err := loadCollectors ( * enabledCollectors )
2013-05-07 07:40:10 -07:00
if err != nil {
2015-05-28 12:21:44 -07:00
log . Fatalf ( "Couldn't load collectors: %s" , err )
2013-05-07 07:40:10 -07:00
}
2014-02-18 03:35:11 -08:00
2015-05-28 12:21:44 -07:00
log . Infof ( "Enabled collectors:" )
2015-10-16 12:17:44 -07:00
for n := range collectors {
2015-05-28 12:21:44 -07:00
log . Infof ( " - %s" , n )
2014-02-07 08:09:39 -08:00
}
2014-02-18 03:35:11 -08:00
2017-03-13 19:55:19 -07:00
if err := prometheus . Register ( NodeCollector { collectors : collectors } ) ; err != nil {
log . Fatalf ( "Couldn't register collector: %s" , err )
}
2017-01-05 10:30:48 -08:00
handler := promhttp . HandlerFor ( prometheus . DefaultGatherer ,
2017-03-13 19:55:19 -07:00
promhttp . HandlerOpts {
ErrorLog : log . NewErrorLogger ( ) ,
ErrorHandling : promhttp . ContinueOnError ,
} )
2014-10-29 07:16:43 -07:00
2017-03-13 19:55:19 -07:00
// TODO(ts): Remove deprecated and problematic InstrumentHandler usage.
2017-01-05 10:30:48 -08:00
http . Handle ( * metricsPath , prometheus . InstrumentHandler ( "prometheus" , handler ) )
2015-03-05 08:02:17 -08: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-15 20:51:09 -07:00
2016-04-30 10:58:17 -07:00
log . Infoln ( "Listening on" , * listenAddress )
2015-03-05 08:02:17 -08:00
err = http . ListenAndServe ( * listenAddress , nil )
if err != nil {
2015-05-28 12:21:44 -07:00
log . Fatal ( err )
2015-03-05 08:02:17 -08:00
}
2014-02-18 03:35:11 -08:00
}